@@ -336,6 +336,25 @@ class _AnnotationMixin {
336336 return svg ;
337337 }
338338
339+ /** The "+" glyph from Zotero's chrome://zotero/skin/16/universal/plus.svg,
340+ * rebuilt inline with `fill="currentColor"` so it inherits the
341+ * surrounding CSS `color` — no chrome:// URL and no `context-fill`
342+ * keyword (that combination drew an invisible box in the reader-window
343+ * relations popup). Same path data as the icon Zotero shows on the
344+ * item pane's "Related" section add button, so the two match exactly. */
345+ _makePlusSvg ( doc ) {
346+ const NS = "http://www.w3.org/2000/svg" ;
347+ const svg = doc . createElementNS ( NS , "svg" ) ;
348+ svg . setAttribute ( "class" , "wv-plus-svg" ) ;
349+ svg . setAttribute ( "viewBox" , "0 0 16 16" ) ;
350+ svg . setAttribute ( "aria-hidden" , "true" ) ;
351+ const p = doc . createElementNS ( NS , "path" ) ;
352+ p . setAttribute ( "fill" , "currentColor" ) ;
353+ p . setAttribute ( "d" , "M14 8H9V3H8V8H3V9H8V14H9V9H14V8Z" ) ;
354+ svg . appendChild ( p ) ;
355+ return svg ;
356+ }
357+
339358 /** Stamp data-has-url on an icon element and (re)populate it with
340359 * the chain SVG when the comment has a URL. Markdown-only comments
341360 * no longer get a dedicated icon — markdown formatting is still
@@ -543,13 +562,13 @@ class _AnnotationMixin {
543562 * removes itself on `popuphidden`.
544563 *
545564 * Options listed (filtered by type at build time):
546- * Annotation Open in Reader
547- * Attachment Open in Reader / Open in New Window / Show File
548- * Note Open Note
549- * Regular Item Open Primary Attachment
565+ * Annotation Open in <PDF/EPUB/Snapshot> in New Tab / New Window
566+ * Attachment Open <Type> in New Tab / New Window / Show File
567+ * Note Open Note in New Tab / New Window
568+ * Regular Item Open <best attachment type> in New Tab / New Window / View Online
550569 * All Show in Library (unless opts.skipShowInLibrary),
551- * Show Parent in Library (if has parent),
552- * Copy Item Link
570+ * Copy Select Link, Copy Open Link (when one
571+ * applies for this item type), Add Related…
553572 *
554573 * `opts.skipShowInLibrary`: omit the "Show in Library" entry —
555574 * used by the right-pane annotation-row wiring where the user
@@ -589,8 +608,14 @@ class _AnnotationMixin {
589608 } ) ;
590609 popup . appendChild ( mi ) ;
591610 } ;
611+ // Add a separator — but never two in a row and never as the
612+ // first element (so groups that turn out empty don't leave a
613+ // dangling rule).
592614 const addSep = ( ) => {
593- popup . appendChild ( doc . createXULElement ( "menuseparator" ) ) ;
615+ const last = popup . lastElementChild as any ;
616+ if ( last && last . localName !== "menuseparator" ) {
617+ popup . appendChild ( doc . createXULElement ( "menuseparator" ) ) ;
618+ }
594619 } ;
595620
596621 const isAnnotation = ! ! ( item . isAnnotation && item . isAnnotation ( ) ) ;
@@ -742,8 +767,15 @@ class _AnnotationMixin {
742767 }
743768 } catch ( e ) { }
744769 if ( parentID ) {
745- appendOpenPair ( parentReaderType ,
746- readerTypeLabel ( parentReaderType ) ,
770+ // Phrase it as "Open in PDF in New Tab" — opening an
771+ // annotation means jumping to it *inside* its document,
772+ // not opening the doc as an object. (Unknown parent
773+ // type → "Open in Reader in New Tab".) The icon still
774+ // uses the parent's type so it reads as a PDF / EPUB /
775+ // snapshot.
776+ const tLabel = readerTypeLabel ( parentReaderType ) ;
777+ const openInLabel = "in " + ( tLabel === "Attachment" ? "Reader" : tLabel ) ;
778+ appendOpenPair ( parentReaderType , openInLabel ,
747779 ( inWindow ) => async ( ) => {
748780 try {
749781 await Zotero . Reader . open ( parentID ,
@@ -845,61 +877,35 @@ class _AnnotationMixin {
845877
846878 addSep ( ) ;
847879
848- // ---- Universal options -- --------------------------------------------
880+ // ---- Library navigation --------------------------------------------
849881 if ( ! opts . skipShowInLibrary ) {
850882 append ( "Show in Library" , ( ) => this . _navigateToItem ( item ) ,
851883 { iconURL : ICON_LIBRARY } ) ;
852884 }
853- // "Show Parent in Library" is meaningful only when the
854- // parent is distinct from where "Show in Library" lands.
855- // For annotations, `selectItem` already routes to the
856- // parent attachment (annotations have no direct row in
857- // the items tree), so this row would duplicate the one
858- // above. Skip it for annotations.
859- if ( item . parentItemID && ! isAnnotation ) {
860- append ( "Show Parent in Library" , ( ) => {
861- try {
862- const zp = win . ZoteroPane ;
863- if ( zp && typeof zp . selectItem === "function" ) {
864- zp . selectItem ( item . parentItemID ) ;
865- }
866- if ( win . Zotero_Tabs && typeof win . Zotero_Tabs . select === "function" ) {
867- win . Zotero_Tabs . select ( "zotero-pane" ) ;
868- }
869- win . focus ( ) ;
870- } catch ( e ) {
871- Zotero . debug ( "[Weavero] show-parent err: " + e ) ;
872- }
873- } , { iconURL : ICON_LIBRARY } ) ;
874- }
875- append ( "Copy Item Link" , ( ) => {
876- try {
877- const lib = item . libraryID ;
878- let prefix = "library" ;
879- try {
880- if ( lib !== Zotero . Libraries . userLibraryID ) {
881- const gid = Zotero . Groups . getGroupIDFromLibraryID ( lib ) ;
882- if ( gid ) prefix = "groups/" + gid ;
883- }
884- } catch ( e ) { }
885- const url = "zotero://select/" + prefix + "/items/" + item . key ;
886- Zotero . Utilities . Internal . copyTextToClipboard ( url ) ;
887- } catch ( e ) {
888- Zotero . debug ( "[Weavero] copy-link err: " + e ) ;
889- }
890- // Plugin's needle icon — distinguishes a Weavero-provided
891- // affordance ("copy a zotero:// URI for this item") from
892- // the chain icons that mean "related items".
893- } , { iconURL : this . _menuItemIconURL } ) ;
894885
895886 addSep ( ) ;
896887
888+ // ---- Copy links + Add Related (one group, separator above) ---------
889+ // The needle icon distinguishes the Weavero copy-link affordances
890+ // ("copy a zotero:// URI for this item") from the chain icon that
891+ // means "related items". "Copy Open Link" is only added when an
892+ // open link applies (this item is a file attachment, has a best
893+ // attachment, or — for an annotation — its parent attachment is
894+ // openable).
895+ append ( "Copy Select Link" ,
896+ ( ) => this . _copyItemLinks ( [ item ] , "select" ) ,
897+ { iconURL : this . _menuItemIconURL } ) ;
898+ if ( this . _buildOpenLink ( item ) ) {
899+ append ( "Copy Open Link"
900+ + ( this . _isExternalOpenTarget ( item ) ? " (external app)" : "" ) ,
901+ ( ) => this . _copyItemLinks ( [ item ] , "open" ) ,
902+ { iconURL : this . _menuItemIconURL } ) ;
903+ }
897904 // "Add Related…" — opens Zotero's select-items dialog and adds
898- // the chosen items as `dc:relation` peers of this one. Uses the
899- // chain icon for visual consistency with the rest of the
900- // related-item affordances (items-list `.wv-tree-rel-icon`,
901- // sidebar `.wv-btn-relations`, PDF reader marker badge, the
902- // "Add related item…" entry on the annotation context menu).
905+ // the chosen items as `dc:relation` peers of this one. Chain icon
906+ // for visual consistency with the rest of the related-item
907+ // affordances (items-list `.wv-tree-rel-icon`, sidebar
908+ // `.wv-btn-relations`, PDF reader marker badge).
903909 append ( "Add Related…" , ( ) => {
904910 try { this . _addRelatedItemDialog ( [ item ] ) ; }
905911 catch ( e ) {
0 commit comments