From 464bca333ba97185dcbc93409001adeb26711902 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 1 Jul 2021 22:43:47 -0400
Subject: added ability to create anchors in PDF/Webboxes by making a selection
 and clicking the start link button

---
 src/client/views/pdf/AnchorMenu.tsx | 1 +
 1 file changed, 1 insertion(+)

(limited to 'src/client/views/pdf/AnchorMenu.tsx')

diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 1e2d72254..86b124de5 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -46,6 +46,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
     public OnClick: (e: PointerEvent) => void = unimplementedFunction;
     public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
     public Highlight: (color: string, isPushpin: boolean) => Opt<Doc> = (color: string, isPushpin: boolean) => undefined;
+    public GetAnchor: () => Opt<Doc> = () => undefined;
     public Delete: () => void = unimplementedFunction;
     public AddTag: (key: string, value: string) => boolean = returnFalse;
     public PinToPres: () => void = unimplementedFunction;
-- 
cgit v1.2.3-70-g09d2


From 3c834ee55899b91f5fff8cfe5c808607f942b9f3 Mon Sep 17 00:00:00 2001
From: dinhanhtruong <70963346+dinhanhtruong@users.noreply.github.com>
Date: Thu, 8 Jul 2021 15:51:26 -0400
Subject: created front-end link popup on text highlight

added button to AnchorMenu marquee selector for showing the link popup after highlighting text. created the front end of the popup. need to fix visibility when clicking out
---
 src/client/views/AntimodeMenu.scss                 |  1 -
 src/client/views/linking/LinkPopup.scss            | 40 +++++++++
 src/client/views/linking/LinkPopup.tsx             | 94 ++++++++++++++++++++++
 src/client/views/nodes/DocumentLinksButton.tsx     | 18 +++--
 src/client/views/nodes/LinkDocPreview.tsx          |  4 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  2 +-
 src/client/views/pdf/AnchorMenu.tsx                | 17 ++++
 7 files changed, 166 insertions(+), 10 deletions(-)
 create mode 100644 src/client/views/linking/LinkPopup.scss
 create mode 100644 src/client/views/linking/LinkPopup.tsx

(limited to 'src/client/views/pdf/AnchorMenu.tsx')

diff --git a/src/client/views/AntimodeMenu.scss b/src/client/views/AntimodeMenu.scss
index a275901be..468ee838d 100644
--- a/src/client/views/AntimodeMenu.scss
+++ b/src/client/views/AntimodeMenu.scss
@@ -8,7 +8,6 @@
     background: #323232;
     box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.25);
     // border-radius: 0px 6px 6px 6px;
-    z-index: 1001;
     display: flex;
 
     &.with-rows {
diff --git a/src/client/views/linking/LinkPopup.scss b/src/client/views/linking/LinkPopup.scss
new file mode 100644
index 000000000..009a21bd6
--- /dev/null
+++ b/src/client/views/linking/LinkPopup.scss
@@ -0,0 +1,40 @@
+.linkPopup-container {
+    background: white;
+    box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
+    top: 35px;
+    height: 200px;
+    width: 200px;
+    position: absolute;
+    padding: 10px;
+    border-radius: 3px;
+
+    input {
+        border: 1px solid #b9b9b9;
+        border-radius: 20px;
+        height: 25px;
+        width: 100%;
+        padding-left: 10px;
+    }
+
+    .divider {
+        margin: 10px 0;
+        height: 20px;
+        width: 100%;
+
+        .line {
+            height: 1px;
+            background-color: #b9b9b9;
+            width: 100%;
+            position: relative;
+            top: 12px;
+        }
+
+        .divider-text {
+            width: 20px;
+            background-color: white;
+            text-align: center;
+            position: relative;
+            margin: auto;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
new file mode 100644
index 000000000..71db06f19
--- /dev/null
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -0,0 +1,94 @@
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Tooltip } from '@material-ui/core';
+import { action, observable, runInAction } from 'mobx';
+import { observer } from "mobx-react";
+import { Doc, DocListCast } from '../../../fields/Doc';
+import { Cast, StrCast } from '../../../fields/Types';
+import { WebField } from '../../../fields/URLField';
+import { emptyFunction, setupMoveUpEvents, returnFalse, returnTrue, returnEmptyDoclist, returnEmptyFilter } from '../../../Utils';
+import { DocumentType } from '../../documents/DocumentTypes';
+import { DocumentManager } from '../../util/DocumentManager';
+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, DocumentViewSharedProps } from '../nodes/DocumentView';
+import { LinkDocPreview } from '../nodes/LinkDocPreview';
+import './LinkPopup.scss';
+import React = require("react");
+import { CurrentUserUtils } from '../../util/CurrentUserUtils';
+import { DefaultStyleProvider } from '../StyleProvider';
+import { Transform } from 'stream';
+import { DocUtils } from '../../documents/Documents';
+import { SearchBox } from '../search/SearchBox';
+
+interface LinkPopupProps {
+    showPopup: boolean;
+    // groupType: string;
+    // linkDoc: Doc;
+    // docView: DocumentView;
+    // sourceDoc: Doc;
+}
+
+/**
+ * Popup component for creating links from text to Dash documents 
+ */
+
+@observer
+export class LinkPopup extends React.Component<LinkPopupProps> {
+
+    render() {
+        const popupVisibility = this.props.showPopup ? "block" : "none";
+        return (
+            <div className="linkPopup-container" style={{ display: popupVisibility }}>
+
+                <div className="linkPopup-url-container">
+                    <input defaultValue={""} autoComplete="off" type="text" placeholder="Enter URL..." id="url-input"
+                        className="linkPopup-searchBox searchBox-input" />
+                    <button style={{ display: "block", margin: "10px auto", }}>Apply hyperlink</button>
+                </div>
+                <div className="divider">
+                    <div className="line"></div>
+                    <p className="divider-text">or</p>
+                </div>
+                <div className="linkPopup-document-search-container">
+                    <i></i>
+                    <input defaultValue={""} autoComplete="off" type="text" placeholder="Search for Document..." id="search-input"
+                        className="linkPopup-searchBox searchBox-input" />
+
+                    {/*                     
+                        <SearchBox Document={CurrentUserUtils.MySearchPanelDoc}
+                        DataDoc={CurrentUserUtils.MySearchPanelDoc}
+                        fieldKey="data"
+                        dropAction="move"
+                        isSelected={returnTrue}
+                        isContentActive={returnTrue}
+                        select={returnTrue}
+                        setHeight={returnFalse}
+                        addDocument={undefined}
+                        addDocTab={this.addDocTabFunc}
+                        pinToPres={emptyFunction}
+                        rootSelected={returnTrue}
+                        styleProvider={DefaultStyleProvider}
+                        layerProvider={undefined}
+                        removeDocument={undefined}
+                        ScreenToLocalTransform={Transform.Identity}
+                        PanelWidth={this.getPWidth}
+                        PanelHeight={this.getPHeight}
+                        renderDepth={0}
+                        focus={DocUtils.DefaultFocus}
+                        docViewPath={returnEmptyDoclist}
+                        whenChildContentsActiveChanged={emptyFunction}
+                        bringToFront={emptyFunction}
+                        docFilters={returnEmptyFilter}
+                        docRangeFilters={returnEmptyFilter}
+                        searchFilterDocs={returnEmptyDoclist}
+                        ContainingCollectionView={undefined}
+                        ContainingCollectionDoc={undefined} /> */}
+                </div>
+            </div>
+        );
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index a6d07374a..046a8c856 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -30,12 +30,12 @@ interface DocumentLinksButtonProps {
     Offset?: (number | undefined)[];
     AlwaysOn?: boolean;
     InMenu?: boolean;
-    StartLink?: boolean;
+    StartLink?: boolean; //whether the link HAS been started (i.e. now needs to be completed)
 }
 @observer
 export class DocumentLinksButton extends React.Component<DocumentLinksButtonProps, {}> {
     private _linkButton = React.createRef<HTMLDivElement>();
-    @observable public static StartLink: Doc | undefined;
+    @observable public static StartLink: Doc | undefined; //origin's Doc, if defined
     @observable public static StartLinkView: DocumentView | undefined;
     @observable public static AnnotationId: string | undefined;
     @observable public static AnnotationUri: string | undefined;
@@ -45,6 +45,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
     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) {
@@ -120,7 +121,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
             if (DocumentLinksButton.StartLink === this.props.View.props.Document) {
                 DocumentLinksButton.StartLink = undefined;
                 DocumentLinksButton.StartLinkView = undefined;
-            } else {
+            } else { //if this LinkButton's Document is undefined
                 DocumentLinksButton.StartLink = this.props.View.props.Document;
                 DocumentLinksButton.StartLinkView = this.props.View;
             }
@@ -131,6 +132,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
         }
     }
 
+
     completeLink = (e: React.PointerEvent): void => {
         setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action((e, doubleTap) => {
             if (doubleTap && !this.props.StartLink) {
@@ -141,7 +143,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
                 } else if (DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document) {
                     const sourceDoc = DocumentLinksButton.StartLink;
                     const targetDoc = this.props.View.ComponentView?.getAnchor?.() || this.props.View.Document;
-                    const linkDoc = DocUtils.MakeLink({ doc: sourceDoc }, { doc: targetDoc }, "long drag");
+                    const linkDoc = DocUtils.MakeLink({ doc: sourceDoc }, { doc: targetDoc }, "long drag"); //why is long drag here when this is used for completing links by clicking?
 
                     LinkManager.currentLink = linkDoc;
 
@@ -242,6 +244,9 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
         return results;
     }
 
+    /**
+     * gets the JSX of the link button (btn used to start/complete links) OR the link-view button (btn on bottom left of each linked node)
+     */
     @computed get linkButtonInner() {
         const btnDim = this.props.InMenu ? "20px" : "30px";
         const link = <img style={{ width: "22px", height: "16px" }} src={`/assets/${"link.png"}`} />;
@@ -263,7 +268,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
                         : link
                     : Array.from(this.filteredLinks).length}
             </div>
-            {this.props.InMenu && !this.props.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document ?
+            {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"}
                     style={{
                         width: btnDim, height: btnDim,
@@ -276,7 +281,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
                     onClick={e => DocumentLinksButton.StartLink && DocumentLinksButton.finishLinkClick(e.clientX, e.clientY, DocumentLinksButton.StartLink, this.props.View.props.Document, true, this.props.View)} />
                 : (null)
             }
-            {DocumentLinksButton.StartLink === this.props.View.props.Document && this.props.InMenu && this.props.StartLink ?
+            {DocumentLinksButton.StartLink === this.props.View.props.Document && 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-startLink"} onPointerDown={this.clearLinks} onClick={this.clearLinks} style={{ width: btnDim, height: btnDim }} />
                 : (null)
             }
@@ -290,6 +295,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
         const buttonTitle = "Tap to view links; double tap to open link collection";
         const title = this.props.InMenu ? menuTitle : buttonTitle;
 
+        //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) :
             this.props.InMenu && (DocumentLinksButton.StartLink || this.props.StartLink) ?
                 <Tooltip title={<div className="dash-tooltip">{title}</div>}>
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 65afbe131..b73fb10df 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -110,11 +110,11 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
         }
     }
     width = () => {
-        if (!this._targetDoc) return 500;
+        if (!this._targetDoc) return 225;
         if (this._targetDoc[WidthSym]() < this._targetDoc?.[HeightSym]()) {
             return Math.min(225, this._targetDoc[HeightSym]()) * this._targetDoc[WidthSym]() / this._targetDoc[HeightSym]();
         }
-        return Math.min(500, NumCast(this._targetDoc?.[WidthSym](), 500));
+        return Math.min(225, NumCast(this._targetDoc?.[WidthSym](), 225));
     }
     height = () => {
         if (!this._targetDoc) return 225;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 911ec1560..5180732b9 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1398,7 +1398,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 SelectionManager.DeselectAll();
                 RichTextMenu.Instance.updateMenu(undefined, undefined, undefined);
                 return;
-            case "Enter": this.insertTime();
+            case "Enter": this.insertTime(); 
             case "Tab": e.preventDefault(); break;
             default: if (this._lastTimedMark?.attrs.userid === Doc.CurrentUserEmail) break;
             case " ":
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 1e2d72254..4d9dbe7a0 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -10,6 +10,7 @@ import { AntimodeMenu, AntimodeMenuProps } from "../AntimodeMenu";
 import { ButtonDropdown } from "../nodes/formattedText/RichTextMenu";
 import "./AnchorMenu.scss";
 import { SelectionManager } from "../../util/SelectionManager";
+import { LinkPopup } from "../linking/LinkPopup";
 
 @observer
 export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -38,6 +39,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
     @observable private _valueValue: string = "";
     @observable private _added: boolean = false;
     @observable private highlightColor: string = "rgba(245, 230, 95, 0.616)";
+    @observable private _showLinkPopup: boolean = false;
 
     @observable public _colorBtn = false;
     @observable public Highlighting: boolean = false;
@@ -79,6 +81,14 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
         }
     }
 
+    @action
+    toggleLinkPopup = (e: React.MouseEvent) => {
+        //ignore the potential null type error because this method cannot be called unless the user selects text and clicks the link button
+        console.log(window.getSelection().toString())
+        //change popup visibility field to visible
+        this._showLinkPopup = !this._showLinkPopup;
+    }
+
     @computed get highlighter() {
         const button =
             <button className="antimodeMenu-button color-preview-button" title="" key="highlighter-button" onClick={this.highlightClicked}>
@@ -135,6 +145,13 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
                         <FontAwesomeIcon icon="comment-alt" size="lg" />
                     </button>
                 </Tooltip>,
+
+                <Tooltip key="link" title={<div className="dash-tooltip">{"Link selected text to document or URL"}</div>}>
+                    <button className="antimodeMenu-button link" onPointerDown={this.toggleLinkPopup} style={{}}>
+                        <FontAwesomeIcon icon="link" size="lg" />
+                    </button>
+                </Tooltip>,
+                <LinkPopup showPopup={this._showLinkPopup} />
             ] : [
                 <Tooltip key="trash" title={<div className="dash-tooltip">{"Remove Link Anchor"}</div>}>
                     <button className="antimodeMenu-button" onPointerDown={this.Delete}>
-- 
cgit v1.2.3-70-g09d2


From 7995c8b9b810df4ed5ade1db71fcb0e2de3d3da2 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 14 Jul 2021 09:47:18 -0400
Subject: fixed selections so that they persist on deselect to allow linking a
 selection on one document directly to a selection on another document.   Also
 fixed recently closed to move closed document to top of list.

---
 src/client/views/DocComponent.tsx     |  5 ++++-
 src/client/views/MarqueeAnnotator.tsx | 23 ++++++++++++-----------
 src/client/views/nodes/ImageBox.tsx   | 15 ++++++++++++---
 src/client/views/nodes/WebBox.tsx     |  2 +-
 src/client/views/pdf/AnchorMenu.tsx   |  4 ++--
 5 files changed, 31 insertions(+), 18 deletions(-)

(limited to 'src/client/views/pdf/AnchorMenu.tsx')

diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index a878a7afb..0b54e3cd6 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -154,7 +154,10 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
                         leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey);
                         Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
                         doc.context = undefined;
-                        recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true);
+                        if (recent) {
+                            Doc.RemoveDocFromList(recent, "data", doc);
+                            Doc.AddDocToList(recent, "data", doc, undefined, true, true);
+                        }
                     });
                     this.props.select(false);
                     return true;
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index b5df7b79b..717bd0768 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -67,7 +67,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
 
         AnchorMenu.Instance.OnClick = (e: PointerEvent) => this.props.anchorMenuClick?.()?.(this.highlight("rgba(173, 216, 230, 0.75)", true));
         AnchorMenu.Instance.Highlight = this.highlight;
-        AnchorMenu.Instance.GetAnchor = () => this.highlight("rgba(173, 216, 230, 0.75)", true);
+        AnchorMenu.Instance.GetAnchor = (savedAnnotations?: ObservableMap<number, HTMLDivElement[]>) => this.highlight("rgba(173, 216, 230, 0.75)", true, savedAnnotations);
         /**
          * This function is used by the AnchorMenu to create an anchor highlight and a new linked text annotation.  
          * It also initiates a Drag/Drop interaction to place the text annotation.
@@ -102,12 +102,13 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
 
     @undoBatch
     @action
-    makeAnnotationDocument = (color: string, isLinkButton?: boolean): Opt<Doc> => {
-        if (this.props.savedAnnotations.size === 0) return undefined;
-        const savedAnnos = Array.from(this.props.savedAnnotations.values())[0];
+    makeAnnotationDocument = (color: string, isLinkButton?: boolean, savedAnnotations?: ObservableMap<number, HTMLDivElement[]>): Opt<Doc> => {
+        const savedAnnoMap = savedAnnotations ?? this.props.savedAnnotations;
+        if (savedAnnoMap.size === 0) return undefined;
+        const savedAnnos = Array.from(savedAnnoMap.values())[0];
         if (savedAnnos.length && (savedAnnos[0] as any).marqueeing) {
             const scale = this.props.scaling?.() || 1;
-            const anno = Array.from(this.props.savedAnnotations.values())[0][0];
+            const anno = savedAnnos[0];
             const containerOffset = this.props.containerOffset?.() || [0, 0];
             const marqueeAnno = Docs.Create.FreeformDocument([], { _isLinkButton: isLinkButton, backgroundColor: color, annotationOn: this.props.rootDoc, title: "Annotation on " + this.props.rootDoc.title });
             marqueeAnno.x = (parseInt(anno.style.left || "0") - containerOffset[0]) / scale;
@@ -115,7 +116,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
             marqueeAnno._height = parseInt(anno.style.height || "0") / scale;
             marqueeAnno._width = parseInt(anno.style.width || "0") / scale;
             anno.remove();
-            this.props.savedAnnotations.clear();
+            savedAnnoMap.clear();
             return marqueeAnno;
         }
 
@@ -123,7 +124,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
         let maxX = -Number.MAX_VALUE;
         let minY = Number.MAX_VALUE;
         const annoDocs: Doc[] = [];
-        this.props.savedAnnotations.forEach((value: HTMLDivElement[], key: number) => value.map(anno => {
+        savedAnnoMap.forEach((value: HTMLDivElement[], key: number) => value.map(anno => {
             const textRegion = new Doc();
             textRegion.x = parseInt(anno.style.left ?? "0");
             textRegion.y = parseInt(anno.style.top ?? "0");
@@ -142,15 +143,15 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
         textRegionAnnoProto.x = Math.max(maxX, 0);
         // mainAnnoDocProto.text = this._selectionText;
         textRegionAnnoProto.textInlineAnnotations = new List<Doc>(annoDocs);
-        this.props.savedAnnotations.clear();
+        savedAnnoMap.clear();
         return textRegionAnno;
     }
     @action
-    highlight = (color: string, isLinkButton: boolean) => {
+    highlight = (color: string, isLinkButton: boolean, savedAnnotations?: ObservableMap<number, HTMLDivElement[]>) => {
         // creates annotation documents for current highlights
         const effectiveAcl = GetEffectiveAcl(this.props.rootDoc[DataSym]);
-        const annotationDoc = [AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl) && this.makeAnnotationDocument(color, isLinkButton);
-        annotationDoc && this.props.addDocument(annotationDoc);
+        const annotationDoc = [AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl) && this.makeAnnotationDocument(color, isLinkButton, savedAnnotations);
+        !savedAnnotations && annotationDoc && this.props.addDocument(annotationDoc);
         return annotationDoc as Doc ?? undefined;
     }
 
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 13dfad0fe..b803c94ba 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -7,7 +7,7 @@ import { List } from '../../../fields/List';
 import { ObjectField } from '../../../fields/ObjectField';
 import { createSchema, makeInterface } from '../../../fields/Schema';
 import { ComputedField } from '../../../fields/ScriptField';
-import { Cast, NumCast } from '../../../fields/Types';
+import { Cast, NumCast, StrCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
 import { TraceMobx } from '../../../fields/util';
 import { emptyFunction, OmitKeys, returnOne, Utils } from '../../../Utils';
@@ -28,6 +28,8 @@ import "./ImageBox.scss";
 import React = require("react");
 import { InkTool } from '../../../fields/InkField';
 import { CurrentUserUtils } from '../../util/CurrentUserUtils';
+import { AnchorMenu } from '../pdf/AnchorMenu';
+import { Docs } from '../../documents/Documents';
 const path = require('path');
 
 export const pageSchema = createSchema({
@@ -62,6 +64,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     } // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document
 
+
+    getAnchor = () => {
+        const anchor = AnchorMenu.Instance?.GetAnchor(this._savedAnnotations);
+        anchor && this.addDocument(anchor);
+        return anchor ?? this.rootDoc;
+    }
+
     componentDidMount() {
         this.props.setContentView?.(this); // bcz: do not remove this.  without it, stepping into an image in the lightbox causes an infinite loop....
         this._disposers.sizer = reaction(() => (
@@ -74,8 +83,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             { fireImmediately: true, delay: 1000 });
         this._disposers.selection = reaction(() => this.props.isSelected(),
             selected => !selected && setTimeout(() => {
-                Array.from(this._savedAnnotations.values()).forEach(v => v.forEach(a => a.remove()));
-                this._savedAnnotations.clear();
+                // Array.from(this._savedAnnotations.values()).forEach(v => v.forEach(a => a.remove()));
+                // this._savedAnnotations.clear();
             }));
         this._disposers.path = reaction(() => ({ nativeSize: this.nativeSize, width: this.layoutDoc[WidthSym]() }),
             ({ nativeSize, width }) => {
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index a16881b66..5791e2310 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -176,7 +176,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     getAnchor = () => {
         const anchor =
-            AnchorMenu.Instance?.GetAnchor() ??
+            AnchorMenu.Instance?.GetAnchor(this._savedAnnotations) ??
             Docs.Create.TextanchorDocument({
                 title: StrCast(this.rootDoc.title + " " + this.layoutDoc._scrollTop),
                 annotationOn: this.rootDoc,
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 86b124de5..c24c4eaaf 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -1,7 +1,7 @@
 import React = require("react");
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { Tooltip } from "@material-ui/core";
-import { action, computed, observable, IReactionDisposer, reaction } from "mobx";
+import { action, computed, observable, IReactionDisposer, reaction, ObservableMap } from "mobx";
 import { observer } from "mobx-react";
 import { ColorState } from "react-color";
 import { Doc, Opt } from "../../../fields/Doc";
@@ -46,7 +46,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
     public OnClick: (e: PointerEvent) => void = unimplementedFunction;
     public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
     public Highlight: (color: string, isPushpin: boolean) => Opt<Doc> = (color: string, isPushpin: boolean) => undefined;
-    public GetAnchor: () => Opt<Doc> = () => undefined;
+    public GetAnchor: (savedAnnotations?: ObservableMap<number, HTMLDivElement[]>) => Opt<Doc> = () => undefined;
     public Delete: () => void = unimplementedFunction;
     public AddTag: (key: string, value: string) => boolean = returnFalse;
     public PinToPres: () => void = unimplementedFunction;
-- 
cgit v1.2.3-70-g09d2


From ee06e72dab596ead6903c3ab3432ecab458613cb Mon Sep 17 00:00:00 2001
From: dinhanhtruong <70963346+dinhanhtruong@users.noreply.github.com>
Date: Mon, 26 Jul 2021 18:45:28 -0400
Subject: Link editor menu UI cleanup + color changes + temp removal of
 linkpopup for PR

---
 src/client/views/collections/CollectionLinearView.scss |  4 ++--
 src/client/views/linking/LinkEditor.scss               |  8 ++++----
 src/client/views/linking/LinkMenu.scss                 |  9 ++++-----
 src/client/views/linking/LinkMenuItem.scss             |  6 +++---
 src/client/views/linking/LinkPopup.tsx                 |  3 +--
 src/client/views/nodes/DocumentLinksButton.scss        |  1 +
 src/client/views/nodes/DocumentLinksButton.tsx         |  4 ++--
 src/client/views/pdf/AnchorMenu.tsx                    | 13 +++++++------
 8 files changed, 24 insertions(+), 24 deletions(-)

(limited to 'src/client/views/pdf/AnchorMenu.tsx')

diff --git a/src/client/views/collections/CollectionLinearView.scss b/src/client/views/collections/CollectionLinearView.scss
index 632f8dbab..dd1e1fbe8 100644
--- a/src/client/views/collections/CollectionLinearView.scss
+++ b/src/client/views/collections/CollectionLinearView.scss
@@ -20,10 +20,10 @@
         }
 
         .bottomPopup-background {
-            background: rgb(173, 216, 230);
+            background: $light-blue;
             padding-right: 14px;
             height: 35;
-            transform: translate3d(6px, 5px, 0px);
+            transform: translate3d(6px, 0px, 0px);
             padding-top: 6.5px;
             padding-bottom: 7px;
             padding-left: 5px;
diff --git a/src/client/views/linking/LinkEditor.scss b/src/client/views/linking/LinkEditor.scss
index 839ebf894..9fddede65 100644
--- a/src/client/views/linking/LinkEditor.scss
+++ b/src/client/views/linking/LinkEditor.scss
@@ -22,7 +22,7 @@
 .linkEditor-info {
     //border-bottom: 0.5px solid $light-gray;
     //padding-bottom: 1px;
-    padding-top: 5px;
+    padding: 12px;
     padding-left: 5px;
     //margin-bottom: 6px;
     display: flex;
@@ -61,7 +61,7 @@
 }
 
 .linkEditor-description {
-    padding-left: 6.5px;
+    padding-left: 26px;
     padding-right: 6.5px;
     padding-bottom: 3.5px;
 
@@ -107,9 +107,9 @@
 }
 
 .linkEditor-followingDropdown {
-    padding-left: 6.5px;
+    padding-left: 26px;
     padding-right: 6.5px;
-    padding-bottom: 6px;
+    padding-bottom: 15cpx;
 
     &:hover {
         cursor: pointer;
diff --git a/src/client/views/linking/LinkMenu.scss b/src/client/views/linking/LinkMenu.scss
index bcd93aed1..19c6463d3 100644
--- a/src/client/views/linking/LinkMenu.scss
+++ b/src/client/views/linking/LinkMenu.scss
@@ -13,9 +13,8 @@
         border: 1px solid #e4e4e4;
         box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
         background: white;
-
         min-width: 170px;
-        max-height: 170px;
+        max-height: 230px;
         overflow-y: scroll;
         z-index: 10;
     }
@@ -50,9 +49,9 @@
 
 
         &:hover {
-            p {
-                background-color: lightgray;
-            }
+            // p {
+            //     background-color: lightgray;
+            // }
 
             p.expand-one {
                 width: calc(100% + 20px);
diff --git a/src/client/views/linking/LinkMenuItem.scss b/src/client/views/linking/LinkMenuItem.scss
index 38363c2c4..90722daf9 100644
--- a/src/client/views/linking/LinkMenuItem.scss
+++ b/src/client/views/linking/LinkMenuItem.scss
@@ -55,8 +55,8 @@
 
                 .linkMenu-destination-title {
                     text-decoration: none;
-                    color: rgb(85, 120, 196);
-                    font-size: 14px;
+                    color: #4476F7;
+                    font-size: 16px;
                     padding-bottom: 2px;
                     padding-right: 4px;
                     margin-right: 4px;
@@ -76,7 +76,7 @@
                 text-decoration: none;
                 font-style: italic;
                 color: rgb(95, 97, 102);
-                font-size: 10px;
+                font-size: 9px;
                 margin-left: 20px;
                 max-width: 125px;
                 height: auto;
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index 89d5b7272..2c4b718f4 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -42,14 +42,13 @@ interface LinkPopupProps {
 export class LinkPopup extends React.Component<LinkPopupProps> {
     @observable private linkURL: string = "";
     @observable public view?: EditorView;
-    private Instance: LinkPopup = this;
 
 
 
     // TODO: should check for valid URL
     @undoBatch
     makeLinkToURL = (target: string, lcoation: string) => {
-        ((this as any)?.TextView as FormattedTextBox).makeLinkAnchor(undefined, "onRadd:rightight", target, target);
+        ((this.view as any)?.TextView as FormattedTextBox).makeLinkAnchor(undefined, "onRadd:rightight", target, target);
     }
 
     @action
diff --git a/src/client/views/nodes/DocumentLinksButton.scss b/src/client/views/nodes/DocumentLinksButton.scss
index daffaf9e7..93e1737fe 100644
--- a/src/client/views/nodes/DocumentLinksButton.scss
+++ b/src/client/views/nodes/DocumentLinksButton.scss
@@ -6,6 +6,7 @@
     min-height: 20;
     position: absolute;
 }
+
 .documentLinksButton,
 .documentLinksButton-endLink,
 .documentLinksButton-startLink {
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 4b4079670..ddc36daa1 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -143,7 +143,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
                 } else if (DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document) {
                     const sourceDoc = DocumentLinksButton.StartLink;
                     const targetDoc = this.props.View.ComponentView?.getAnchor?.() || this.props.View.Document;
-                    const linkDoc = DocUtils.MakeLink({ doc: sourceDoc }, { doc: targetDoc }, "link"); //why is long drag here when this is used for completing links by clicking?
+                    const linkDoc = DocUtils.MakeLink({ doc: sourceDoc }, { doc: targetDoc }, "links"); //why is long drag here when this is used for completing links by clicking?
 
                     LinkManager.currentLink = linkDoc;
 
@@ -257,7 +257,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
             <div className={"documentLinksButton"}
                 onPointerDown={this.onLinkButtonDown} onClick={this.onLinkClick}
                 style={{
-                    backgroundColor: this.props.InMenu ? "" : "#add8e6",
+                    backgroundColor: this.props.InMenu ? "" : '#BDDDF5',
                     color: this.props.InMenu ? "white" : "black",
                     width: btnDim,
                     height: btnDim,
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index f9e12f462..70ca19842 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -147,12 +147,13 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
                     </button>
                 </Tooltip>,
 
-                <Tooltip key="link" title={<div className="dash-tooltip">{"Link selected text to document or URL"}</div>}>
-                    <button className="antimodeMenu-button link" onPointerDown={this.toggleLinkPopup} style={{}}>
-                        <FontAwesomeIcon icon="link" size="lg" />
-                    </button>
-                </Tooltip>,
-                <LinkPopup showPopup={this._showLinkPopup} />
+                //NOTE: link popup is currently incomplete
+                // <Tooltip key="link" title={<div className="dash-tooltip">{"Link selected text to document or URL"}</div>}>
+                //     <button className="antimodeMenu-button link" onPointerDown={this.toggleLinkPopup} style={{}}>
+                //         <FontAwesomeIcon icon="link" size="lg" />
+                //     </button>
+                // </Tooltip>,
+                // <LinkPopup showPopup={this._showLinkPopup} />
             ] : [
                 <Tooltip key="trash" title={<div className="dash-tooltip">{"Remove Link Anchor"}</div>}>
                     <button className="antimodeMenu-button" onPointerDown={this.Delete}>
-- 
cgit v1.2.3-70-g09d2


From 0546ecf205b7d2b76f341a7157beebf95fb888a8 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 1 Aug 2021 22:43:46 -0400
Subject: made url server references relative.

---
 src/Utils.ts                                       |  1 -
 .../apis/google_docs/GooglePhotosClientUtils.ts    |  2 +-
 src/client/documents/Documents.ts                  | 90 ++--------------------
 src/client/util/HypothesisUtils.ts                 |  2 +-
 src/client/views/collections/CollectionSubView.tsx |  2 +-
 .../views/collections/CollectionTimeView.tsx       |  2 +-
 src/client/views/nodes/AudioBox.tsx                |  2 +-
 src/client/views/nodes/DocumentLinksButton.tsx     |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  6 +-
 src/client/views/nodes/FieldView.tsx               |  6 +-
 src/client/views/nodes/ImageBox.tsx                |  2 +-
 src/client/views/nodes/LinkDocPreview.tsx          |  4 +-
 src/client/views/nodes/PDFBox.tsx                  | 24 ------
 src/client/views/nodes/ScreenshotBox.tsx           |  4 +-
 src/client/views/nodes/VideoBox.tsx                |  8 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  6 +-
 .../views/nodes/formattedText/RichTextMenu.tsx     |  8 +-
 src/client/views/pdf/AnchorMenu.tsx                |  1 -
 src/fields/Doc.ts                                  | 12 ++-
 src/fields/URLField.ts                             | 15 +++-
 src/mobile/ImageUpload.tsx                         |  2 +-
 src/server/server_Initialization.ts                |  3 +-
 22 files changed, 58 insertions(+), 146 deletions(-)

(limited to 'src/client/views/pdf/AnchorMenu.tsx')

diff --git a/src/Utils.ts b/src/Utils.ts
index d87c3cc6b..194c38a6f 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -67,7 +67,6 @@ export namespace Utils {
     export function prepend(extension: string): string {
         return window.location.origin + extension;
     }
-
     export function fileUrl(filename: string): string {
         return prepend(`/files/${filename}`);
     }
diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts
index 899e65a16..ff9460b62 100644
--- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts
+++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts
@@ -285,7 +285,7 @@ export namespace GooglePhotos {
             const photos = await endpoint();
             const albumId = StrCast(collection.albumId);
             if (albumId && albumId.length) {
-                const enrichment = new photos.TextEnrichment(content || Utils.prepend("/doc/" + collection[Id]));
+                const enrichment = new photos.TextEnrichment(content || Doc.globalServerPath(collection));
                 const position = new photos.AlbumPosition(photos.AlbumPosition.POSITIONS.FIRST_IN_ALBUM);
                 const enrichmentItem = await photos.albums.addEnrichment(albumId, enrichment, position);
                 if (enrichmentItem) {
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index e863b4198..ac52b0acf 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -549,84 +549,6 @@ export namespace Docs {
      */
     export namespace Create {
 
-        /**
-         * Synchronously returns a collection into which
-         * the device documents will be put. This is initially empty,
-         * but gets populated by updates from the web socket. When everything is over,
-         * this function cleans up after itself.
-         * s
-         * Look at Websocket.ts for the server-side counterpart to this
-         * function.
-         */
-        export function Buxton() {
-            let responded = false;
-            const loading = new Doc;
-            loading.title = "Please wait for the import script...";
-            const parent = TreeDocument([loading], {
-                title: "The Buxton Collection",
-                _width: 400,
-                _height: 400
-            });
-            const parentProto = Doc.GetProto(parent);
-            const { _socket } = DocServer;
-
-            // just in case, clean up
-            _socket.off(MessageStore.BuxtonDocumentResult.Message);
-            _socket.off(MessageStore.BuxtonImportComplete.Message);
-
-            // this is where the client handles the receipt of a new valid parsed document
-            Utils.AddServerHandler(_socket, MessageStore.BuxtonDocumentResult, ({ device, invalid: errors }) => {
-                if (!responded) {
-                    responded = true;
-                    parentProto.data = new List<Doc>();
-                }
-                if (device) {
-                    const { title, __images, additionalMedia } = device;
-                    delete device.__images;
-                    delete device.additionalMedia;
-                    const { ImageDocument, StackingDocument } = Docs.Create;
-                    const constructed = __images.map(({ url, nativeWidth, nativeHeight }) => ({ url: Utils.prepend(url), nativeWidth, nativeHeight }));
-                    const deviceImages = constructed.map(({ url, nativeWidth, nativeHeight }, i) => {
-                        const imageDoc = ImageDocument(url, {
-                            title: `image${i}.${extname(url)}`,
-                            _nativeWidth: nativeWidth,
-                            _nativeHeight: nativeHeight
-                        });
-                        const media = additionalMedia[i];
-                        if (media) {
-                            for (const key of Object.keys(media)) {
-                                imageDoc[`additionalMedia_${key}`] = Utils.prepend(`/files/${key}/buxton/${media[key]}`);
-                            }
-                        }
-                        return imageDoc;
-                    });
-                    // the main document we create
-                    const doc = StackingDocument(deviceImages, { title, hero: new ImageField(constructed[0].url) });
-                    doc.nameAliases = new List<string>([title.toLowerCase()]);
-                    // add the parsed attributes to this main document
-                    Doc.Get.FromJson({ data: device, appendToExisting: { targetDoc: Doc.GetProto(doc) } });
-                    Doc.AddDocToList(parentProto, "data", doc);
-                } else if (errors) {
-                    console.log("Documents:" + errors);
-                } else {
-                    alert("A Buxton document import was completely empty (??)");
-                }
-            });
-
-            // when the import is complete, we stop listening for these creation
-            // and termination events and alert the user
-            Utils.AddServerHandler(_socket, MessageStore.BuxtonImportComplete, ({ deviceCount, errorCount }) => {
-                _socket.off(MessageStore.BuxtonDocumentResult.Message);
-                _socket.off(MessageStore.BuxtonImportComplete.Message);
-                alert(`Successfully imported ${deviceCount} device${deviceCount === 1 ? "" : "s"}, with ${errorCount} error${errorCount === 1 ? "" : "s"}, in ${(Date.now() - startTime) / 1000} seconds.`);
-            });
-            const startTime = Date.now();
-            Utils.Emit(_socket, MessageStore.BeginBuxtonImport, ""); // signal the server to start importing
-            return parent; // synchronously return the collection, to be populateds
-        }
-
-        Scripting.addGlobal(Buxton);
-
         /**
          * This function receives the relevant document prototype and uses
          * it to create a new of that base-level prototype, or the
@@ -675,7 +597,7 @@ export namespace Docs {
         }
 
         export function ImageDocument(url: string, options: DocumentOptions = {}) {
-            const imgField = new ImageField(new URL(url));
+            const imgField = new ImageField(url);
             return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { title: path.basename(url), ...options });
         }
 
@@ -689,11 +611,11 @@ export namespace Docs {
         }
 
         export function VideoDocument(url: string, options: DocumentOptions = {}) {
-            return InstanceFromProto(Prototypes.get(DocumentType.VID), new VideoField(new URL(url)), options);
+            return InstanceFromProto(Prototypes.get(DocumentType.VID), new VideoField(url), options);
         }
 
         export function YoutubeDocument(url: string, options: DocumentOptions = {}) {
-            return InstanceFromProto(Prototypes.get(DocumentType.YOUTUBE), new YoutubeField(new URL(url)), options);
+            return InstanceFromProto(Prototypes.get(DocumentType.YOUTUBE), new YoutubeField(url), options);
         }
 
         export function WebCamDocument(url: string, options: DocumentOptions = {}) {
@@ -709,7 +631,7 @@ export namespace Docs {
         }
 
         export function AudioDocument(url: string, options: DocumentOptions = {}) {
-            return InstanceFromProto(Prototypes.get(DocumentType.AUDIO), new AudioField(new URL(url)),
+            return InstanceFromProto(Prototypes.get(DocumentType.AUDIO), new AudioField(url),
                 { ...options, backgroundColor: ComputedField.MakeFunction("this._mediaState === 'playing' ? 'green':'gray'") as any });
         }
 
@@ -782,11 +704,11 @@ export namespace Docs {
         }
 
         export function PdfDocument(url: string, options: DocumentOptions = {}) {
-            return InstanceFromProto(Prototypes.get(DocumentType.PDF), new PdfField(new URL(url)), options);
+            return InstanceFromProto(Prototypes.get(DocumentType.PDF), new PdfField(url), options);
         }
 
         export function WebDocument(url: string, options: DocumentOptions = {}) {
-            return InstanceFromProto(Prototypes.get(DocumentType.WEB), url ? new WebField(new URL(url)) : undefined, options);
+            return InstanceFromProto(Prototypes.get(DocumentType.WEB), url ? new WebField(url) : undefined, options);
         }
 
         export function HtmlDocument(html: string, options: DocumentOptions = {}) {
diff --git a/src/client/util/HypothesisUtils.ts b/src/client/util/HypothesisUtils.ts
index 8ddfce772..635673025 100644
--- a/src/client/util/HypothesisUtils.ts
+++ b/src/client/util/HypothesisUtils.ts
@@ -126,7 +126,7 @@ export namespace Hypothesis {
         });
 
         const annotationId = StrCast(linkDoc.annotationId);
-        const linkUrl = Utils.prepend("/doc/" + sourceDoc[Id]);
+        const linkUrl = Doc.globalServerPath(sourceDoc);
         const interval = setInterval(() => {// keep trying to edit until annotations have loaded and editing is successful
             !success && document.dispatchEvent(new CustomEvent<{ targetUrl: string, id: string }>("deleteLink", {
                 detail: { targetUrl: linkUrl, id: annotationId },
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index a5d27f038..0d9b64d24 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -303,7 +303,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                     } else {
                         const path = window.location.origin + "/doc/";
                         if (text.startsWith(path)) {
-                            const docid = text.replace(Utils.prepend("/doc/"), "").split("?")[0];
+                            const docid = text.replace(Doc.globalServerPath(), "").split("?")[0];
                             DocServer.GetRefField(docid).then(f => {
                                 if (f instanceof Doc) {
                                     if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 339163510..08b5e6bac 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -37,7 +37,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
     @observable _focusRangeFilters: Opt<string[]>;
 
     getAnchor = () => {
-        const anchor = Docs.Create.HTMLAnchorDocument({
+        const anchor = Docs.Create.HTMLAnchorDocument([], {
             title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as any,
             annotationOn: this.rootDoc
         });
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index a2e36f12e..82bad971d 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -196,7 +196,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         this._recorder.ondataavailable = async (e: any) => {
             const [{ result }] = await Networking.UploadFilesToServer(e.data);
             if (!(result instanceof Error)) {
-                this.props.Document[this.props.fieldKey] = new AudioField(Utils.prepend(result.accessPaths.agnostic.client));
+                this.props.Document[this.props.fieldKey] = new AudioField(result.accessPaths.agnostic.client);
             }
         };
         this._recordStart = new Date().getTime();
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index ddc36daa1..aa3f10188 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -194,7 +194,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
                 Doc.GetProto(linkDoc as Doc).linksToAnnotation = true;
                 Doc.GetProto(linkDoc as Doc).annotationId = DocumentLinksButton.AnnotationId;
                 Doc.GetProto(linkDoc as Doc).annotationUri = DocumentLinksButton.AnnotationUri;
-                const dashHyperlink = Utils.prepend("/doc/" + (startIsAnnotation ? endLink[Id] : startLink[Id]));
+                const dashHyperlink = Doc.globalServerPath(startIsAnnotation ? endLink : startLink);
                 Hypothesis.makeLink(StrCast(startIsAnnotation ? endLink.title : startLink.title), dashHyperlink, DocumentLinksButton.AnnotationId,
                     (startIsAnnotation ? startLink : endLink)); // edit annotation to add a Dash hyperlink to the linked doc
             }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 60fa462ad..b8ccc4712 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -746,7 +746,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                         moreItems.push({ description: "Tag Child Images via Google Photos", event: () => GooglePhotos.Query.TagChildImages(this.props.Document), icon: "caret-square-right" });
                         moreItems.push({ description: "Write Back Link to Album", event: () => GooglePhotos.Transactions.AddTextEnrichment(this.props.Document), icon: "caret-square-right" });
                     }
-                    moreItems.push({ description: "Copy ID", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "fingerprint" });
+                    moreItems.push({ description: "Copy ID", event: () => Utils.CopyText(Doc.globalServerPath(this.props.Document)), icon: "fingerprint" });
                 }
             }
 
@@ -760,7 +760,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             const help = cm.findByDescription("Help...");
             const helpItems: ContextMenuProps[] = help && "subitems" in help ? help.subitems : [];
             !Doc.UserDoc().novice && helpItems.push({ description: "Show Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "add:right"), icon: "layer-group" });
-            helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument(Utils.prepend("/assets/cheat-sheet.pdf"), { _width: 300, _height: 300 }), "add:right"), icon: "keyboard" });
+            helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument("/assets/cheat-sheet.pdf", { _width: 300, _height: 300 }), "add:right"), icon: "keyboard" });
             !Doc.UserDoc().novice && helpItems.push({ description: "Print Document in Console", event: () => console.log(this.props.Document), icon: "hand-point-right" });
             cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" });
         }
@@ -885,7 +885,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             recorder.ondataavailable = async (e: any) => {
                 const [{ result }] = await Networking.UploadFilesToServer(e.data);
                 if (!(result instanceof Error)) {
-                    const audioDoc = Docs.Create.AudioDocument(Utils.prepend(result.accessPaths.agnostic.client), { title: "audio test", _width: 200, _height: 32 });
+                    const audioDoc = Docs.Create.AudioDocument(result.accessPaths.agnostic.client, { title: "audio test", _width: 200, _height: 32 });
                     audioDoc.treeViewExpandedView = "layout";
                     const audioAnnos = Cast(self.dataDoc[self.LayoutFieldKey + "-audioAnnotations"], listSpec(Doc));
                     if (audioAnnos === undefined) {
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 86250c9d1..ebbc1138a 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -64,9 +64,9 @@ export class FieldView extends React.Component<FieldViewProps> {
         // else if (field instaceof PresBox) {
         //    return <PresBox {...this.props} />;
         // }
-        else if (field instanceof VideoField) {
-            return <VideoBox {...this.props} />;
-        }
+        // else if (field instanceof VideoField) {
+        //     return <VideoBox {...this.props} />;
+        // }
         // else if (field instanceof AudioField) {
         //     return <AudioBox {...this.props} />;
         //}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index cfd43bb62..2c0106960 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -238,7 +238,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     let succeeded = true;
                     let data: ImageField | undefined;
                     try {
-                        data = new ImageField(Utils.prepend(accessPaths.agnostic.client));
+                        data = new ImageField(accessPaths.agnostic.client);
                     } catch {
                         succeeded = false;
                     }
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index b73fb10df..126a37eb8 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -72,14 +72,14 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
     @computed get href() {
         if (this.props.hrefs?.length) {
             const href = this.props.hrefs[this._hrefInd];
-            if (href.indexOf(Utils.prepend("/doc/")) !== 0) {  // link to a web page URL -- try to show a preview
+            if (href.indexOf(Doc.localServerPath()) !== 0) {  // link to a web page URL -- try to show a preview
                 if (href.startsWith("https://en.wikipedia.org/wiki/")) {
                     wiki().page(href.replace("https://en.wikipedia.org/wiki/", "")).then(page => page.summary().then(action(summary => this._toolTipText = summary.substring(0, 500))));
                 } else {
                     setTimeout(action(() => this._toolTipText = "url => " + href));
                 }
             } else { // hyperlink to a document .. decode doc id and retrieve from the server. this will trigger vals() being invalidated
-                const anchorDoc = href.replace(Utils.prepend("/doc/"), "").split("?")[0];
+                const anchorDoc = href.replace(Doc.localServerPath(), "").split("?")[0];
                 anchorDoc && DocServer.GetRefField(anchorDoc).then(action(anchor => {
                     if (anchor instanceof Doc && DocListCast(anchor.links).length) {
                         this._linkDoc = DocListCast(anchor.links)[0];
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 8f61e252b..0b451e2b4 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -53,30 +53,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             if (PDFBox.pdfcache.get(this.pdfUrl.url.href)) runInAction(() => this._pdf = PDFBox.pdfcache.get(this.pdfUrl!.url.href));
             else if (PDFBox.pdfpromise.get(this.pdfUrl.url.href)) PDFBox.pdfpromise.get(this.pdfUrl.url.href)?.then(action(pdf => this._pdf = pdf));
         }
-
-        const backup = "oldPath";
-        const href = this.pdfUrl?.url.href;
-        if (href) {
-            const pathCorrectionTest = /upload\_[a-z0-9]{32}.(.*)/g;
-            const matches = pathCorrectionTest.exec(href);
-            // console.log("\nHere's the { url } being fed into the outer regex:");
-            // console.log(href);
-            // console.log("And here's the 'properPath' build from the captured filename:\n");
-            if (matches !== null && href.startsWith(window.location.origin)) {
-                const properPath = Utils.prepend(`/files/pdfs/${matches[0]}`);
-                //console.log(properPath);
-                if (!properPath.includes(href)) {
-                    console.log(`The two (url and proper path) were not equal`);
-                    const proto = Doc.GetProto(this.props.Document);
-                    proto[this.props.fieldKey] = new PdfField(properPath);
-                    proto[backup] = href;
-                } else {
-                    //console.log(`The two (url and proper path) were equal`);
-                }
-            } else {
-                console.log("Outer matches was null!");
-            }
-        }
     }
 
     componentWillUnmount() { this._selectReactionDisposer?.(); }
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 700f8a7d3..0e235a62d 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -227,7 +227,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
             this._audioRec.onstop = async (e: any) => {
                 const [{ result }] = await Networking.UploadFilesToServer(aud_chunks);
                 if (!(result instanceof Error)) {
-                    this.dataDoc[this.props.fieldKey + "-audio"] = new AudioField(Utils.prepend(result.accessPaths.agnostic.client));
+                    this.dataDoc[this.props.fieldKey + "-audio"] = new AudioField(result.accessPaths.agnostic.client);
                 }
             };
             this._videoRef!.srcObject = await (navigator.mediaDevices as any).getDisplayMedia({ video: true });
@@ -244,7 +244,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                     this.layoutDoc.layout = VideoBox.LayoutString(this.fieldKey);
                     this.dataDoc.nativeWidth = this.dataDoc.nativeHeight = undefined;
                     this.layoutDoc._fitWidth = undefined;
-                    this.dataDoc[this.props.fieldKey] = new VideoField(Utils.prepend(result.accessPaths.agnostic.client));
+                    this.dataDoc[this.props.fieldKey] = new VideoField(result.accessPaths.agnostic.client);
                 } else alert("video conversion failed");
             };
             this._audioRec.start();
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index fc08a2302..ce45c01e6 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -75,10 +75,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, "_timecodeToShow"/* videoStart */, "_timecodeToHide" /* videoEnd */, timecode ? timecode : undefined) || this.rootDoc;
     }
 
-    choosePath(url: string) {
-        return url.indexOf(window.location.origin) === -1 ? Utils.CorsProxy(url) : url;
-    }
-
     videoLoad = () => {
         const aspect = this.player!.videoWidth / this.player!.videoHeight;
         Doc.SetNativeWidth(this.dataDoc, this.player!.videoWidth);
@@ -182,8 +178,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         }
     }
 
-    private createRealSummaryLink = (relative: string, downX?: number, downY?: number) => {
-        const url = this.choosePath(Utils.prepend(relative));
+    private createRealSummaryLink = (imagePath: string, downX?: number, downY?: number) => {
+        const url = !imagePath.startsWith("/") ? Utils.CorsProxy(imagePath) : imagePath;
         const width = this.layoutDoc._width || 1;
         const height = this.layoutDoc._height || 0;
         const imageSummary = Docs.Create.ImageDocument(url, {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 140d39929..f7e9ee028 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -371,7 +371,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
                 const anchor = Docs.Create.TextanchorDocument();
                 const alink = DocUtils.MakeLink({ doc: anchor }, { doc: target }, "automatic")!;
-                const allAnchors = [{ href: Utils.prepend("/doc/" + anchor[Id]), title: "a link", anchorId: anchor[Id] }];
+                const allAnchors = [{ href: Doc.localServerPath(anchor), title: "a link", anchorId: anchor[Id] }];
                 const link = this._editorView!.state.schema.marks.linkAnchor.create({ allAnchors, title: "auto link", location });
                 tr = tr.addMark(flattened[i].from, flattened[i].to, link);
             });
@@ -705,7 +705,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             let tr = state.tr.addMark(sel.from, sel.to, splitter);
             if (sel.from !== sel.to) {
                 const anchor = anchorDoc ?? Docs.Create.TextanchorDocument({ title: this._editorView?.state.doc.textBetween(sel.from, sel.to) });
-                const href = targetHref ?? Utils.prepend("/doc/" + anchor[Id]);
+                const href = targetHref ?? Doc.localServerPath(anchor);
                 if (anchor !== anchorDoc) this.addDocument(anchor);
                 tr.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => {
                     if (node.firstChild === null && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) {
@@ -1042,7 +1042,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             }
             const marks = [...node.marks];
             const linkIndex = marks.findIndex(mark => mark.type.name === "link");
-            const allLinks = [{ href: Utils.prepend(`/doc/${linkId}`), title, linkId }];
+            const allLinks = [{ href: Doc.globalServerPath(linkId), title, linkId }];
             const link = view.state.schema.mark(view.state.schema.marks.linkAnchor, { allLinks, location: "add:right", title, docref: true });
             marks.splice(linkIndex === -1 ? 0 : linkIndex, 1, link);
             return node.mark(marks);
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index a6f8ff2e2..fb4114023 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -821,8 +821,8 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
         if (link) {
             const href = link.attrs.allAnchors.length > 0 ? link.attrs.allAnchors[0].href : undefined;
             if (href) {
-                if (href.indexOf(Utils.prepend("/doc/")) === 0) {
-                    const linkclicked = href.replace(Utils.prepend("/doc/"), "").split("?")[0];
+                if (href.indexOf(Doc.localServerPath()) === 0) {
+                    const linkclicked = href.replace(Doc.localServerPath(), "").split("?")[0];
                     if (linkclicked) {
                         const linkDoc = await DocServer.GetRefField(linkclicked);
                         if (linkDoc instanceof Doc) {
@@ -864,8 +864,8 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
                 const allAnchors = linkAnchor.attrs.allAnchors.slice();
                 this.TextView.RemoveAnchorFromSelection(allAnchors);
                 // bcz: Argh ... this will remove the link from the document even it's anchored somewhere else in the text which happens if only part of the anchor text was selected.
-                allAnchors.filter((aref: any) => aref?.href.indexOf(Utils.prepend("/doc/")) === 0).forEach((aref: any) => {
-                    const anchorId = aref.href.replace(Utils.prepend("/doc/"), "").split("?")[0];
+                allAnchors.filter((aref: any) => aref?.href.indexOf(Doc.localServerPath()) === 0).forEach((aref: any) => {
+                    const anchorId = aref.href.replace(Doc.localServerPath(), "").split("?")[0];
                     anchorId && DocServer.GetRefField(anchorId).then(linkDoc => LinkManager.Instance.deleteLink(linkDoc as Doc));
                 });
             }
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 70ca19842..55816ed52 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -85,7 +85,6 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
     @action
     toggleLinkPopup = (e: React.MouseEvent) => {
         //ignore the potential null type error because this method cannot be called unless the user selects text and clicks the link button
-        console.log(window.getSelection().toString())
         //change popup visibility field to visible
         this._showLinkPopup = !this._showLinkPopup;
     }
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 111fd3f0d..a7e5d8541 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -596,7 +596,7 @@ export namespace Doc {
                 const mapped = cloneMap.get(id);
                 return href + (mapped ? mapped[Id] : id);
             };
-            const regex = `(${Utils.prepend("/doc/")})([^"]*)`;
+            const regex = `(${Doc.localServerPath()})([^"]*)`;
             const re = new RegExp(regex, "g");
             copy[key] = new RichTextField(field.Data.replace(/("textId":|"audioId":|"anchorId":)"([^"]+)"/g, replacer).replace(re, replacer2), field.Text);
         });
@@ -896,6 +896,16 @@ export namespace Doc {
         return true;
     }
 
+
+    // converts a document id to a url path on the server
+    export function globalServerPath(doc: Doc | string = ""): string {
+        return Utils.prepend("/doc/" + (doc instanceof Doc ? doc[Id] : doc));
+    }
+    // converts a document id to a url path on the server
+    export function localServerPath(doc?: Doc): string {
+        return "/doc/" + (doc ? doc[Id] : "");
+    }
+
     export function overlapping(doc1: Doc, doc2: Doc, clusterDistance: number) {
         const doc2Layout = Doc.Layout(doc2);
         const doc1Layout = Doc.Layout(doc1);
diff --git a/src/fields/URLField.ts b/src/fields/URLField.ts
index fb71160ca..d96e8a70a 100644
--- a/src/fields/URLField.ts
+++ b/src/fields/URLField.ts
@@ -3,14 +3,17 @@ import { serializable, custom } from "serializr";
 import { ObjectField } from "./ObjectField";
 import { ToScriptString, ToString, Copy } from "./FieldSymbols";
 import { Scripting, scriptingGlobal } from "../client/util/Scripting";
+import { Utils } from "../Utils";
 
 function url() {
     return custom(
         function (value: URL) {
-            return value.href;
+            return value.origin === window.location.origin ?
+                value.pathname :
+                value.href;
         },
         function (jsonValue: string) {
-            return new URL(jsonValue);
+            return new URL(jsonValue, window.location.origin);
         }
     );
 }
@@ -24,15 +27,21 @@ export abstract class URLField extends ObjectField {
     constructor(url: URL | string) {
         super();
         if (typeof url === "string") {
-            url = new URL(url);
+            url = url.startsWith("http") ? new URL(url) : new URL(url, window.location.origin);
         }
         this.url = url;
     }
 
     [ToScriptString]() {
+        if (Utils.prepend(this.url.pathname) === this.url.href) {
+            return `new ${this.constructor.name}("${this.url.pathname}")`;
+        }
         return `new ${this.constructor.name}("${this.url.href}")`;
     }
     [ToString]() {
+        if (Utils.prepend(this.url.pathname) === this.url.href) {
+            return this.url.pathname;
+        }
         return this.url.href;
     }
 
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
index 98696496f..f910d765e 100644
--- a/src/mobile/ImageUpload.tsx
+++ b/src/mobile/ImageUpload.tsx
@@ -50,7 +50,7 @@ export class Uploader extends React.Component<ImageUploadProps> {
                             if (result instanceof Error) {
                                 return;
                             }
-                            const path = Utils.prepend(result.accessPaths.agnostic.client);
+                            const path = result.accessPaths.agnostic.client;
                             let doc = null;
                             // Case 1: File is a video
                             if (file.type === "video/mp4") {
diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts
index e40f2b8e5..0f4a067fc 100644
--- a/src/server/server_Initialization.ts
+++ b/src/server/server_Initialization.ts
@@ -142,8 +142,9 @@ function registerCorsProxy(server: express.Express) {
     const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
     server.use("/corsProxy", async (req, res) => {
 
-        const requrl = decodeURIComponent(req.url.substring(1));
         const referer = req.headers.referer ? decodeURIComponent(req.headers.referer) : "";
+        const requrlraw = decodeURIComponent(req.url.substring(1));
+        const requrl = requrlraw.startsWith("/") ? referer + requrlraw : requrlraw;
         // cors weirdness here... 
         // if the referer is a cors page and the cors() route (I think) redirected to /corsProxy/<path> and the requested url path was relative, 
         // then we redirect again to the cors referer and just add the relative path.
-- 
cgit v1.2.3-70-g09d2


From 9aa0e5e812dfbc67b0542c6740d43209313a37d6 Mon Sep 17 00:00:00 2001
From: geireann <geireann.lindfield@gmail.com>
Date: Tue, 17 Aug 2021 23:50:00 -0400
Subject: more updates

---
 src/client/documents/Documents.ts       | 19 +++++++++----------
 src/client/views/linking/LinkPopup.scss |  2 +-
 src/client/views/linking/LinkPopup.tsx  |  6 ++++--
 src/client/views/nodes/FieldView.tsx    |  5 ++---
 src/client/views/pdf/AnchorMenu.tsx     | 25 ++++++++++++++++---------
 src/client/views/search/SearchBox.tsx   | 28 ++++++++++++++++++++--------
 6 files changed, 52 insertions(+), 33 deletions(-)

(limited to 'src/client/views/pdf/AnchorMenu.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 48886aa3b..b14a6f800 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1,7 +1,7 @@
 import { action, runInAction } from "mobx";
-import { basename, extname } from "path";
+import { basename } from "path";
 import { DateField } from "../../fields/DateField";
-import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym, Initializing, updateCachedAcls } from "../../fields/Doc";
+import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Initializing, Opt, updateCachedAcls, WidthSym } from "../../fields/Doc";
 import { Id } from "../../fields/FieldSymbols";
 import { HtmlField } from "../../fields/HtmlField";
 import { InkField } from "../../fields/InkField";
@@ -13,20 +13,20 @@ import { ComputedField, ScriptField } from "../../fields/ScriptField";
 import { Cast, NumCast, StrCast } from "../../fields/Types";
 import { AudioField, ImageField, PdfField, VideoField, WebField, YoutubeField } from "../../fields/URLField";
 import { SharingPermissions } from "../../fields/util";
-import { MessageStore } from "../../server/Message";
 import { Upload } from "../../server/SharedMediaTypes";
 import { OmitKeys, Utils } from "../../Utils";
 import { YoutubeBox } from "../apis/youtube/YoutubeBox";
 import { DocServer } from "../DocServer";
 import { Networking } from "../Network";
+import { CurrentUserUtils } from "../util/CurrentUserUtils";
 import { DocumentManager } from "../util/DocumentManager";
 import { dropActionType } from "../util/DragManager";
 import { DirectoryImportBox } from "../util/Import & Export/DirectoryImportBox";
 import { LinkManager } from "../util/LinkManager";
 import { Scripting } from "../util/Scripting";
 import { undoBatch, UndoManager } from "../util/UndoManager";
-import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMulticolumnView";
 import { CollectionDockingView } from "../views/collections/CollectionDockingView";
+import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMulticolumnView";
 import { CollectionView, CollectionViewType } from "../views/collections/CollectionView";
 import { ContextMenu } from "../views/ContextMenu";
 import { ContextMenuProps } from "../views/ContextMenuItem";
@@ -36,30 +36,29 @@ import { AudioBox } from "../views/nodes/AudioBox";
 import { ColorBox } from "../views/nodes/ColorBox";
 import { ComparisonBox } from "../views/nodes/ComparisonBox";
 import { DocFocusOptions } from "../views/nodes/DocumentView";
+import { EquationBox } from "../views/nodes/EquationBox";
+import { FieldViewProps } from "../views/nodes/FieldView";
 import { FilterBox } from "../views/nodes/FilterBox";
 import { FontIconBox } from "../views/nodes/FontIconBox";
 import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox";
+import { FunctionPlotBox } from "../views/nodes/FunctionPlotBox";
 import { ImageBox } from "../views/nodes/ImageBox";
 import { KeyValueBox } from "../views/nodes/KeyValueBox";
 import { LabelBox } from "../views/nodes/LabelBox";
 import { LinkBox } from "../views/nodes/LinkBox";
 import { LinkDescriptionPopup } from "../views/nodes/LinkDescriptionPopup";
 import { PDFBox } from "../views/nodes/PDFBox";
-import { PresBox } from "../views/nodes/trails/PresBox";
 import { ScreenshotBox } from "../views/nodes/ScreenshotBox";
 import { ScriptingBox } from "../views/nodes/ScriptingBox";
 import { SliderBox } from "../views/nodes/SliderBox";
 import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox";
+import { PresBox } from "../views/nodes/trails/PresBox";
+import { PresElementBox } from "../views/nodes/trails/PresElementBox";
 import { VideoBox } from "../views/nodes/VideoBox";
 import { WebBox } from "../views/nodes/WebBox";
-import { PresElementBox } from "../views/nodes/trails/PresElementBox";
 import { SearchBox } from "../views/search/SearchBox";
 import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
 import { DocumentType } from "./DocumentTypes";
-import { EquationBox } from "../views/nodes/EquationBox";
-import { FunctionPlotBox } from "../views/nodes/FunctionPlotBox";
-import { CurrentUserUtils } from "../util/CurrentUserUtils";
-import { FieldViewProps } from "../views/nodes/FieldView";
 const path = require('path');
 
 const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", ""));
diff --git a/src/client/views/linking/LinkPopup.scss b/src/client/views/linking/LinkPopup.scss
index 8ae65158d..60c9ebfcd 100644
--- a/src/client/views/linking/LinkPopup.scss
+++ b/src/client/views/linking/LinkPopup.scss
@@ -5,7 +5,7 @@
     height: 200px;
     width: 200px;
     position: absolute;
-    padding: 15px;
+    // padding: 15px;
     border-radius: 3px;
 
     input {
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index b5a29415f..85fd91d9f 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -50,7 +50,7 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
         const popupVisibility = this.props.showPopup ? "block" : "none";
         return (
             <div className="linkPopup-container" style={{ display: popupVisibility }}>
-                <div className="linkPopup-url-container">
+                {/* <div className="linkPopup-url-container">
                     <input autoComplete="off" type="text" value={this.linkURL} placeholder="Enter URL..." onChange={this.onLinkChange} />
                     <button onPointerDown={e => this.makeLinkToURL(this.linkURL, "add:right")}
                         style={{ display: "block", margin: "10px auto", }}>Apply hyperlink</button>
@@ -58,7 +58,7 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
                 <div className="divider">
                     <div className="line"></div>
                     <p className="divider-text">or</p>
-                </div>
+                </div> */}
                 <div className="linkPopup-document-search-container">
                     {/* <i></i>
                     <input defaultValue={""} autoComplete="off" type="text" placeholder="Search for Document..." id="search-input"
@@ -67,6 +67,8 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
                     <SearchBox 
                         Document={CurrentUserUtils.MySearchPanelDoc}
                         DataDoc={CurrentUserUtils.MySearchPanelDoc}
+                        // linkFrom={}
+                        linkSearch={true}
                         fieldKey="data"
                         dropAction="move"
                         isSelected={returnTrue}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index ebbc1138a..ee81e106a 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -2,11 +2,10 @@ import React = require("react");
 import { computed } from "mobx";
 import { observer } from "mobx-react";
 import { DateField } from "../../../fields/DateField";
-import { Doc, Field, FieldResult, Opt } from "../../../fields/Doc";
+import { Doc, Field, FieldResult } from "../../../fields/Doc";
 import { List } from "../../../fields/List";
-import { VideoField, WebField } from "../../../fields/URLField";
+import { WebField } from "../../../fields/URLField";
 import { DocumentViewSharedProps } from "./DocumentView";
-import { VideoBox } from "./VideoBox";
 
 //
 // these properties get assigned through the render() method of the DocumentView when it creates this node.
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 55816ed52..d098791e5 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -46,6 +46,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
     @observable public Status: "marquee" | "annotation" | "" = "";
 
     public OnClick: (e: PointerEvent) => void = unimplementedFunction;
+    public OnLink: (e: PointerEvent) => void = unimplementedFunction;
     public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
     public Highlight: (color: string, isPushpin: boolean) => Opt<Doc> = (color: string, isPushpin: boolean) => undefined;
     public GetAnchor: (savedAnnotations?: ObservableMap<number, HTMLDivElement[]>) => Opt<Doc> = () => undefined;
@@ -65,7 +66,14 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
 
     componentDidMount() {
         this._disposer = reaction(() => SelectionManager.Views(),
-            selected => AnchorMenu.Instance.fadeOut(true));
+            selected => {
+                AnchorMenu.Instance.fadeOut(true)
+                this._showLinkPopup = false;
+            });
+    }
+
+    componentWillUnmount() {
+        console.log("unmount");
     }
 
     pointerDown = (e: React.PointerEvent) => {
@@ -145,14 +153,13 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
                         <FontAwesomeIcon icon="comment-alt" size="lg" />
                     </button>
                 </Tooltip>,
-
-                //NOTE: link popup is currently incomplete
-                // <Tooltip key="link" title={<div className="dash-tooltip">{"Link selected text to document or URL"}</div>}>
-                //     <button className="antimodeMenu-button link" onPointerDown={this.toggleLinkPopup} style={{}}>
-                //         <FontAwesomeIcon icon="link" size="lg" />
-                //     </button>
-                // </Tooltip>,
-                // <LinkPopup showPopup={this._showLinkPopup} />
+                //NOTE: link popup is currently in progress
+                <Tooltip key="link" title={<div className="dash-tooltip">{"Link selected text to document or URL"}</div>}>
+                    <button className="antimodeMenu-button link" onPointerDown={this.toggleLinkPopup} style={{}}>
+                        <FontAwesomeIcon icon="link" size="lg" />
+                    </button>
+                </Tooltip>,
+                <LinkPopup showPopup={this._showLinkPopup}/>
             ] : [
                 <Tooltip key="trash" title={<div className="dash-tooltip">{"Remove Link Anchor"}</div>}>
                     <button className="antimodeMenu-button" onPointerDown={this.Delete}>
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 680982685..67c7fc845 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -12,21 +12,26 @@ import { ViewBoxBaseComponent } from "../DocComponent";
 import { FieldView, FieldViewProps } from '../nodes/FieldView';
 import "./SearchBox.scss";
 import { DocumentManager } from '../../util/DocumentManager';
+import { DocUtils } from '../../documents/Documents';
 
 export const searchSchema = createSchema({ 
-    Document: Doc,
-    linkSearch: Boolean 
+    Document: Doc
 });
 
 type SearchBoxDocument = makeInterface<[typeof documentSchema, typeof searchSchema]>;
 const SearchBoxDocument = makeInterface(documentSchema, searchSchema);
 
+export interface SearchBoxProps extends FieldViewProps {
+    linkSearch: boolean;
+    // linkFrom: Doc;
+}
+
 /**
  * This is the SearchBox component. It represents the search box input and results in
  * the search panel on the left side of the screen.
  */
 @observer
-export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDocument>(SearchBoxDocument) {
+export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDocument>(SearchBoxDocument) {
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SearchBox, fieldKey); }
     public static Instance: SearchBox;
 
@@ -103,6 +108,10 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         this._selectedResult = doc;
     });
 
+    makeLink = action((doc: Doc) => {
+        DocUtils.MakeLink({doc: doc}, {doc:doc});
+    });
+
     /**
      * @param {Doc[]} docs - docs to be searched through recursively
      * @param {number, Doc => void} func - function to be called on each doc
@@ -278,6 +287,9 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
     render() {
         var validResults = 0;
 
+        const isLinkSearch:boolean = this.props.linkSearch;
+
+
         const results = this._results.map(result => {
             var className = "searchBox-results-scroll-view-result";
 
@@ -288,7 +300,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             if (this._docTypeString == "all" || this._docTypeString == result[0].type) {
                 validResults++;
                 return (
-                    <div key={result[0][Id]} onClick={() => this.onResultClick(result[0])} className={className}>
+                    <div key={result[0][Id]} onClick={isLinkSearch ? () => this.makeLink(result[0]) : () => this.onResultClick(result[0])} className={className}>
                         <div className="searchBox-result-title">
                             {result[0].title}
                         </div>
@@ -309,11 +321,11 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
 
         return (
             <div style={{ pointerEvents: "all" }} className="searchBox-container">
-                <div className="searchBox-bar">
-                    <select name="type" id="searchBox-type" className="searchBox-type" onChange={this.onSelectChange}>
+                 <div className="searchBox-bar" >
+                 {isLinkSearch ? (null) : <select name="type" id="searchBox-type" className="searchBox-type" onChange={this.onSelectChange}>
                         {this.selectOptions}
-                    </select>
-                    <input defaultValue={""} autoComplete="off" onChange={this.onInputChange} type="text" placeholder="Search..." id="search-input" className="searchBox-input" ref={this._inputRef} />
+                    </select>}
+                    <input defaultValue={""} autoComplete="off" onChange={this.onInputChange} type="text" placeholder="Search..." id="search-input" className="searchBox-input" style={{width: isLinkSearch ? "100%" : undefined, borderRadius: isLinkSearch ? "5px" : undefined}} ref={this._inputRef} />
                 </div >
                 <div className="searchBox-results-container">
                     <div className="searchBox-results-count">
-- 
cgit v1.2.3-70-g09d2


From cc89a0c16246afde8bb3d891a4ede492b6644b1f Mon Sep 17 00:00:00 2001
From: geireann <geireann.lindfield@gmail.com>
Date: Wed, 18 Aug 2021 11:01:57 -0400
Subject: added search linking

---
 src/Utils.ts                                              |  1 +
 src/client/views/MarqueeAnnotator.tsx                     |  2 ++
 src/client/views/linking/LinkPopup.tsx                    |  5 ++++-
 src/client/views/nodes/formattedText/FormattedTextBox.tsx |  1 +
 src/client/views/pdf/AnchorMenu.tsx                       | 12 +++++-------
 src/client/views/search/SearchBox.tsx                     | 14 +++++++++++---
 src/client/views/topbar/TopBar.scss                       |  1 +
 7 files changed, 25 insertions(+), 11 deletions(-)

(limited to 'src/client/views/pdf/AnchorMenu.tsx')

diff --git a/src/Utils.ts b/src/Utils.ts
index 194c38a6f..f9ca8646f 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -439,6 +439,7 @@ export function emptyFunction() { }
 
 export function unimplementedFunction() { throw new Error("This function is not implemented, but should be."); }
 
+
 export type Without<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
 
 export type Predicate<K, V> = (entry: [K, V]) => boolean;
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index a3a3bce56..fa1a4cfea 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -68,6 +68,8 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
         AnchorMenu.Instance.OnClick = (e: PointerEvent) => this.props.anchorMenuClick?.()?.(this.highlight("rgba(173, 216, 230, 0.75)", true));
         AnchorMenu.Instance.Highlight = this.highlight;
         AnchorMenu.Instance.GetAnchor = (savedAnnotations?: ObservableMap<number, HTMLDivElement[]>) => this.highlight("rgba(173, 216, 230, 0.75)", true, savedAnnotations);
+        AnchorMenu.Instance.onMakeAnchor = AnchorMenu.Instance.GetAnchor;
+
         /**
          * This function is used by the AnchorMenu to create an anchor highlight and a new linked text annotation.  
          * It also initiates a Drag/Drop interaction to place the text annotation.
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index 85fd91d9f..c8be9069c 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -11,9 +11,11 @@ import { SearchBox } from '../search/SearchBox';
 import { DefaultStyleProvider } from '../StyleProvider';
 import './LinkPopup.scss';
 import React = require("react");
+import { Doc, Opt } from '../../../fields/Doc';
 
 interface LinkPopupProps {
     showPopup: boolean;
+    linkFrom?: () => Doc | undefined;
     // groupType: string;
     // linkDoc: Doc;
     // docView: DocumentView;
@@ -48,6 +50,7 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
 
     render() {
         const popupVisibility = this.props.showPopup ? "block" : "none";
+        const linkDoc = this.props.linkFrom ? this.props.linkFrom : undefined;
         return (
             <div className="linkPopup-container" style={{ display: popupVisibility }}>
                 {/* <div className="linkPopup-url-container">
@@ -67,7 +70,7 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
                     <SearchBox 
                         Document={CurrentUserUtils.MySearchPanelDoc}
                         DataDoc={CurrentUserUtils.MySearchPanelDoc}
-                        // linkFrom={}
+                        linkFrom={linkDoc}
                         linkSearch={true}
                         fieldKey="data"
                         dropAction="move"
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index b0b8ce75d..d1027dfd7 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -217,6 +217,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             this._editorView?.state && RichTextMenu.Instance.insertHighlight(color, this._editorView.state, this._editorView?.dispatch);
             return undefined;
         });
+        AnchorMenu.Instance.onMakeAnchor = this.getAnchor;
         /**
          * This function is used by the PDFmenu to create an anchor highlight and a new linked text annotation.  
          * It also initiates a Drag/Drop interaction to place the text annotation.
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index d098791e5..8d74b2ac4 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -45,8 +45,9 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
     @observable public Highlighting: boolean = false;
     @observable public Status: "marquee" | "annotation" | "" = "";
 
+    public onMakeAnchor: () => Opt<Doc> = () => undefined; // Method to get anchor from text search
+
     public OnClick: (e: PointerEvent) => void = unimplementedFunction;
-    public OnLink: (e: PointerEvent) => void = unimplementedFunction;
     public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
     public Highlight: (color: string, isPushpin: boolean) => Opt<Doc> = (color: string, isPushpin: boolean) => undefined;
     public GetAnchor: (savedAnnotations?: ObservableMap<number, HTMLDivElement[]>) => Opt<Doc> = () => undefined;
@@ -67,15 +68,12 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
     componentDidMount() {
         this._disposer = reaction(() => SelectionManager.Views(),
             selected => {
-                AnchorMenu.Instance.fadeOut(true)
                 this._showLinkPopup = false;
+                console.log("unmount");
+                AnchorMenu.Instance.fadeOut(true)
             });
     }
 
-    componentWillUnmount() {
-        console.log("unmount");
-    }
-
     pointerDown = (e: React.PointerEvent) => {
         setupMoveUpEvents(this, e, (e: PointerEvent) => {
             this.StartDrag(e, this._commentCont.current!);
@@ -159,7 +157,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
                         <FontAwesomeIcon icon="link" size="lg" />
                     </button>
                 </Tooltip>,
-                <LinkPopup showPopup={this._showLinkPopup}/>
+                <LinkPopup showPopup={this._showLinkPopup} linkFrom={this.onMakeAnchor}/>
             ] : [
                 <Tooltip key="trash" title={<div className="dash-tooltip">{"Remove Link Anchor"}</div>}>
                     <button className="antimodeMenu-button" onPointerDown={this.Delete}>
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 67c7fc845..07186fe8d 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -23,7 +23,7 @@ const SearchBoxDocument = makeInterface(documentSchema, searchSchema);
 
 export interface SearchBoxProps extends FieldViewProps {
     linkSearch: boolean;
-    // linkFrom: Doc;
+    linkFrom?: (() => Doc | undefined) | undefined;
 }
 
 /**
@@ -108,8 +108,16 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc
         this._selectedResult = doc;
     });
 
-    makeLink = action((doc: Doc) => {
-        DocUtils.MakeLink({doc: doc}, {doc:doc});
+    makeLink = action((linkTo: Doc) => {
+        console.log("[makeLink-1] got here!")
+        console.log(linkTo.title);
+        if (this.props.linkFrom){
+            const linkFrom = this.props.linkFrom();
+            if (linkFrom){
+                console.log(linkFrom.title);
+                DocUtils.MakeLink({doc: linkFrom}, {doc:linkTo});
+            }
+        }
     });
 
     /**
diff --git a/src/client/views/topbar/TopBar.scss b/src/client/views/topbar/TopBar.scss
index 2ecbb536b..d04ae8a80 100644
--- a/src/client/views/topbar/TopBar.scss
+++ b/src/client/views/topbar/TopBar.scss
@@ -53,6 +53,7 @@
             .topbar-dashboards {
                 display: flex;
                 flex-direction: row;
+                gap: 5px;
             }
 
             .topbar-lozenge-dashboard {
-- 
cgit v1.2.3-70-g09d2


From 8f77323d6be4d4e3537d2bc2bbe815e9d578eccb Mon Sep 17 00:00:00 2001
From: dinhanhtruong <70963346+dinhanhtruong@users.noreply.github.com>
Date: Fri, 20 Aug 2021 00:12:42 -0400
Subject: fixed bug where link colors reset on reload

need to fix new mystery bug where any new links disappear after refreshing once but re-appear after a second refrsh
---
 src/client/util/LinkManager.ts                             | 14 +++++++-------
 .../collectionFreeForm/CollectionFreeFormLinkView.tsx      |  3 ++-
 .../collectionFreeForm/CollectionFreeFormLinksView.tsx     |  1 +
 src/client/views/linking/LinkEditor.tsx                    | 11 ++++++-----
 src/client/views/nodes/LinkDescriptionPopup.tsx            |  4 ++--
 src/client/views/pdf/AnchorMenu.tsx                        |  4 ++--
 6 files changed, 20 insertions(+), 17 deletions(-)

(limited to 'src/client/views/pdf/AnchorMenu.tsx')

diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 175de0fa5..1fc0a7593 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -99,13 +99,13 @@ export class LinkManager {
 
 
     public createLinkrelationshipLists = () => {
-        const linkRelationshipList = new List<string>();
-        const linkColorList = new List<string>();
-        Doc.UserDoc().linkRelationshipList = linkRelationshipList;
-        Doc.UserDoc().linkColorList = linkColorList;
-        console.log(Doc.UserDoc().linkRelationshipList);
-        console.log(Doc.UserDoc().linkColorList);
-        //
+        //create new lists for link relations and their associated colors if the lists don't already exist
+        if (!Doc.UserDoc().linkRelationshipList && !Doc.UserDoc().linkColorList) {
+            const linkRelationshipList = new List<string>();
+            const linkColorList = new List<string>();
+            Doc.UserDoc().linkRelationshipList = linkRelationshipList;
+            Doc.UserDoc().linkColorList = linkColorList;
+        }
     }
 
     public addLink(linkDoc: Doc, checkExists = false) {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index ba67bbcef..0c44df64c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -180,7 +180,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         const linkRelationship = LinkManager.currentLink?.linkRelationship; //get string representing relationship
         const linkRelationshipList = Doc.UserDoc().linkRelationshipList as List<string>;
         const linkColorList = Doc.UserDoc().linkColorList as List<string>;
-        const strokeColor = linkColorList[linkRelationshipList.indexOf(linkRelationship)]; //access stroke color using index of the relationship in the color list
+        //access stroke color using index of the relationship in the color list (default black)
+        const strokeColor = linkRelationshipList.indexOf(linkRelationship) == -1 ? "black" : linkColorList[linkRelationshipList.indexOf(linkRelationship)];
         console.log(strokeColor);
         return !a.width || !b.width || ((!this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<>
             <path className="collectionfreeformlinkview-linkLine" style={{ opacity: this._opacity, strokeDasharray: "2 2", stroke: strokeColor }}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 5e0b31754..e812064b7 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -9,6 +9,7 @@ import "./CollectionFreeFormLinksView.scss";
 import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView";
 import React = require("react");
 import { DocumentType } from "../../../documents/DocumentTypes";
+import { LinkManager } from "../../../util/LinkManager";
 
 @observer
 export class CollectionFreeFormLinksView extends React.Component {
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index 22c3c5f56..7d6f4caf2 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -2,7 +2,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { Tooltip } from "@material-ui/core";
 import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
-import { Doc } from "../../../fields/Doc";
+import { Doc, StrListCast } from "../../../fields/Doc";
 import { Cast, DateCast, StrCast } from "../../../fields/Types";
 import { LinkManager } from "../../util/LinkManager";
 import { undoBatch } from "../../util/UndoManager";
@@ -41,8 +41,8 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
     setRelationshipValue = action((value: string) => {
         if (LinkManager.currentLink) {
             LinkManager.currentLink.linkRelationship = value;
-            const linkRelationshipList = Doc.UserDoc().linkRelationshipList as List<string>;
-            const linkColorList = Doc.UserDoc().linkColorList as List<string>;
+            const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList);
+            const linkColorList = StrListCast(Doc.UserDoc().linkColorList);
             // if the relationship does not exist in the list, add it and a corresponding unique randomly generated color 
             if (linkRelationshipList && !linkRelationshipList.includes(value)) {
                 linkRelationshipList.push(value);
@@ -99,10 +99,11 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
                         style={{ width: "100%" }}
                         id="input"
                         value={this.relationship}
-                        placeholder={"enter link label"}
+                        placeholder={"Enter link relationship"}
                         // color={"rgb(88, 88, 88)"}
                         onKeyDown={this.onRelationshipKey}
                         onChange={this.handleRelationshipChange}
+                        onBlur={this.onRelationshipDown}
                     ></input>
                 </div>
                 <div className="linkEditor-description-add-button"
@@ -122,7 +123,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
                         style={{ width: "100%" }}
                         id="input"
                         value={this.description}
-                        placeholder={"enter link label"}
+                        placeholder={"Enter link description"}
                         // color={"rgb(88, 88, 88)"}
                         onKeyDown={this.onKey}
                         onChange={this.handleChange}
diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx
index 30b272a9a..b62a4dd56 100644
--- a/src/client/views/nodes/LinkDescriptionPopup.tsx
+++ b/src/client/views/nodes/LinkDescriptionPopup.tsx
@@ -54,7 +54,7 @@ export class LinkDescriptionPopup extends React.Component<{}> {
             }}>
             <input className="linkDescriptionPopup-input"
                 onKeyPress={e => e.key === "Enter" && this.onDismiss(true)}
-                placeholder={"(optional) enter link label..."}
+                placeholder={"(Optional) Enter link description..."}
                 onChange={(e) => this.descriptionChanged(e)}>
             </input>
             <div className="linkDescriptionPopup-btn">
@@ -65,4 +65,4 @@ export class LinkDescriptionPopup extends React.Component<{}> {
             </div>
         </div>;
     }
-} 
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 8d74b2ac4..75e3f81fb 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -152,12 +152,12 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
                     </button>
                 </Tooltip>,
                 //NOTE: link popup is currently in progress
-                <Tooltip key="link" title={<div className="dash-tooltip">{"Link selected text to document or URL"}</div>}>
+                <Tooltip key="link" title={<div className="dash-tooltip">{"Link selected text to document"}</div>}>
                     <button className="antimodeMenu-button link" onPointerDown={this.toggleLinkPopup} style={{}}>
                         <FontAwesomeIcon icon="link" size="lg" />
                     </button>
                 </Tooltip>,
-                <LinkPopup showPopup={this._showLinkPopup} linkFrom={this.onMakeAnchor}/>
+                <LinkPopup showPopup={this._showLinkPopup} linkFrom={this.onMakeAnchor} />
             ] : [
                 <Tooltip key="trash" title={<div className="dash-tooltip">{"Remove Link Anchor"}</div>}>
                     <button className="antimodeMenu-button" onPointerDown={this.Delete}>
-- 
cgit v1.2.3-70-g09d2


From 2d8b3c6b73da1b7685903697525a277fd53340a5 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 26 Aug 2021 00:32:47 -0400
Subject: a lot of changes to move isContentActive into DocumentView

---
 src/Utils.ts                                       |  2 +-
 src/client/views/DocComponent.tsx                  | 23 ++++++++----------
 src/client/views/collections/CollectionSubView.tsx |  3 +--
 src/client/views/collections/CollectionView.tsx    |  8 ++++++-
 src/client/views/collections/TabDocView.tsx        |  3 ++-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 10 ++++----
 src/client/views/nodes/AudioBox.tsx                |  8 +++----
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  6 +++--
 src/client/views/nodes/ComparisonBox.tsx           | 17 ++++++++++----
 src/client/views/nodes/DocumentView.tsx            | 15 ++++++++----
 src/client/views/nodes/ImageBox.tsx                |  3 +--
 src/client/views/nodes/PDFBox.tsx                  | 11 ++++-----
 src/client/views/nodes/VideoBox.tsx                | 27 +++++++++++-----------
 src/client/views/nodes/WebBox.tsx                  | 12 ++++------
 .../views/nodes/formattedText/FormattedTextBox.tsx | 10 ++++----
 src/client/views/pdf/AnchorMenu.tsx                |  1 -
 src/client/views/pdf/PDFViewer.tsx                 |  3 +--
 src/fields/Doc.ts                                  |  3 +++
 18 files changed, 91 insertions(+), 74 deletions(-)

(limited to 'src/client/views/pdf/AnchorMenu.tsx')

diff --git a/src/Utils.ts b/src/Utils.ts
index 102ac520b..de3b13f63 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -116,7 +116,7 @@ export namespace Utils {
     }
 
     const isTransparentFunctionHack = "isTransparent(__value__)";
-    const noRecursionHack = "__noRecursion";
+    export const noRecursionHack = "__noRecursion";
     export function IsRecursiveFilter(val: string) {
         return !val.includes(noRecursionHack);
     }
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index d9cc29bed..33dff9da5 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -1,17 +1,17 @@
-import { Doc, Opt, DataSym, AclReadonly, AclAugment, AclPrivate, AclEdit, AclSym, DocListCast, AclAdmin, AclSelfEdit } from '../../fields/Doc';
-import { Touchable } from './Touchable';
-import { computed, action, observable } from 'mobx';
-import { Cast, BoolCast, ScriptCast } from '../../fields/Types';
+import { action, computed, observable } from 'mobx';
+import { DateField } from '../../fields/DateField';
+import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, AclSym, DataSym, Doc, DocListCast, Opt } from '../../fields/Doc';
 import { InkTool } from '../../fields/InkField';
-import { InteractionUtils } from '../util/InteractionUtils';
 import { List } from '../../fields/List';
-import { DateField } from '../../fields/DateField';
 import { ScriptField } from '../../fields/ScriptField';
-import { GetEffectiveAcl, SharingPermissions, distributeAcls, denormalizeEmail, inheritParentAcls } from '../../fields/util';
-import { CurrentUserUtils } from '../util/CurrentUserUtils';
-import { DocUtils } from '../documents/Documents';
+import { Cast, ScriptCast } from '../../fields/Types';
+import { denormalizeEmail, distributeAcls, GetEffectiveAcl, inheritParentAcls, SharingPermissions } from '../../fields/util';
 import { returnFalse } from '../../Utils';
+import { DocUtils } from '../documents/Documents';
+import { CurrentUserUtils } from '../util/CurrentUserUtils';
+import { InteractionUtils } from '../util/InteractionUtils';
 import { UndoManager } from '../util/UndoManager';
+import { Touchable } from './Touchable';
 
 
 ///  DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView)
@@ -107,6 +107,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
         // key where data is stored
         @computed get fieldKey() { return this.props.fieldKey; }
 
+        isAnyChildContentActive = () => this._isAnyChildContentActive;
 
         lookupField = (field: string) => ScriptCast((this.layoutDoc as any).lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field }).result;
 
@@ -229,10 +230,6 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
         }
 
         whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive));
-        isContentActive = (outsideReaction?: boolean) => (CurrentUserUtils.SelectedTool !== InkTool.None ||
-            (this.props.isContentActive?.() || this.props.Document.forceActive ||
-                this.props.isSelected(outsideReaction) || this._isAnyChildContentActive ||
-                this.props.rootSelected(outsideReaction)) ? true : false)
     }
     return Component;
 }
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 1f4c35daa..b70df93da 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -23,6 +23,7 @@ import ReactLoading from 'react-loading';
 export interface SubCollectionViewProps extends CollectionViewProps {
     CollectionView: Opt<CollectionView>;
     SetSubView?: (subView: any) => void;
+    isAnyChildContentActive: () => boolean;
 }
 
 export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: X) {
@@ -490,7 +491,5 @@ import { FormattedTextBox, GoogleRef } from "../nodes/formattedText/FormattedTex
 import { CollectionView, CollectionViewType, CollectionViewProps } from "./CollectionView";
 import { SelectionManager } from "../../util/SelectionManager";
 import { OverlayView } from "../OverlayView";
-import { Hypothesis } from "../../util/HypothesisUtils";
 import { GetEffectiveAcl, TraceMobx } from "../../../fields/util";
-import { FilterBox } from "../nodes/FilterBox";
 
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index a821aeeea..229e93b9e 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -37,6 +37,7 @@ import { CollectionTreeView } from "./CollectionTreeView";
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import './CollectionView.scss';
 import { returnEmptyString } from '../../../Utils';
+import { InkTool } from '../../../fields/InkField';
 export const COLLECTION_BORDER_WIDTH = 2;
 const path = require('path');
 
@@ -119,7 +120,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
         // const imageProtos = children.filter(doc => Cast(doc.data, ImageField)).map(Doc.GetProto);
         // const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags);
         // return !allTagged ? (null) : <img id={"google-tags"} src={"/assets/google_tags.png"} />;
-        this.isContentActive();
+        //this.isContentActive();
     }
 
     screenToLocalTransform = () => this.props.renderDepth ? this.props.ScreenToLocalTransform() : this.props.ScreenToLocalTransform().scale(this.props.PanelWidth() / this.bodyPanelWidth());
@@ -253,6 +254,9 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
 
     @observable _subView: any = undefined;
 
+    isContentActive = (outsideReaction?: boolean) => {
+        return this.props.isContentActive() ? true : false;
+    }
     render() {
         TraceMobx();
         const props: SubCollectionViewProps = {
@@ -262,6 +266,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             moveDocument: this.moveDocument,
             removeDocument: this.removeDocument,
             isContentActive: this.isContentActive,
+            isAnyChildContentActive: this.isAnyChildContentActive,
+            whenChildContentsActiveChanged: this.whenChildContentsActiveChanged,
             PanelWidth: this.bodyPanelWidth,
             PanelHeight: this.props.PanelHeight,
             ScreenToLocalTransform: this.screenToLocalTransform,
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index e24fcf372..117dba4de 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -480,7 +480,8 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                     childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
                     noOverlay={true} // don't render overlay Docs since they won't scale
                     setHeight={returnFalse}
-                    isContentActive={returnTrue}
+                    isContentActive={returnFalse}
+                    isAnyChildContentActive={returnFalse}
                     select={emptyFunction}
                     dropAction={undefined}
                     isSelected={returnFalse}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index b5d9ebd9f..fb949a36d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,6 +1,7 @@
 import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { computedFn } from "mobx-utils";
+import { DateField } from "../../../../fields/DateField";
 import { Doc, HeightSym, Opt, StrListCast, WidthSym } from "../../../../fields/Doc";
 import { collectionSchema, documentSchema } from "../../../../fields/documentSchemas";
 import { Id } from "../../../../fields/FieldSymbols";
@@ -17,6 +18,7 @@ import { aggregateBounds, emptyFunction, intersectRect, returnFalse, setupMoveUp
 import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
 import { DocServer } from "../../../DocServer";
 import { Docs, DocUtils } from "../../../documents/Documents";
+import { DocumentType } from "../../../documents/DocumentTypes";
 import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
 import { DocumentManager } from "../../../util/DocumentManager";
 import { DragManager, dropActionType } from "../../../util/DragManager";
@@ -48,8 +50,7 @@ import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCurso
 import "./CollectionFreeFormView.scss";
 import { MarqueeView } from "./MarqueeView";
 import React = require("react");
-import { DocumentType } from "../../../documents/DocumentTypes";
-import { DateField } from "../../../../fields/DateField";
+import Color = require("color");
 
 export const panZoomSchema = createSchema({
     _panX: "number",
@@ -117,7 +118,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
 
     @computed get views() { return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); }
     @computed get backgroundEvents() { return this.props.layerProvider?.(this.layoutDoc) === false && SnappingManager.GetIsDragging(); }
-    @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && (this.props.ContainingCollectionView?.isContentActive() || this.props.isContentActive()); }
+    @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && this.props.isContentActive(); }
     @computed get fitToContentVals() {
         return {
             bounds: { ...this.contentBounds, cx: (this.contentBounds.x + this.contentBounds.r) / 2, cy: (this.contentBounds.y + this.contentBounds.b) / 2 },
@@ -170,6 +171,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
     getContainerTransform = () => this.cachedGetContainerTransform.copy();
     getTransformOverlay = () => this.getContainerTransform().translate(1, 1);
     getActiveDocuments = () => this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout);
+    isAnyChildContentActive = () => this.props.isAnyChildContentActive();
     addLiveTextBox = (newBox: Doc) => {
         FormattedTextBox.SelectOnLoad = newBox[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed
         this.addDocument(newBox);
@@ -1033,7 +1035,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             docFilters={this.childDocFilters}
             docRangeFilters={this.childDocRangeFilters}
             searchFilterDocs={this.searchFilterDocs}
-            isContentActive={this.isAnnotationOverlay ? this.props.isContentActive : returnFalse}
+            isContentActive={returnFalse}
             isDocumentActive={this.props.childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
             focus={this.focusDocument}
             addDocTab={this.addDocTab}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 82bad971d..faaa887c4 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -267,7 +267,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     // returns the html audio element
     @computed get audio() {
-        return <audio ref={this.setRef} className={`audiobox-control${this.isContentActive() ? "-interactive" : ""}`}>
+        return <audio ref={this.setRef} className={`audiobox-control${this.props.isContentActive() ? "-interactive" : ""}`}>
             <source src={this.path} type="audio/mpeg" />
             Not supported.
         </audio>;
@@ -328,6 +328,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             focus={DocUtils.DefaultFocus}
             bringToFront={emptyFunction}
             CollectionView={undefined}
+            isAnyChildContentActive={this.isAnyChildContentActive}
             duration={this.duration}
             playFrom={this.playFrom}
             setTime={this.setAnchorTime}
@@ -337,7 +338,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             ScreenToLocalTransform={this.timelineScreenToLocal}
             Play={this.Play}
             Pause={this.Pause}
-            isContentActive={this.isContentActive}
             playLink={this.playLink}
             PanelWidth={this.timelineWidth}
             PanelHeight={this.timelineHeight}
@@ -345,7 +345,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     }
 
     render() {
-        const interactive = SnappingManager.GetIsDragging() || this.isContentActive() ? "-interactive" : "";
+        const interactive = SnappingManager.GetIsDragging() || this.props.isContentActive() ? "-interactive" : "";
         return <div className="audiobox-container"
             onContextMenu={this.specificContextMenu}
             onClick={!this.path && !this._recorder ? this.recordAudioAnnotation : undefined}
@@ -370,7 +370,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                             RECORD
                         </button>}
                 </div> :
-                <div className="audiobox-controls" style={{ pointerEvents: this._isAnyChildContentActive || this.isContentActive() ? "all" : "none" }} >
+                <div className="audiobox-controls" style={{ pointerEvents: this._isAnyChildContentActive || this.props.isContentActive() ? "all" : "none" }} >
                     <div className="audiobox-dictation" />
                     <div className="audiobox-player" style={{ height: `${AudioBox.heightPercent}%` }} >
                         <div className="audiobox-playhead" style={{ width: AudioBox.playheadWidth }} title={this.mediaState === "paused" ? "play" : "pause"} onClick={this.Play}> <FontAwesomeIcon style={{ width: "100%", position: "absolute", left: "0px", top: "5px", borderWidth: "thin", borderColor: "white" }} icon={this.mediaState === "paused" ? "play" : "pause"} size={"1x"} /></div>
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 092823603..9cc4b1f9a 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -17,8 +17,8 @@ import { InkingStroke } from "../InkingStroke";
 import { StyleProp } from "../StyleProvider";
 import "./CollectionFreeFormDocumentView.scss";
 import { DocumentView, DocumentViewProps } from "./DocumentView";
-import { FieldViewProps } from "./FieldView";
 import React = require("react");
+import Color = require("color");
 
 export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
     dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined;
@@ -164,6 +164,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
             PanelWidth: this.panelWidth,
             PanelHeight: this.panelHeight,
         };
+        const background = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
+        const mixBlendMode = StrCast(this.layoutDoc.mixBlendMode) as any || (background && Color(background).alpha() !== 1 ? "multiply" : undefined);
         return <div className={"collectionFreeFormDocumentView-container"}
             style={{
                 outline: this.Highlight ? "orange solid 2px" : "",
@@ -172,7 +174,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 transform: this.transform,
                 transition: this.props.dataTransition ? this.props.dataTransition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.dataTransition),
                 zIndex: this.ZInd,
-                mixBlendMode: StrCast(this.layoutDoc.mixBlendMode) as any,
+                mixBlendMode,
                 display: this.ZInd === -99 ? "none" : undefined
             }} >
             <DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} />
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 153176afc..6708a08ee 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -1,17 +1,18 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, observable } from 'mobx';
 import { observer } from "mobx-react";
-import { Doc } from '../../../fields/Doc';
+import { Doc, Opt } from '../../../fields/Doc';
 import { documentSchema } from '../../../fields/documentSchemas';
 import { createSchema, makeInterface } from '../../../fields/Schema';
 import { Cast, NumCast, StrCast } from '../../../fields/Types';
-import { emptyFunction, OmitKeys, setupMoveUpEvents } from '../../../Utils';
+import { emptyFunction, OmitKeys, returnFalse, setupMoveUpEvents } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { undoBatch } from '../../util/UndoManager';
 import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { StyleProp } from '../StyleProvider';
 import "./ComparisonBox.scss";
-import { DocumentView } from './DocumentView';
+import { DocumentView, DocumentViewProps } from './DocumentView';
 import { FieldView, FieldViewProps } from './FieldView';
 import React = require("react");
 
@@ -71,6 +72,11 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
         delete this.dataDoc[fieldKey];
     }
 
+    docStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => {
+        if (property === StyleProp.PointerEvents) return "none";
+        return this.props.styleProvider?.(doc, props, property);
+    }
+
     render() {
         const clipWidth = NumCast(this.layoutDoc._clipWidth) + "%";
         const clearButton = (which: string) => {
@@ -84,6 +90,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
             const whichDoc = Cast(this.dataDoc[`compareBox-${which}`], Doc, null);
             return whichDoc ? <>
                 <DocumentView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
+                    isContentActive={returnFalse}
+                    isDocumentActive={returnFalse}
+                    styleProvider={this.docStyleProvider}
                     Document={whichDoc}
                     DataDoc={undefined}
                     pointerEvents={"none"} />
@@ -102,7 +111,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
         };
 
         return (
-            <div className={`comparisonBox${this.isContentActive() || SnappingManager.GetIsDragging() ? "-interactive" : ""}` /* change className to easily disable/enable pointer events in CSS */}>
+            <div className={`comparisonBox${this.props.isContentActive() || SnappingManager.GetIsDragging() ? "-interactive" : ""}` /* change className to easily disable/enable pointer events in CSS */}>
                 {displayBox("after", 1, this.props.PanelWidth() - 3)}
                 <div className="clip-div" style={{ width: clipWidth, transition: this._animating, background: StrCast(this.layoutDoc._backgroundColor, "gray") }}>
                     {displayBox("before", 0, 0)}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index bb259da3e..11fb5cdb3 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -84,6 +84,7 @@ export interface DocComponentView {
     reverseNativeScaling?: () => boolean; // DocumentView's setup screenToLocal based on the doc having a nativeWidth/Height.  However, some content views (e.g., FreeFormView w/ fitToBox set) may ignore the native dimensions so this flags the DocumentView to not do Nativre scaling.
     shrinkWrap?: () => void;  // requests a document to display all of its contents with no white space.  currently only implemented (needed?) for freeform views
     menuControls?: () => JSX.Element; // controls to display in the top menu bar when the document is selected.
+    isAnyChildContentActive?: () => boolean; // is any child content of the document active
     getKeyFrameEditing?: () => boolean; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown)
     setKeyFrameEditing?: (set: boolean) => void; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown)
     playFrom?: (time: number, endTime?: number) => void;
@@ -182,7 +183,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     private _dropDisposer?: DragManager.DragDropDisposer;
     private _holdDisposer?: InteractionUtils.MultiTouchEventDisposer;
     protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
-    _componentView: Opt<DocComponentView>; // needs to be accessed from DocumentView wrapper class
+    @observable _componentView: Opt<DocComponentView>; // needs to be accessed from DocumentView wrapper class
 
     private get topMost() { return this.props.renderDepth === 0 && !LightboxView.LightboxDoc; }
     public get displayName() { return "DocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive
@@ -778,8 +779,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     contentScaling = () => this.ContentScale;
     onClickFunc = () => this.onClickHandler;
     setHeight = (height: number) => this.layoutDoc._height = height;
-    setContentView = (view: { getAnchor?: () => Doc, forward?: () => boolean, back?: () => boolean }) => this._componentView = view;
-    isContentActive = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || this.props.isContentActive() ? true : false;
+    setContentView = action((view: { getAnchor?: () => Doc, forward?: () => boolean, back?: () => boolean }) => this._componentView = view);
+    isContentActive = (outsideReaction?: boolean) => {
+        return CurrentUserUtils.SelectedTool !== InkTool.None ||
+            this.props.Document.forceActive ||
+            this.props.isSelected(outsideReaction) ||
+            this._componentView?.isAnyChildContentActive?.() ||
+            this.props.isContentActive() ? true : false;
+    }
     @computed get contents() {
         TraceMobx();
         const audioView = !this.layoutDoc._showAudio ? (null) :
@@ -794,7 +801,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             </div>;
         return <div className="documentView-contentsView"
             style={{
-                pointerEvents: (this.props.contentPointerEvents as any) || (CurrentUserUtils.SelectedTool !== InkTool.None || SnappingManager.GetIsDragging() || this.isContentActive() ? "all" : "none"),
+                pointerEvents: (this.props.contentPointerEvents as any) || (this.isContentActive() ? "all" : "none"),
                 height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
             }}>
             <DocumentContentsView key={1} {...this.props}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index c4e74ebd2..b392ddb95 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -332,7 +332,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         return <div className="imageBox-annotationLayer" style={{ height: this.props.PanelHeight() }} ref={this._annotationLayer} />;
     }
     marqueeDown = (e: React.PointerEvent) => {
-        if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
+        if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
             setupMoveUpEvents(this, e, action(e => {
                 MarqueeAnnotator.clearAnnotations(this._savedAnnotations)
                 this._marqueeing = [e.clientX, e.clientY];
@@ -368,7 +368,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 ScreenToLocalTransform={this.screenToLocalTransform}
                 scaling={returnOne}
                 select={emptyFunction}
-                isContentActive={this.isContentActive}
                 whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                 removeDocument={this.removeDocument}
                 moveDocument={this.moveDocument}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 23236cf20..341fa5919 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -177,9 +177,9 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         </>;
         const searchTitle = `${!this._searching ? "Open" : "Close"} Search Bar`;
         const curPage = this.Document._curPage || 1;
-        return !this.isContentActive() ? (null) :
+        return !this.props.isContentActive() ? (null) :
             <div className="pdfBox-ui" onKeyDown={e => [KeyCodes.BACKSPACE, KeyCodes.DELETE].includes(e.keyCode) ? e.stopPropagation() : true}
-                onPointerDown={e => e.stopPropagation()} style={{ display: this.isContentActive() ? "flex" : "none" }}>
+                onPointerDown={e => e.stopPropagation()} style={{ display: this.props.isContentActive() ? "flex" : "none" }}>
                 <div className="pdfBox-overlayCont" onPointerDown={(e) => e.stopPropagation()} style={{ left: `${this._searching ? 0 : 100}%` }}>
                     <button className="pdfBox-overlayButton" title={searchTitle} />
                     <input className="pdfBox-searchBar" placeholder="Search" ref={this._searchRef} onChange={this.searchStringChanged}
@@ -209,7 +209,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     {this._pageControls ? pageBtns : (null)}
                 </div>
                 <button className="pdfBox-sidebarBtn" title="Toggle Sidebar"
-                    style={{ display: !this.isContentActive() ? "none" : undefined }}
+                    style={{ display: !this.props.isContentActive() ? "none" : undefined }}
                     onPointerDown={this.sidebarBtnDown} >
                     <FontAwesomeIcon icon={"chevron-left"} size="sm" />
                 </button>
@@ -229,7 +229,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     }
 
     @computed get renderTitleBox() {
-        const classname = "pdfBox" + (this.isContentActive() ? "-interactive" : "");
+        const classname = "pdfBox" + (this.props.isContentActive() ? "-interactive" : "");
         return <div className={classname} >
             <div className="pdfBox-title-outer">
                 <strong className="pdfBox-title" >{this.props.Document.title}</strong>
@@ -268,7 +268,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     dataDoc={this.dataDoc}
                     pdf={this._pdf!}
                     url={this.pdfUrl!.url.pathname}
-                    isContentActive={this.isContentActive}
+                    isContentActive={this.props.isContentActive}
                     anchorMenuClick={this.anchorMenuClick}
                     loaded={!Doc.NativeAspect(this.dataDoc) ? this.loaded : undefined}
                     setPdfViewer={this.setPdfViewer}
@@ -291,7 +291,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 sidebarAddDocument={this.sidebarAddDocument}
                 moveDocument={this.moveDocument}
                 removeDocument={this.removeDocument}
-                isContentActive={this.isContentActive}
             />
             {this.settingsPanel()}
         </div>;
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index d4df30b48..484dec7e2 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -307,7 +307,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         const interactive = CurrentUserUtils.SelectedTool !== InkTool.None || !this.props.isSelected() ? "" : "-interactive";
         const style = "videoBox-content" + (this._fullScreen ? "-fullScreen" : "") + interactive;
         return !field ? <div key="loading">Loading</div> :
-            <div className="container" key="container" style={{ pointerEvents: this._isAnyChildContentActive || this.isContentActive() ? "all" : "none" }}>
+            <div className="container" key="container" style={{ mixBlendMode: "multiply", pointerEvents: this.props.isContentActive() ? "all" : "none" }}>
                 <div className={`${style}`} style={{ width: "100%", height: "100%", left: "0px" }}>
                     <video key="video" autoPlay={this._screenCapture} ref={this.setVideoRef}
                         style={{ height: "100%", width: "auto", display: "flex", margin: "auto" }}
@@ -321,7 +321,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         Not supported.
                     </video>
                     {!this.audiopath || this.audiopath === field.url.href ? (null) :
-                        <audio ref={this.setAudioRef} className={`audiobox-control${this.isContentActive() ? "-interactive" : ""}`}>
+                        <audio ref={this.setAudioRef} className={`audiobox-control${this.props.isContentActive() ? "-interactive" : ""}`}>
                             <source src={this.audiopath} type="audio/mpeg" />
                         Not supported.
                     </audio>}
@@ -378,30 +378,30 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     private get uIButtons() {
         const curTime = (this.layoutDoc._currentTimecode || 0);
         const nonNativeControls = [
-            <Tooltip title={<div className="dash-tooltip">{"playback"}</div>} placement="bottom">
-                <div className="videoBox-play" key="play" onPointerDown={this.onPlayDown} >
+            <Tooltip title={<div className="dash-tooltip">{"playback"}</div>} key="play" placement="bottom">
+                <div className="videoBox-play" onPointerDown={this.onPlayDown} >
                     <FontAwesomeIcon icon={this._playing ? "pause" : "play"} size="lg" />
                 </div>
             </Tooltip>,
-            <Tooltip title={<div className="dash-tooltip">{"timecode"}</div>} placement="bottom">
+            <Tooltip title={<div className="dash-tooltip">{"timecode"}</div>} key="time" placement="bottom">
                 <div className="videoBox-time" onPointerDown={this.onResetDown} >
                     <span>{formatTime(curTime)}</span>
                     <span style={{ fontSize: 8 }}>{" " + Math.floor((curTime - Math.trunc(curTime)) * 100).toString().padStart(2, "0")}</span>
                 </div>
             </Tooltip>,
-            <Tooltip title={<div className="dash-tooltip">{"view full screen"}</div>} placement="bottom">
+            <Tooltip title={<div className="dash-tooltip">{"view full screen"}</div>} key="full" placement="bottom">
                 <div className="videoBox-full" onPointerDown={this.FullScreen}>
                     <FontAwesomeIcon icon="expand" size="lg" />
                 </div>
             </Tooltip>];
         return <div className="videoBox-ui">
             {[...(VideoBox._nativeControls ? [] : nonNativeControls),
-            <Tooltip title={<div className="dash-tooltip">{"snapshot current frame"}</div>} placement="bottom">
+            <Tooltip title={<div className="dash-tooltip">{"snapshot current frame"}</div>} key="snap" placement="bottom">
                 <div className="videoBox-snapshot" onPointerDown={this.onSnapshotDown} >
                     <FontAwesomeIcon icon="camera" size="lg" />
                 </div>
             </Tooltip>,
-            <Tooltip title={<div className="dash-tooltip">{"show annotation timeline"}</div>} placement="bottom">
+            <Tooltip title={<div className="dash-tooltip">{"show annotation timeline"}</div>} key="timeline" placement="bottom">
                 <div className="videoBox-timelineButton" onPointerDown={this.onTimelineHdlDown}>
                     <FontAwesomeIcon icon="eye" size="lg" />
                 </div>
@@ -429,7 +429,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         setupMoveUpEvents(this, e,
             action((e: PointerEvent) => {
                 this._clicking = false;
-                if (this.isContentActive()) {
+                if (this.props.isContentActive()) {
                     const local = this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).transformPoint(e.clientX, e.clientY);
                     this.layoutDoc._timelineHeightPercent = Math.max(0, Math.min(100, local[1] / this.props.PanelHeight() * 100));
                 }
@@ -438,7 +438,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             () => {
                 this.layoutDoc._timelineHeightPercent = this.heightPercent !== 100 ? 100 : VideoBox.heightPercent;
                 setTimeout(action(() => this._clicking = false), 500);
-            }, this.isContentActive(), this.isContentActive());
+            }, this.props.isContentActive(), this.props.isContentActive());
     });
 
     onResetDown = (e: React.PointerEvent) => {
@@ -529,12 +529,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 playFrom={this.playFrom}
                 setTime={this.setAnchorTime}
                 playing={this.playing}
+                isAnyChildContentActive={this.isAnyChildContentActive}
                 whenChildContentsActiveChanged={this.timelineWhenChildContentsActiveChanged}
                 removeDocument={this.removeDocument}
                 ScreenToLocalTransform={this.timelineScreenToLocal}
                 Play={this.Play}
                 Pause={this.Pause}
-                isContentActive={this.isContentActive}
                 playLink={this.playLink}
                 PanelHeight={this.timelineHeight}
             />
@@ -546,7 +546,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     }
 
     marqueeDown = (e: React.PointerEvent) => {
-        if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
+        if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
             setupMoveUpEvents(this, e, action(e => {
                 MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
                 this._marqueeing = [e.clientX, e.clientY];
@@ -570,7 +570,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     }
     marqueeFitScaling = () => (this.props.scaling?.() || 1) * this.heightPercent / 100;
     marqueeOffset = () => [this.panelWidth() / 2 * (1 - this.heightPercent / 100) / (this.heightPercent / 100), 0];
-    timelineDocFilter = () => ["_timelineLabel:true:x"];
+    timelineDocFilter = () => [`_timelineLabel:true,${Utils.noRecursionHack}:x`];
     render() {
         const borderRad = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BorderRounding);
         const borderRadius = borderRad?.includes("px") ? `${Number(borderRad.split("px")[0]) / this.scaling()}px` : borderRad;
@@ -592,7 +592,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         ScreenToLocalTransform={this.screenToLocalTransform}
                         docFilters={this.timelineDocFilter}
                         select={emptyFunction}
-                        isContentActive={this.isContentActive}
                         scaling={returnOne}
                         whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                         removeDocument={this.removeDocument}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index ae6b90e41..b484ce302 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -401,7 +401,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     @action
     onMarqueeDown = (e: React.PointerEvent) => {
-        if (!e.altKey && e.button === 0 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
+        if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
             setupMoveUpEvents(this, e, action(e => {
                 MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
                 this._marqueeing = [e.clientX, e.clientY];
@@ -484,7 +484,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             NumCast(this.layoutDoc.nativeWidth)
 
     @computed get content() {
-        return <div className={"webBox-cont" + (!this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.isContentActive() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting ? "-interactive" : "")}
+        return <div className={"webBox-cont" + (!this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.props.isContentActive() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting ? "-interactive" : "")}
             style={{ width: NumCast(this.layoutDoc[this.fieldKey + "-contentWidth"]) || `${100 / (this.props.scaling?.() || 1)}%`, }}>
             {this.urlContent}
         </div>;
@@ -529,7 +529,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 docFilters={docFilters || this.props.docFilters}
                 dontRenderDocuments={docFilters ? false : true}
                 select={emptyFunction}
-                isContentActive={returnFalse}
                 ContentScaling={returnOne}
                 bringToFront={emptyFunction}
                 whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
@@ -539,7 +538,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 childPointerEvents={true}
                 pointerEvents={CurrentUserUtils.SelectedTool !== InkTool.None || this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none"} />;
         return (
-            <div className="webBox" ref={this._mainCont} style={{ pointerEvents: this.isContentActive() ? "all" : this.isContentActive() || SnappingManager.GetIsDragging() ? undefined : "none" }} >
+            <div className="webBox" ref={this._mainCont} style={{ pointerEvents: this.props.isContentActive() ? "all" : this.props.isContentActive() || SnappingManager.GetIsDragging() ? undefined : "none" }} >
                 <div className={`webBox-container`} style={{ pointerEvents }} onContextMenu={this.specificContextMenu}>
                     <base target="_blank" />
                     <div className={"webBox-outerContent"} ref={this._outerRef}
@@ -559,7 +558,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                                 {renderAnnotations(this.transparentFilter)}
                             </div>
                             {renderAnnotations(this.opaqueFilter)}
-                            {renderAnnotations()}
+                            {SnappingManager.GetIsDragging() ? (null) : renderAnnotations()}
                             {this.annotationLayer}
                         </div>
                     </div>
@@ -588,10 +587,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     sidebarAddDocument={this.sidebarAddDocument}
                     moveDocument={this.moveDocument}
                     removeDocument={this.removeDocument}
-                    isContentActive={this.isContentActive}
                 />
                 <button className="webBox-overlayButton-sidebar" key="sidebar" title="Toggle Sidebar"
-                    style={{ display: !this.isContentActive() ? "none" : undefined }}
+                    style={{ display: !this.props.isContentActive() ? "none" : undefined }}
                     onPointerDown={this.sidebarBtnDown} >
                     <FontAwesomeIcon style={{ color: "white" }} icon={"chevron-left"} size="sm" />
                 </button>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index d1027dfd7..4b1d76d00 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1211,7 +1211,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         if ((e.nativeEvent as any).formattedHandled) {
             console.log("handled");
         }
-        if (!(e.nativeEvent as any).formattedHandled && this.isContentActive(true)) {
+        if (!(e.nativeEvent as any).formattedHandled && this.props.isContentActive(true)) {
             const editor = this._editorView!;
             const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY });
             !this.props.isSelected(true) && editor.dispatch(editor.state.tr.setSelection(new TextSelection(editor.state.doc.resolve(pcords?.pos || 0))));
@@ -1481,7 +1481,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     @computed get sidebarHandle() {
         TraceMobx();
         const annotated = DocListCast(this.dataDoc[this.SidebarKey]).filter(d => d?.author).length;
-        return (!annotated && !this.isContentActive()) ? (null) : <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown}
+        return (!annotated && !this.props.isContentActive()) ? (null) : <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown}
             style={{
                 left: `max(0px, calc(100% - ${this.sidebarWidthPercent} ${this.sidebarWidth() ? "- 5px" : "- 10px"}))`,
                 background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.WidgetColor + (annotated ? ":annotated" : ""))
@@ -1504,7 +1504,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     sidebarAddDocument={this.sidebarAddDocument}
                     moveDocument={this.moveDocument}
                     removeDocument={this.removeDocument}
-                    isContentActive={this.isContentActive}
                 /> :
                 <ComponentTag
                     {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
@@ -1517,7 +1516,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     scaleField={this.SidebarKey + "-scale"}
                     isAnnotationOverlay={false}
                     select={emptyFunction}
-                    isContentActive={this.isContentActive}
                     scaling={this.sidebarContentScaling}
                     whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                     removeDocument={this.sidebarRemDocument}
@@ -1539,7 +1537,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     render() {
         TraceMobx();
         const selected = this.props.isSelected();
-        const active = this.isContentActive();
+        const active = this.props.isContentActive();
         const scale = this.props.hideOnLeave ? 1 : (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
         const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : "";
         const interactive = (CurrentUserUtils.SelectedTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || this.props.layerProvider?.(this.layoutDoc) !== false);
@@ -1551,7 +1549,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         const selPaddingClass = selected && !this.layoutDoc._singleLine && margins >= 10 ? "-selected" : "";
         return (
             <div className="formattedTextBox-cont"
-                onWheel={e => this.isContentActive() && e.stopPropagation()}
+                onWheel={e => this.props.isContentActive() && e.stopPropagation()}
                 style={{
                     transform: this.props.dontScale ? undefined : `scale(${scale})`,
                     transformOrigin: this.props.dontScale ? undefined : "top left",
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 75e3f81fb..42bec38da 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -69,7 +69,6 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
         this._disposer = reaction(() => SelectionManager.Views(),
             selected => {
                 this._showLinkPopup = false;
-                console.log("unmount");
                 AnchorMenu.Instance.fadeOut(true)
             });
     }
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 734d9127c..bc35d2126 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -512,7 +512,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
         const renderAnnotations = (docFilters?: () => string[]) =>
             <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
                 isAnnotationOverlay={true}
-                isContentActive={returnFalse}
                 fieldKey={this.props.fieldKey + "-annotations"}
                 setPreviewCursor={this.setPreviewCursor}
                 PanelHeight={this.panelHeight}
@@ -543,7 +542,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                     transform: `scale(${this._zoomed})`
                 }}>
                 {renderAnnotations(this.opaqueFilter)}
-                {renderAnnotations()}
+                {SnappingManager.GetIsDragging() ? (null) : renderAnnotations()}
             </div>
         </div>;
     }
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 17f41fac8..b09ff93d0 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1092,6 +1092,9 @@ export namespace Doc {
             const isTransparent = (color: string) => color !== "" && (Color(color).alpha() !== 1);
             return isTransparent(StrCast(doc[key]));
         }
+        if (typeof value === "string") {
+            value = value.replace(`,${Utils.noRecursionHack}`, "");
+        }
         const fieldVal = doc[key];
         if (Cast(fieldVal, listSpec("string"), []).length) {
             const vals = Cast(fieldVal, listSpec("string"), []);
-- 
cgit v1.2.3-70-g09d2


From c42f909188aff5398de31e443500eb64b8690ac4 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 26 Aug 2021 08:57:20 -0400
Subject: fixed warnings/errors

---
 src/client/util/SelectionManager.ts                |  2 +-
 src/client/views/MainView.tsx                      |  1 +
 src/client/views/TemplateMenu.tsx                  |  1 +
 .../views/collections/CollectionSchemaView.tsx     |  2 +-
 src/client/views/collections/TreeView.tsx          |  1 +
 .../CollectionFreeFormLinkView.tsx                 |  8 ++--
 .../collections/collectionSchema/SchemaTable.tsx   |  4 +-
 src/client/views/linking/LinkEditor.tsx            |  6 +--
 .../views/linking/LinkRelationshipSearch.tsx       | 12 ++---
 src/client/views/nodes/FilterBox.tsx               |  1 +
 src/client/views/nodes/ImageBox.tsx                |  2 +-
 src/client/views/nodes/LinkBox.tsx                 |  1 +
 src/client/views/pdf/AnchorMenu.tsx                |  2 +-
 src/client/views/pdf/PDFViewer.tsx                 |  2 +-
 src/client/views/search/SearchBox.tsx              | 56 ++++++++++------------
 15 files changed, 50 insertions(+), 51 deletions(-)

(limited to 'src/client/views/pdf/AnchorMenu.tsx')

diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index dbcc49f3d..0cfaebbf2 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -1,10 +1,10 @@
 import { action, observable, ObservableMap } from "mobx";
 import { computedFn } from "mobx-utils";
 import { Doc, Opt } from "../../fields/Doc";
+import { DocumentType } from "../documents/DocumentTypes";
 import { CollectionSchemaView } from "../views/collections/collectionSchema/CollectionSchemaView";
 import { CollectionViewType } from "../views/collections/CollectionView";
 import { DocumentView } from "../views/nodes/DocumentView";
-import { DocumentType } from "../documents/DocumentTypes";
 
 export namespace SelectionManager {
 
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 6a388c5b4..8b5e18fb2 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -473,6 +473,7 @@ export class MainView extends React.Component {
                     bringToFront={emptyFunction}
                     select={emptyFunction}
                     isContentActive={returnFalse}
+                    isAnyChildContentActive={returnFalse}
                     isSelected={returnFalse}
                     docViewPath={returnEmptyDoclist}
                     moveDocument={this.moveButtonDoc}
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 5491a81e6..ff3f92364 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -141,6 +141,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                 onCheckedClick={this.scriptField}
                 onChildClick={this.scriptField}
                 dropAction={undefined}
+                isAnyChildContentActive={returnFalse}
                 isContentActive={returnTrue}
                 bringToFront={emptyFunction}
                 focus={emptyFunction}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 1efea96be..6bdeaf722 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -18,6 +18,7 @@ import { SnappingManager } from "../../util/SnappingManager";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
 import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../views/global/globalCssVariables.scss';
+import { SchemaTable } from "../collections/collectionSchema/SchemaTable";
 import { ContextMenu } from "../ContextMenu";
 import { ContextMenuProps } from "../ContextMenuItem";
 import '../DocumentDecorations.scss';
@@ -25,7 +26,6 @@ import { DocumentView } from "../nodes/DocumentView";
 import { DefaultStyleProvider } from "../StyleProvider";
 import "./CollectionSchemaView.scss";
 import { CollectionSubView } from "./CollectionSubView";
-import { SchemaTable } from "../collections/collectionSchema/SchemaTable";
 // bcz: need to add drag and drop of rows and columns.  This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657
 
 export enum ColumnType {
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 3ee9dbf59..566083e7e 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -698,6 +698,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             isDocumentActive={asText ? this.props.isContentActive : returnFalse}
             styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider}
             hideTitle={asText}
+            treeViewDoc={this.props.treeView?.props.Document}
             fitContentsToDoc={returnTrue}
             hideDecorationTitle={this.props.treeView.outlineMode}
             hideResizeHandles={this.props.treeView.outlineMode}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 59891b7a1..16258404d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -2,15 +2,15 @@ import { action, computed, IReactionDisposer, observable, reaction } from "mobx"
 import { observer } from "mobx-react";
 import { Doc } from "../../../../fields/Doc";
 import { Id } from "../../../../fields/FieldSymbols";
+import { List } from "../../../../fields/List";
 import { NumCast, StrCast } from "../../../../fields/Types";
 import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils';
 import { DocumentType } from "../../../documents/DocumentTypes";
+import { LinkManager } from "../../../util/LinkManager";
 import { SnappingManager } from "../../../util/SnappingManager";
 import { DocumentView } from "../../nodes/DocumentView";
 import "./CollectionFreeFormLinkView.scss";
 import React = require("react");
-import { LinkManager } from "../../../util/LinkManager";
-import { List } from "../../../fields/List";
 
 
 export interface CollectionFreeFormLinkViewProps {
@@ -177,11 +177,11 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         if (!this.renderData) return (null);
         const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData;
         LinkManager.currentLink = this.props.LinkDocs[0];
-        const linkRelationship = LinkManager.currentLink?.linkRelationship; //get string representing relationship
+        const linkRelationship = StrCast(LinkManager.currentLink?.linkRelationship); //get string representing relationship
         const linkRelationshipList = Doc.UserDoc().linkRelationshipList as List<string>;
         const linkColorList = Doc.UserDoc().linkColorList as List<string>;
         //access stroke color using index of the relationship in the color list (default black)
-        const strokeColor = linkRelationshipList.indexOf(linkRelationship) == -1 ? "black" : linkColorList[linkRelationshipList.indexOf(linkRelationship)];
+        const strokeColor = linkRelationshipList.indexOf(linkRelationship) === -1 ? "black" : linkColorList[linkRelationshipList.indexOf(linkRelationship)];
         return !a.width || !b.width || ((!this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<>
             <path className="collectionfreeformlinkview-linkLine" style={{ opacity: this._opacity, strokeDasharray: "2 2", stroke: strokeColor }}
                 d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`} />
diff --git a/src/client/views/collections/collectionSchema/SchemaTable.tsx b/src/client/views/collections/collectionSchema/SchemaTable.tsx
index abe549072..631f623c6 100644
--- a/src/client/views/collections/collectionSchema/SchemaTable.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTable.tsx
@@ -197,7 +197,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                 <div onClick={e => this.changeSorting(col)} style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit", cursor: "hand" }}>
                     <FontAwesomeIcon icon={sortIcon} size="lg" />
                 </div>
-                {this.props.Document._chromeHidden || this.props.addDocument == returnFalse ? undefined : <div className="collectionSchemaView-addRow" onClick={this.createRow}>+ new</div>}
+                {this.props.Document._chromeHidden || this.props.addDocument === returnFalse ? undefined : <div className="collectionSchemaView-addRow" onClick={this.createRow}>+ new</div>}
             </div>;
 
             return {
@@ -562,7 +562,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
             onPointerDown={this.props.onPointerDown} onClick={this.props.onClick} onWheel={e => this.props.active(true) && e.stopPropagation()}
             onDrop={e => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} >
             {this.reactTable}
-            {this.props.Document._chromeHidden || this.props.addDocument == returnFalse ? undefined : <div className="collectionSchemaView-addRow" onClick={this.createRow}>+ new</div>}
+            {this.props.Document._chromeHidden || this.props.addDocument === returnFalse ? undefined : <div className="collectionSchemaView-addRow" onClick={this.createRow}>+ new</div>}
             {!this._showDoc ? (null) :
                 <div className="collectionSchemaView-documentPreview" ref="overlay"
                     style={{
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index fba95cad2..240a71c3e 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -48,7 +48,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
             if (linkRelationshipList && !linkRelationshipList.includes(value)) {
                 linkRelationshipList.push(value);
                 const randColor = "rgb(" + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + ")";
-                linkColorList.push(randColor)
+                linkColorList.push(randColor);
             }
             this.relationshipButtonColor = "rgb(62, 133, 55)";
             setTimeout(action(() => this.relationshipButtonColor = ""), 750);
@@ -62,7 +62,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
     @action
     getRelationshipResults = () => {
         const query = this.relationship; //current content in input box
-        const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList)
+        const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList);
         if (linkRelationshipList) {
             return linkRelationshipList.filter(rel => rel.includes(query));
         }
@@ -73,7 +73,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
      */
     @action
     toggleRelationshipResults = () => {
-        this.relationshipSearchVisibility = this.relationshipSearchVisibility == "none" ? "block" : "none";
+        this.relationshipSearchVisibility = this.relationshipSearchVisibility === "none" ? "block" : "none";
     }
 
     @undoBatch
diff --git a/src/client/views/linking/LinkRelationshipSearch.tsx b/src/client/views/linking/LinkRelationshipSearch.tsx
index 8f83f0e6e..53da880e4 100644
--- a/src/client/views/linking/LinkRelationshipSearch.tsx
+++ b/src/client/views/linking/LinkRelationshipSearch.tsx
@@ -15,7 +15,7 @@ export class LinkRelationshipSearch extends React.Component<LinkRelationshipSear
     handleResultClick = (e: React.MouseEvent) => {
         const relationship = (e.target as HTMLParagraphElement).textContent;
         if (relationship) {
-            this.props.handleRelationshipSearchChange(relationship)
+            this.props.handleRelationshipSearchChange(relationship);
         }
     }
 
@@ -31,8 +31,8 @@ export class LinkRelationshipSearch extends React.Component<LinkRelationshipSear
      * Render an empty div to increase the height of LinkEditor to accommodate 2+ results 
     */
     emptyDiv = () => {
-        if (this.props.results && this.props.results.length > 2 && this.props.display == "block") {
-            return <div style={{ height: "50px" }}></div>
+        if (this.props.results && this.props.results.length > 2 && this.props.display === "block") {
+            return <div style={{ height: "50px" }} />;
         }
     }
 
@@ -47,9 +47,9 @@ export class LinkRelationshipSearch extends React.Component<LinkRelationshipSear
                     {   // return a dropdown of relationship results if there exist results
                         this.props.results
                             ? this.props.results.map(result => {
-                                return (<p key={result} onClick={this.handleResultClick}>
+                                return <p key={result} onClick={this.handleResultClick}>
                                     {result}
-                                </p>)
+                                </p>;
                             })
                             : <p>No matching relationships</p>
                     }
@@ -58,6 +58,6 @@ export class LinkRelationshipSearch extends React.Component<LinkRelationshipSear
                 {/*Render an empty div to increase the height of LinkEditor to accommodate 2+ results */}
                 {this.emptyDiv()}
             </div>
-        )
+        );
     }
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index 1e13d1b5a..7ad03e055 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -417,6 +417,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
                     renderDepth={1}
                     dropAction={this.props.dropAction}
                     ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+                    isAnyChildContentActive={returnFalse}
                     addDocTab={returnFalse}
                     pinToPres={returnFalse}
                     isSelected={returnFalse}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index b392ddb95..38deb4a73 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -334,7 +334,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     marqueeDown = (e: React.PointerEvent) => {
         if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
             setupMoveUpEvents(this, e, action(e => {
-                MarqueeAnnotator.clearAnnotations(this._savedAnnotations)
+                MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
                 this._marqueeing = [e.clientX, e.clientY];
                 return true;
             }), returnFalse, () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations), false);
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index c65ba9c69..55ea45bb8 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -30,6 +30,7 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps, LinkDocument>(
                 dontRegisterView={true}
                 renderDepth={this.props.renderDepth + 1}
                 CollectionView={undefined}
+                isAnyChildContentActive={returnFalse}
                 isContentActive={this.isContentActiveFunc}
                 addDocument={returnFalse}
                 removeDocument={returnFalse}
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 42bec38da..95e318738 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -69,7 +69,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
         this._disposer = reaction(() => SelectionManager.Views(),
             selected => {
                 this._showLinkPopup = false;
-                AnchorMenu.Instance.fadeOut(true)
+                AnchorMenu.Instance.fadeOut(true);
             });
     }
 
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index bc35d2126..e77fdde3d 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -525,7 +525,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 CollectionView={undefined}
                 ScreenToLocalTransform={this.overlayTransform}
                 renderDepth={this.props.renderDepth + 1}
-                childPointerEvents={true} />
+                childPointerEvents={true} />;
         return <div>
             <div className={`pdfViewerDash-overlay${CurrentUserUtils.SelectedTool !== InkTool.None || SnappingManager.GetIsDragging() ? "-inking" : ""}`}
                 style={{
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 07186fe8d..260ddfc90 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -14,7 +14,7 @@ import "./SearchBox.scss";
 import { DocumentManager } from '../../util/DocumentManager';
 import { DocUtils } from '../../documents/Documents';
 
-export const searchSchema = createSchema({ 
+export const searchSchema = createSchema({
     Document: Doc
 });
 
@@ -109,13 +109,12 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc
     });
 
     makeLink = action((linkTo: Doc) => {
-        console.log("[makeLink-1] got here!")
         console.log(linkTo.title);
-        if (this.props.linkFrom){
+        if (this.props.linkFrom) {
             const linkFrom = this.props.linkFrom();
-            if (linkFrom){
+            if (linkFrom) {
                 console.log(linkFrom.title);
-                DocUtils.MakeLink({doc: linkFrom}, {doc:linkTo});
+                DocUtils.MakeLink({ doc: linkFrom }, { doc: linkTo });
             }
         }
     });
@@ -177,10 +176,10 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc
      * right side of each search result.
      */
     static formatType(type: String): String {
-        if (type == "pdf") {
+        if (type === "pdf") {
             return "PDF";
         }
-        else if (type == "image") {
+        else if (type === "image") {
             return "Img";
         }
 
@@ -200,28 +199,25 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc
         const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.KVP, DocumentType.FILTER, DocumentType.SEARCH, DocumentType.SEARCHITEM, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
         const blockedKeys = ["x", "y", "proto", "width", "autoHeight", "acl-Override", "acl-Public", "context", "zIndex", "height", "text-scrollHeight", "text-height", "cloneFieldFilter", "isPrototype", "text-annotations",
             "dragFactory-count", "text-noTemplate", "aliases", "system", "layoutKey", "baseProto", "xMargin", "yMargin", "links", "layout", "layout_keyValue", "fitWidth", "viewType", "title-custom",
-            "panX", "panY", "viewScale"]
+            "panX", "panY", "viewScale"];
         const collection = CollectionDockingView.Instance;
         query = query.toLowerCase();
 
-        this._results = []
-        this._selectedResult = undefined
+        this._results = [];
+        this._selectedResult = undefined;
 
         if (collection !== undefined) {
             const docs = DocListCast(collection.rootDoc[Doc.LayoutFieldKey(collection.rootDoc)]);
-            const docIDs: String[] = []
-            console.log(docs.length)
+            const docIDs: String[] = [];
             SearchBox.foreachRecursiveDoc(docs, (depth: number, doc: Doc) => {
                 const dtype = StrCast(doc.type, "string") as DocumentType;
                 if (dtype && !blockedTypes.includes(dtype) && !docIDs.includes(doc[Id]) && depth > 0) {
                     const hlights = new Set<string>();
                     SearchBox.documentKeys(doc).forEach(key => Field.toString(doc[key] as Field).toLowerCase().includes(query) && hlights.add(key));
-                    blockedKeys.forEach(key => {
-                        hlights.delete(key);
-                    })
+                    blockedKeys.forEach(key => hlights.delete(key));
                     Array.from(hlights.keys()).length > 0 && this._results.push([doc, Array.from(hlights.keys())]);
                 }
-                docIDs.push(doc[Id])
+                docIDs.push(doc[Id]);
             });
         }
     }
@@ -245,7 +241,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc
     submitSearch = async () => {
         this.resetSearch();
 
-        let query = StrCast(this._searchString);
+        const query = StrCast(this._searchString);
         Doc.SetSearchQuery(query);
         this._results = [];
 
@@ -282,11 +278,9 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc
      */
     @computed
     public get selectOptions() {
-        const selectValues = ["all", "rtf", "image", "pdf", "web", "video", "audio", "collection"]
+        const selectValues = ["all", "rtf", "image", "pdf", "web", "video", "audio", "collection"];
 
-        return selectValues.map(value => {
-            return <option key={value} value={value}>{SearchBox.formatType(value)}</option>
-        })
+        return selectValues.map(value => <option key={value} value={value}>{SearchBox.formatType(value)}</option>);
     }
 
     /**
@@ -295,17 +289,17 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc
     render() {
         var validResults = 0;
 
-        const isLinkSearch:boolean = this.props.linkSearch;
+        const isLinkSearch: boolean = this.props.linkSearch;
 
 
         const results = this._results.map(result => {
             var className = "searchBox-results-scroll-view-result";
 
-            if (this._selectedResult == result[0]) {
-                className += " searchBox-results-scroll-view-result-selected"
+            if (this._selectedResult === result[0]) {
+                className += " searchBox-results-scroll-view-result-selected";
             }
 
-            if (this._docTypeString == "all" || this._docTypeString == result[0].type) {
+            if (this._docTypeString === "all" || this._docTypeString === result[0].type) {
                 validResults++;
                 return (
                     <div key={result[0][Id]} onClick={isLinkSearch ? () => this.makeLink(result[0]) : () => this.onResultClick(result[0])} className={className}>
@@ -319,25 +313,25 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc
                             {result[1].join(", ")}
                         </div>
                     </div>
-                )
+                );
             }
 
             return null;
-        })
+        });
 
         results.filter(result => result);
 
         return (
             <div style={{ pointerEvents: "all" }} className="searchBox-container">
-                 <div className="searchBox-bar" >
-                 {isLinkSearch ? (null) : <select name="type" id="searchBox-type" className="searchBox-type" onChange={this.onSelectChange}>
+                <div className="searchBox-bar" >
+                    {isLinkSearch ? (null) : <select name="type" id="searchBox-type" className="searchBox-type" onChange={this.onSelectChange}>
                         {this.selectOptions}
                     </select>}
-                    <input defaultValue={""} autoComplete="off" onChange={this.onInputChange} type="text" placeholder="Search..." id="search-input" className="searchBox-input" style={{width: isLinkSearch ? "100%" : undefined, borderRadius: isLinkSearch ? "5px" : undefined}} ref={this._inputRef} />
+                    <input defaultValue={""} autoComplete="off" onChange={this.onInputChange} type="text" placeholder="Search..." id="search-input" className="searchBox-input" style={{ width: isLinkSearch ? "100%" : undefined, borderRadius: isLinkSearch ? "5px" : undefined }} ref={this._inputRef} />
                 </div >
                 <div className="searchBox-results-container">
                     <div className="searchBox-results-count">
-                        {`${validResults}` + " result" + (validResults == 1 ? "" : "s")}
+                        {`${validResults}` + " result" + (validResults === 1 ? "" : "s")}
                     </div>
                     <div className="searchBox-results-scroll-view">
                         {results}
-- 
cgit v1.2.3-70-g09d2


From 4e251670efd5072238758e1e06f61d7d79aaced2 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 26 Aug 2021 09:03:17 -0400
Subject: from last

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

(limited to 'src/client/views/pdf/AnchorMenu.tsx')

diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 95e318738..17979ef4b 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -156,7 +156,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
                         <FontAwesomeIcon icon="link" size="lg" />
                     </button>
                 </Tooltip>,
-                <LinkPopup showPopup={this._showLinkPopup} linkFrom={this.onMakeAnchor} />
+                <LinkPopup key="popup" showPopup={this._showLinkPopup} linkFrom={this.onMakeAnchor} />
             ] : [
                 <Tooltip key="trash" title={<div className="dash-tooltip">{"Remove Link Anchor"}</div>}>
                     <button className="antimodeMenu-button" onPointerDown={this.Delete}>
-- 
cgit v1.2.3-70-g09d2

