From 0f8b556ac88632d31db4218bcea2e7a559deb6e4 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 11 Apr 2022 20:11:42 -0400
Subject: fixed sendtoback menu and functionality.  fixed mixedblendmode for
 groups.  fixed orange highlighting when docs are toggled hidden.   fixed
 placement of linking button.

---
 src/client/views/nodes/DocumentLinksButton.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/views/nodes/DocumentLinksButton.tsx')

diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 6d96a9ab6..46537df7e 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -278,7 +278,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
 
         //render circular tooltip if it isn't set to invisible and show the number of doc links the node has, and render inner-menu link button for starting/stopping links if currently in menu
         return (!Array.from(this.filteredLinks).length && !this.props.AlwaysOn) ? (null) :
-            <div className="documentLinksButton-wrapper" >
+            <div className="documentLinksButton-wrapper" style={{ transform: this.props.InMenu ? undefined : `scale(${(this.props.ContentScaling?.() || 1) * this.props.View.screenToLocalTransform().Scale})` }} >
                 {
                     (this.props.InMenu && (DocumentLinksButton.StartLink || this.props.StartLink)) ||
                         (!DocumentLinksButton.LinkEditorDocView && !this.props.InMenu) ?
-- 
cgit v1.2.3-70-g09d2


From 36261eac67ae6f872c9be2c9766d21ac24698f8e Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 28 Apr 2022 01:37:27 -0400
Subject: fixed linkEditor to work when invoked from documentButtonsBar and
 properties sidebar is up.

---
 src/client/views/MainView.tsx                       |  2 +-
 src/client/views/PropertiesDocBacklinksSelector.tsx |  3 ++-
 src/client/views/linking/LinkMenu.tsx               | 20 ++++++++++++++------
 src/client/views/linking/LinkMenuGroup.tsx          |  2 ++
 src/client/views/linking/LinkMenuItem.tsx           |  6 +++---
 src/client/views/nodes/DocumentLinksButton.tsx      | 10 ++--------
 6 files changed, 24 insertions(+), 19 deletions(-)

(limited to 'src/client/views/nodes/DocumentLinksButton.tsx')

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index b73074899..c794c73db 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -632,7 +632,7 @@ export class MainView extends React.Component {
             <ComponentDecorations boundsLeft={this.leftScreenOffsetOfMainDocView} boundsTop={this.topOfMainDocContent} />
             {this.topbar}
             {LinkDescriptionPopup.descriptionPopup ? <LinkDescriptionPopup /> : null}
-            {DocumentLinksButton.LinkEditorDocView ? <LinkMenu docView={DocumentLinksButton.LinkEditorDocView} /> : (null)}
+            {DocumentLinksButton.LinkEditorDocView ? <LinkMenu clearLinkEditor={action(() => DocumentLinksButton.LinkEditorDocView = undefined)} docView={DocumentLinksButton.LinkEditorDocView} /> : (null)}
             {LinkDocPreview.LinkInfo ? <LinkDocPreview {...LinkDocPreview.LinkInfo} /> : (null)}
             <div style={{ position: "relative", display: LightboxView.LightboxDoc ? "none" : undefined, zIndex: 2001 }} >
                 <CollectionMenu panelWidth={this.topMenuWidth} panelHeight={this.topMenuHeight} />
diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx
index dce3e35e8..4ead8eaf0 100644
--- a/src/client/views/PropertiesDocBacklinksSelector.tsx
+++ b/src/client/views/PropertiesDocBacklinksSelector.tsx
@@ -3,6 +3,7 @@ import { observer } from "mobx-react";
 import * as React from "react";
 import { Doc, DocListCast } from "../../fields/Doc";
 import { Cast } from "../../fields/Types";
+import { emptyFunction } from "../../Utils";
 import { DocumentType } from "../documents/DocumentTypes";
 import { LinkManager } from "../util/LinkManager";
 import { SelectionManager } from "../util/SelectionManager";
@@ -46,7 +47,7 @@ export class PropertiesDocBacklinksSelector extends React.Component<PropertiesDo
     render() {
         return !SelectionManager.Views().length ? (null) : <div>
             {this.props.hideTitle ? (null) : <p key="contexts">Contexts:</p>}
-            <LinkMenu docView={SelectionManager.Views().lastElement()} itemHandler={this.getOnClick} position={{ x: 0 }} />
+            <LinkMenu docView={SelectionManager.Views().lastElement()} clearLinkEditor={emptyFunction} itemHandler={this.getOnClick} position={{ x: 0 }} />
         </div>;
     }
 }
\ No newline at end of file
diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx
index bc922be36..a564c59d3 100644
--- a/src/client/views/linking/LinkMenu.tsx
+++ b/src/client/views/linking/LinkMenu.tsx
@@ -1,9 +1,10 @@
-import { action, computed, observable } from "mobx";
+import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
 import { observer } from "mobx-react";
 import { Doc } from "../../../fields/Doc";
 import { LinkManager } from "../../util/LinkManager";
+import { SelectionManager } from "../../util/SelectionManager";
 import { DocumentLinksButton } from "../nodes/DocumentLinksButton";
-import { DocumentView, DocumentViewSharedProps } from "../nodes/DocumentView";
+import { DocumentView } from "../nodes/DocumentView";
 import { LinkDocPreview } from "../nodes/LinkDocPreview";
 import { LinkEditor } from "./LinkEditor";
 import './LinkMenu.scss';
@@ -14,6 +15,7 @@ interface Props {
     docView: DocumentView;
     position?: { x?: number, y?: number };
     itemHandler?: (doc: Doc) => void;
+    clearLinkEditor: () => void;
 }
 
 /**
@@ -21,7 +23,7 @@ interface Props {
  */
 @observer
 export class LinkMenu extends React.Component<Props> {
-    private _editorRef = React.createRef<HTMLDivElement>();
+    _editorRef = React.createRef<HTMLDivElement>();
     @observable _editingLink?: Doc;
     @observable _linkMenuRef = React.createRef<HTMLDivElement>();
 
@@ -29,16 +31,21 @@ export class LinkMenu extends React.Component<Props> {
         return this.props.position ?? (dv => ({ x: dv?.left || 0, y: (dv?.bottom || 0) + 15 }))(this.props.docView.getBounds());
     }
 
+    clear = action(() => {
+        this.props.clearLinkEditor();
+        this._editingLink = undefined;
+    });
+
     componentDidMount() { document.addEventListener("pointerdown", this.onPointerDown); }
     componentWillUnmount() { document.removeEventListener("pointerdown", this.onPointerDown); }
 
-    onPointerDown = (e: PointerEvent) => {
+    onPointerDown = action((e: PointerEvent) => {
         LinkDocPreview.Clear();
         if (!this._linkMenuRef.current?.contains(e.target as any) &&
             !this._editorRef.current?.contains(e.target as any)) {
-            DocumentLinksButton.ClearLinkEditor();
+            this.clear();
         }
-    }
+    });
 
     /**
      * maps each link to a JSX element to be rendered
@@ -54,6 +61,7 @@ export class LinkMenu extends React.Component<Props> {
                 sourceDoc={this.props.docView.props.Document}
                 group={group[1]}
                 groupType={group[0]}
+                clearLinkEditor={this.clear}
                 showEditor={action(linkDoc => this._editingLink = linkDoc)} />);
 
         return linkItems.length ? linkItems : this.props.position ? [<></>] : [<p key="">No links have been created yet. Drag the linking button onto another document to create a link.</p>];
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx
index 5b1e29e67..fa6a2f506 100644
--- a/src/client/views/linking/LinkMenuGroup.tsx
+++ b/src/client/views/linking/LinkMenuGroup.tsx
@@ -13,6 +13,7 @@ interface LinkMenuGroupProps {
     sourceDoc: Doc;
     group: Doc[];
     groupType: string;
+    clearLinkEditor: () => void;
     showEditor: (linkDoc: Doc) => void;
     docView: DocumentView;
     itemHandler?: (doc: Doc) => void;
@@ -53,6 +54,7 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
                     linkDoc={linkDoc}
                     sourceDoc={this.props.sourceDoc}
                     destinationDoc={destination}
+                    clearLinkEditor={this.props.clearLinkEditor}
                     showEditor={this.props.showEditor}
                     menuRef={this._menuRef} />;
             }
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index d6400a6b3..3ddcf803d 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -13,7 +13,6 @@ import { DragManager } from '../../util/DragManager';
 import { Hypothesis } from '../../util/HypothesisUtils';
 import { LinkManager } from '../../util/LinkManager';
 import { undoBatch } from '../../util/UndoManager';
-import { DocumentLinksButton } from '../nodes/DocumentLinksButton';
 import { DocumentView } from '../nodes/DocumentView';
 import { LinkDocPreview } from '../nodes/LinkDocPreview';
 import './LinkMenuItem.scss';
@@ -26,6 +25,7 @@ interface LinkMenuItemProps {
     docView: DocumentView;
     sourceDoc: Doc;
     destinationDoc: Doc;
+    clearLinkEditor: () => void;
     showEditor: (linkDoc: Doc) => void;
     menuRef: React.Ref<HTMLDivElement>;
     itemHandler?: (doc: Doc) => void;
@@ -92,12 +92,12 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
                 const eleClone: any = this._drag.current!.cloneNode(true);
                 eleClone.style.transform = `translate(${e.x}px, ${e.y}px)`;
                 StartLinkTargetsDrag(eleClone, this.props.docView, e.x, e.y, this.props.sourceDoc, [this.props.linkDoc]);
-                DocumentLinksButton.ClearLinkEditor();
+                this.props.clearLinkEditor();
                 return true;
             },
             emptyFunction,
             () => {
-                DocumentLinksButton.ClearLinkEditor();
+                this.props.clearLinkEditor();
                 if (this.props.itemHandler) {
 
                     this.props.itemHandler?.(this.props.linkDoc);
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 46537df7e..9b79db319 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -1,21 +1,17 @@
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { Tooltip } from "@material-ui/core";
-import { action, computed, observable, runInAction, trace } from "mobx";
+import { action, computed, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { Doc, Opt } from "../../../fields/Doc";
-import { Id } from "../../../fields/FieldSymbols";
-import { ScriptField } from "../../../fields/ScriptField";
 import { StrCast } from "../../../fields/Types";
 import { TraceMobx } from "../../../fields/util";
 import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../../Utils";
-import { DocServer } from "../../DocServer";
-import { Docs, DocUtils } from "../../documents/Documents";
+import { DocUtils } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
 import { Hypothesis } from "../../util/HypothesisUtils";
 import { LinkManager } from "../../util/LinkManager";
 import { undoBatch, UndoManager } from "../../util/UndoManager";
 import { Colors } from "../global/globalEnums";
-import { LightboxView } from "../LightboxView";
 import './DocumentLinksButton.scss';
 import { DocumentView } from "./DocumentView";
 import { LinkDescriptionPopup } from "./LinkDescriptionPopup";
@@ -46,8 +42,6 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
     @observable public static invisibleWebDoc: Opt<Doc>;
     public static invisibleWebRef = React.createRef<HTMLDivElement>();
 
-    @action public static ClearLinkEditor() { DocumentLinksButton.LinkEditorDocView = undefined; }
-
     @action @undoBatch
     onLinkButtonMoved = (e: PointerEvent) => {
         if (this.props.InMenu && this.props.StartLink) {
-- 
cgit v1.2.3-70-g09d2


From 778432158e5f0bcdcb2e68ff6872a5c9335ef3af Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 28 Apr 2022 10:49:32 -0400
Subject: made sharing menu a developer feature.  made link relationships
 support non-symmetry

---
 src/client/util/LinkManager.ts                            |  9 ++++++---
 src/client/views/PropertiesView.tsx                       |  2 +-
 src/client/views/nodes/DocumentLinksButton.tsx            | 11 +++++++++--
 src/client/views/nodes/LinkDocPreview.tsx                 |  2 +-
 src/client/views/nodes/formattedText/FormattedTextBox.tsx | 10 ++++++----
 5 files changed, 23 insertions(+), 11 deletions(-)

(limited to 'src/client/views/nodes/DocumentLinksButton.tsx')

diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 0f3da0548..7ba7a1d4c 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -29,6 +29,7 @@ export class LinkManager {
     public static currentLink: Opt<Doc>;
     public static get Instance() { return LinkManager._instance; }
     public static addLinkDB = (linkDb: any) => LinkManager.userLinkDBs.push(linkDb);
+    public static AutoKeywords = "keywords:Usages";
     static links: Doc[] = [];
     constructor() {
         LinkManager._instance = this;
@@ -149,9 +150,11 @@ export class LinkManager {
     public getRelatedGroupedLinks(anchor: Doc): Map<string, Array<Doc>> {
         const anchorGroups = new Map<string, Array<Doc>>();
         this.relatedLinker(anchor).forEach(link => {
-            if (!link.linkRelationship || link?.linkRelationship !== "-ungrouped-") {
-                const group = anchorGroups.get(StrCast(link.linkRelationship));
-                anchorGroups.set(StrCast(link.linkRelationship), group ? [...group, link] : [link]);
+            if (link.linkRelationship && link.linkRelationship !== "-ungrouped-") {
+                const relation = StrCast(link.linkRelationship);
+                const anchorRelation = relation.indexOf(":") ? relation.split(":")[Doc.AreProtosEqual(Cast(link.anchor1, Doc, null), anchor) ? 0 : 1] : relation;
+                const group = anchorGroups.get(anchorRelation);
+                anchorGroups.set(anchorRelation, group ? [...group, link] : [link]);
             } else {
                 // if link is in no groups then put it in default group
                 const group = anchorGroups.get("*");
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index b63395c76..21c688421 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1362,7 +1362,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
                     {this.fieldsSubMenu}
 
-                    {this.sharingSubMenu}
+                    {isNovice ? null : this.sharingSubMenu}
 
                     {isNovice ? null : this.filtersSubMenu}
 
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 9b79db319..d2e6e8579 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -17,6 +17,7 @@ import { DocumentView } from "./DocumentView";
 import { LinkDescriptionPopup } from "./LinkDescriptionPopup";
 import { TaskCompletionBox } from "./TaskCompletedBox";
 import React = require("react");
+import { DocumentType } from "../../documents/DocumentTypes";
 
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
@@ -158,7 +159,9 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
         } else if (startLink !== endLink) {
             endLink = endLinkView?.docView?._componentView?.getAnchor?.() || endLink;
             startLink = DocumentLinksButton.StartLinkView?.docView?._componentView?.getAnchor?.() || startLink;
-            const linkDoc = DocUtils.MakeLink({ doc: startLink }, { doc: endLink }, DocumentLinksButton.AnnotationId ? "hypothes.is annotation" : "link", undefined, undefined, true);
+            const linkDoc = DocUtils.MakeLink({ doc: startLink }, { doc: endLink },
+                DocumentLinksButton.AnnotationId ? "hypothes.is annotation" :
+                    endLink.type === DocumentType.RTF ? "Commentary:Comments On" : "link", undefined, undefined, true);
 
             LinkManager.currentLink = linkDoc;
 
@@ -272,7 +275,11 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
 
         //render circular tooltip if it isn't set to invisible and show the number of doc links the node has, and render inner-menu link button for starting/stopping links if currently in menu
         return (!Array.from(this.filteredLinks).length && !this.props.AlwaysOn) ? (null) :
-            <div className="documentLinksButton-wrapper" style={{ transform: this.props.InMenu ? undefined : `scale(${(this.props.ContentScaling?.() || 1) * this.props.View.screenToLocalTransform().Scale})` }} >
+            <div className="documentLinksButton-wrapper"
+                style={{
+                    transform: this.props.InMenu ? undefined :
+                        `scale(${(this.props.ContentScaling?.() || 1) * this.props.View.screenToLocalTransform().Scale})`
+                }} >
                 {
                     (this.props.InMenu && (DocumentLinksButton.StartLink || this.props.StartLink)) ||
                         (!DocumentLinksButton.LinkEditorDocView && !this.props.InMenu) ?
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 28915674d..375434933 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -85,7 +85,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                 anchorDoc && DocServer.GetRefField(anchorDoc).then(action(anchor => {
                     if (anchor instanceof Doc && DocListCast(anchor.links).length) {
                         this._linkDoc = this._linkDoc ?? DocListCast(anchor.links)[0];
-                        const automaticLink = this._linkDoc.linkRelationship === "automatic";
+                        const automaticLink = this._linkDoc.linkRelationship === LinkManager.AutoKeywords;
                         if (automaticLink) { // automatic links specify the target in the link info, not the source
                             const linkTarget = anchor;
                             this._linkSrc = LinkManager.getOppositeAnchor(this._linkDoc, linkTarget);
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 756d6c2d6..29117794e 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -349,7 +349,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     autoLink = () => {
         if (this._editorView) {
             const newAutoLinks = new Set<Doc>();
-            const oldAutoLinks = DocListCast(this.props.Document.links).filter(link => link.linkRelationship === "automatic");
+            const oldAutoLinks = DocListCast(this.props.Document.links).filter(link => link.linkRelationship === LinkManager.AutoKeywords);
             const f = this._editorView.state.selection.from;
             const t = this._editorView.state.selection.to;
             var tr = this._editorView.state.tr as any;
@@ -382,14 +382,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     hyperlinkTerm = (tr: any, target: Doc, newAutoLinks: Set<Doc>) => {
         const editorView = this._editorView;
         if (editorView && (editorView as any).docView && !Doc.AreProtosEqual(target, this.rootDoc)) {
-            const flattened1 = this.findInNode(editorView, editorView.state.doc, StrCast(target.title).replace(/^@/, ""));
+            const autoLinkTerm = StrCast(target.title).replace(/^@/, "");
+            const flattened1 = this.findInNode(editorView, editorView.state.doc, autoLinkTerm);
             var alink: Doc | undefined;
             flattened1.forEach((flat, i) => {
-                const flattened = this.findInNode(this._editorView!, this._editorView!.state.doc, StrCast(target.title).replace(/^@/, ""));
+                const flattened = this.findInNode(this._editorView!, this._editorView!.state.doc, autoLinkTerm);
                 this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
                 alink = alink ?? (DocListCast(this.Document.links).find(link =>
                     Doc.AreProtosEqual(Cast(link.anchor1, Doc, null), this.rootDoc) &&
-                    Doc.AreProtosEqual(Cast(link.anchor2, Doc, null), target)) || DocUtils.MakeLink({ doc: this.props.Document }, { doc: target }, "automatic")!);
+                    Doc.AreProtosEqual(Cast(link.anchor2, Doc, null), target)) || DocUtils.MakeLink({ doc: this.props.Document }, { doc: target },
+                        LinkManager.AutoKeywords)!);
                 newAutoLinks.add(alink);
                 const splitter = editorView.state.schema.marks.splitter.create({ id: Utils.GenerateGuid() });
                 const sel = flattened[i];
-- 
cgit v1.2.3-70-g09d2


From 59a22f3a007b201e68ac2f3e1d62e0ca5e66488a Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 28 Apr 2022 12:13:44 -0400
Subject: fixed feedback dragging link button. fixed warnings.  added some
 assymetric linkRelationships.

---
 src/client/documents/Documents.ts                              |  3 ++-
 src/client/util/DocumentManager.ts                             |  2 +-
 src/client/util/LinkManager.ts                                 |  2 +-
 src/client/views/SidebarAnnos.tsx                              |  2 +-
 .../collections/collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 .../views/collections/collectionFreeForm/MarqueeView.tsx       |  2 +-
 src/client/views/linking/LinkMenu.tsx                          |  4 +---
 src/client/views/nodes/DocumentLinksButton.scss                |  2 ++
 src/client/views/nodes/DocumentLinksButton.tsx                 | 10 +++++-----
 src/client/views/nodes/DocumentView.tsx                        |  4 ++--
 src/client/views/nodes/ImageBox.tsx                            |  2 +-
 src/client/views/nodes/PDFBox.tsx                              |  4 ++--
 src/client/views/nodes/formattedText/RichTextRules.ts          |  2 +-
 src/client/views/search/SearchBox.tsx                          |  2 +-
 src/server/ApiManagers/UploadManager.ts                        |  4 ++--
 15 files changed, 24 insertions(+), 23 deletions(-)

(limited to 'src/client/views/nodes/DocumentLinksButton.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 0bb873667..087d32a60 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1094,10 +1094,11 @@ export namespace DocUtils {
     export function MakeLinkToActiveAudio(getSourceDoc: () => Doc, broadcastEvent = true) {
         broadcastEvent && runInAction(() => DocumentManager.Instance.RecordingEvent = DocumentManager.Instance.RecordingEvent + 1);
         return DocUtils.ActiveRecordings.map(audio =>
-            DocUtils.MakeLink({ doc: getSourceDoc() }, { doc: audio.getAnchor() || audio.props.Document }, "recording link", "recording timeline"));
+            DocUtils.MakeLink({ doc: getSourceDoc() }, { doc: audio.getAnchor() || audio.props.Document }, "recording annotation:linked recording", "recording timeline"));
     }
 
     export function MakeLink(source: { doc: Doc }, target: { doc: Doc }, linkRelationship: string = "", description: string = "", id?: string, allowParCollectionLink?: boolean, showPopup?: number[]) {
+        if (!linkRelationship) linkRelationship = target.doc.type === DocumentType.RTF ? "Commentary:Comments On" : "link";
         const sv = DocumentManager.Instance.getDocumentView(source.doc);
         if (!allowParCollectionLink && sv?.props.ContainingCollectionDoc === target.doc) return;
         if (target.doc === Doc.UserDoc()) return undefined;
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 412d5a169..b6c28d2fe 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -167,7 +167,7 @@ export class DocumentManager {
     ): Promise<void> => {
         originalTarget = originalTarget ?? targetDoc;
         const getFirstDocView = LightboxView.LightboxDoc ? DocumentManager.Instance.getLightboxDocumentView : DocumentManager.Instance.getFirstDocumentView;
-        var docView = getFirstDocView(targetDoc, originatingDoc);
+        const docView = getFirstDocView(targetDoc, originatingDoc);
         const annotatedDoc = Cast(targetDoc.annotationOn, Doc, null);
         const resolvedTarget = targetDoc.type === DocumentType.MARKER ? annotatedDoc ?? targetDoc : targetDoc; // if target is a marker, then focus toggling should apply to the document it's on since the marker itself doesn't have a hidden field
         var wasHidden = resolvedTarget.hidden;
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 7ba7a1d4c..9445533dc 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -152,7 +152,7 @@ export class LinkManager {
         this.relatedLinker(anchor).forEach(link => {
             if (link.linkRelationship && link.linkRelationship !== "-ungrouped-") {
                 const relation = StrCast(link.linkRelationship);
-                const anchorRelation = relation.indexOf(":") ? relation.split(":")[Doc.AreProtosEqual(Cast(link.anchor1, Doc, null), anchor) ? 0 : 1] : relation;
+                const anchorRelation = relation.indexOf(":") !== -1 ? relation.split(":")[Doc.AreProtosEqual(Cast(link.anchor1, Doc, null), anchor) ? 0 : 1] : relation;
                 const group = anchorGroups.get(anchorRelation);
                 anchorGroups.set(anchorRelation, group ? [...group, link] : [link]);
             } else {
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 43a02d029..04c0565ea 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -61,7 +61,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
         FormattedTextBox.SelectOnLoad = target[Id];
         FormattedTextBox.DontSelectInitialText = true;
         this.allMetadata.map(tag => target[tag] = tag);
-        DocUtils.MakeLink({ doc: anchor }, { doc: target }, "inline markup");
+        DocUtils.MakeLink({ doc: anchor }, { doc: target }, "inline comment:comment on");
         this.addDocument(target);
         this._stackRef.current?.focusDocument(target);
     }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f0b3d70a0..3f72052ae 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -278,7 +278,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             if (!linkDragData.linkDragView.props.CollectionFreeFormDocumentView?.() || linkDragData.dragDocument.context !== this.props.Document) { // if the source doc view's context isn't this same freeformcollectionlinkDragData.dragDocument.context === this.props.Document
                 const source = Docs.Create.TextDocument("", { _width: 200, _height: 75, x: xp, y: yp, title: "dropped annotation" });
                 this.props.addDocument?.(source);
-                de.complete.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: linkDragData.linkSourceGetAnchor() }, "doc annotation", ""); // TODODO this is where in text links get passed
+                de.complete.linkDocument = DocUtils.MakeLink({ doc: linkDragData.linkSourceGetAnchor() }, { doc: source }, "annotated by:annotation of", ""); // TODODO this is where in text links get passed
             }
             e.stopPropagation();  //  do nothing if link is dropped into any freeform view parent of dragged document
             return true;
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 2174aaf10..5f303b428 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -521,7 +521,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         });
         const summary = Docs.Create.TextDocument("", { _backgroundColor: "#e2ad32", x: this.Bounds.left, y: this.Bounds.top, isPushpin: true, _width: 200, _height: 200, _fitToBox: true, _showSidebar: true, title: "overview" });
         const portal = Docs.Create.FreeformDocument(selected, { x: this.Bounds.left + 200, y: this.Bounds.top, isGroup: true, backgroundColor: "transparent" });
-        DocUtils.MakeLink({ doc: summary }, { doc: portal }, "summarizing", "");
+        DocUtils.MakeLink({ doc: summary }, { doc: portal }, "summary of:summarized by", "");
 
         portal.hidden = true;
         this.props.addDocument?.(portal);
diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx
index a564c59d3..17d28e886 100644
--- a/src/client/views/linking/LinkMenu.tsx
+++ b/src/client/views/linking/LinkMenu.tsx
@@ -1,9 +1,7 @@
-import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
+import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
 import { Doc } from "../../../fields/Doc";
 import { LinkManager } from "../../util/LinkManager";
-import { SelectionManager } from "../../util/SelectionManager";
-import { DocumentLinksButton } from "../nodes/DocumentLinksButton";
 import { DocumentView } from "../nodes/DocumentView";
 import { LinkDocPreview } from "../nodes/LinkDocPreview";
 import { LinkEditor } from "./LinkEditor";
diff --git a/src/client/views/nodes/DocumentLinksButton.scss b/src/client/views/nodes/DocumentLinksButton.scss
index 9ab3171d3..0f3eb14bc 100644
--- a/src/client/views/nodes/DocumentLinksButton.scss
+++ b/src/client/views/nodes/DocumentLinksButton.scss
@@ -2,7 +2,9 @@
 
 .documentLinksButton-wrapper {
     transform-origin: top left;
+    width: 100%;
 }
+
 .documentLinksButton-menu {
     width: 100%;
     height: 100%;
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index d2e6e8579..7f69adf6c 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -160,8 +160,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
             endLink = endLinkView?.docView?._componentView?.getAnchor?.() || endLink;
             startLink = DocumentLinksButton.StartLinkView?.docView?._componentView?.getAnchor?.() || startLink;
             const linkDoc = DocUtils.MakeLink({ doc: startLink }, { doc: endLink },
-                DocumentLinksButton.AnnotationId ? "hypothes.is annotation" :
-                    endLink.type === DocumentType.RTF ? "Commentary:Comments On" : "link", undefined, undefined, true);
+                DocumentLinksButton.AnnotationId ? "hypothes.is annotation" : undefined, undefined, undefined, true);
 
             LinkManager.currentLink = linkDoc;
 
@@ -245,9 +244,9 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
                 </div>
             </div>
             :
-            <div className="documentLinksButton-menu" ref={this._linkButton}>
+            <div className="documentLinksButton-menu" >
                 {this.props.InMenu && !this.props.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document ? //if the origin node is not this node
-                    <div className={"documentLinksButton-endLink"}
+                    <div className={"documentLinksButton-endLink"} ref={this._linkButton}
                         onPointerDown={DocumentLinksButton.StartLink && this.completeLink}
                         onClick={e => DocumentLinksButton.StartLink && DocumentLinksButton.finishLinkClick(e.clientX, e.clientY, DocumentLinksButton.StartLink, this.props.View.props.Document, true, this.props.View)}>
                         <FontAwesomeIcon className="documentdecorations-icon" icon="link" />
@@ -256,7 +255,8 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
                 }
                 {
                     this.props.InMenu && this.props.StartLink ? //if link has been started from current node, then set behavior of link button to deactivate linking when clicked again
-                        <div className={`documentLinksButton ${isActive ? `startLink` : ``}`} onPointerDown={isActive ? undefined : this.onLinkButtonDown} onClick={isActive ? this.clearLinks : this.onLinkClick}>
+                        <div className={`documentLinksButton ${isActive ? `startLink` : ``}`} ref={this._linkButton}
+                            onPointerDown={isActive ? undefined : this.onLinkButtonDown} onClick={isActive ? this.clearLinks : this.onLinkClick}>
                             <FontAwesomeIcon className="documentdecorations-icon" icon="link" />
                         </div>
                         :
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 9d738180b..8570f6fff 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -663,7 +663,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             }
             if (de.complete.annoDragData || this.rootDoc !== linkdrag.linkSourceDoc.context) {
                 const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.() ?? this.props.Document;
-                de.complete.linkDocument = DocUtils.MakeLink({ doc: linkdrag.linkSourceDoc }, { doc: dropDoc }, "link", undefined, undefined, undefined, [de.x, de.y]);
+                de.complete.linkDocument = DocUtils.MakeLink({ doc: linkdrag.linkSourceDoc }, { doc: dropDoc }, undefined, undefined, undefined, undefined, [de.x, de.y]);
             }
         }
     }
@@ -674,7 +674,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         const portalLink = this.allLinks.find(d => d.anchor1 === this.props.Document);
         if (!portalLink) {
             const portal = Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), _fitWidth: true, title: StrCast(this.props.Document.title) + " [Portal]" });
-            DocUtils.MakeLink({ doc: this.props.Document }, { doc: portal }, "portal to");
+            DocUtils.MakeLink({ doc: this.props.Document }, { doc: portal }, "portal to:portal from");
         }
         this.Document.followLinkLocation = "inPlace";
         this.Document.followLinkZoom = true;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index aadad5ffa..5982d4d66 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -152,7 +152,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         croppingProto.isPrototype = true;
         croppingProto.proto = Cast(this.rootDoc.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
         croppingProto.type = DocumentType.IMG;
-        croppingProto.layout = ImageBox.LayoutString("data")
+        croppingProto.layout = ImageBox.LayoutString("data");
         croppingProto.data = ObjectField.MakeCopy(this.rootDoc[this.fieldKey] as ObjectField);
         croppingProto["data-nativeWidth"] = anchw;
         croppingProto["data-nativeHeight"] = anchh;
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index b556b0ef1..668c6c8fc 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -160,11 +160,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     public backPage = () => {
         this.Document._curPage = Math.max(1, (NumCast(this.Document._curPage) || 1) - 1);
         return true;
-    };
+    }
     public forwardPage = () => {
         this.Document._curPage = Math.min(NumCast(this.dataDoc[this.props.fieldKey + "-numPages"]), (NumCast(this.Document._curPage) || 1) + 1);
         return true;
-    };
+    }
     public gotoPage = (p: number) => this.Document._curPage = p;
 
     @undoBatch
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index 00c03875b..427e05edb 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -275,7 +275,7 @@ export class RichTextRules {
                                     this.TextBox.EditorView?.dispatch(rstate.tr.setSelection(new TextSelection(rstate.doc.resolve(start), rstate.doc.resolve(end - 3))));
                                 }
                                 const target = ((docx instanceof Doc) && docx) || Docs.Create.FreeformDocument([], { title: rawdocid.replace(/^:/, ""), _width: 500, _height: 500, }, docid);
-                                DocUtils.MakeLink({ doc: this.TextBox.getAnchor() }, { doc: target }, "portal to", undefined);
+                                DocUtils.MakeLink({ doc: this.TextBox.getAnchor() }, { doc: target }, "portal to:portal from", undefined);
 
                                 const fstate = this.TextBox.EditorView?.state;
                                 if (fstate && selection) {
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 5fe2a5ab1..9257cb75e 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -112,7 +112,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
         if (this.props.linkFrom) {
             const linkFrom = this.props.linkFrom();
             if (linkFrom) {
-                DocUtils.MakeLink({ doc: linkFrom }, { doc: linkTo }, "Link");
+                DocUtils.MakeLink({ doc: linkFrom }, { doc: linkTo });
             }
         }
     });
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index 5e0cd67cc..83a2bc79b 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -14,7 +14,7 @@ import { normalize } from "path";
 import RouteSubscriber from "../RouteSubscriber";
 const imageDataUri = require('image-data-uri');
 import { SolrManager } from "./SearchManager";
-let fs = require('fs');
+const fs = require('fs');
 
 export enum Directory {
     parsed_files = "parsed_files",
@@ -265,7 +265,7 @@ export default class UploadManager extends ApiManager {
                 }
                 if (deleteFiles) {
                     const path = serverPathToFile(Directory.images, "");
-                    let regex = new RegExp(`${deleteFiles}.*`);
+                    const regex = new RegExp(`${deleteFiles}.*`);
                     fs.readdirSync(path).filter((f: any) => regex.test(f)).map((f: any) => fs.unlinkSync(path + f));
                 }
                 return imageDataUri.outputFile(uri, serverPathToFile(Directory.images, InjectSize(filename, origSuffix))).then((savedName: string) => {
-- 
cgit v1.2.3-70-g09d2

