From 15615e6789ae4eb121a6d0ac6ba607e74369bd6e Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 9 Sep 2020 16:57:25 -0400
Subject: several pdf fixes - clipping link anchors to bounds of container. 
 pdf box titles don't change based on zoom anymore.   can't zoom a pdf if not
 selected.  fixed scrolling of previews without scrolling targets.

---
 .../CollectionFreeFormLinkView.tsx                 | 30 +++++++++++++++++-----
 1 file changed, 24 insertions(+), 6 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 3a2979696..417b4c1ff 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -103,8 +103,24 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
             //         showLinks={action(() => { })}
             //     />, { x: 300, y: 300 });
         });
+
+
     }
 
+    visibleY = (el: any) => {
+        var rect = el.getBoundingClientRect(), top = rect.top, height = rect.height,
+            el = el.parentNode;
+        do {
+            rect = el.getBoundingClientRect();
+            if (top <= rect.bottom === false && getComputedStyle(el).overflow === "hidden") return rect.bottom;
+            // Check if the element is out of view due to a container scrolling
+            if ((top + height) <= rect.top && getComputedStyle(el).overflow === "hidden") return rect.top;
+            el = el.parentNode;
+        } while (el != document.body);
+        // Check its within the document viewport
+        return top;//top <= document.documentElement.clientHeight && getComputedStyle(document.documentElement).overflow === "hidden";
+    };
+
     @computed get renderData() {
         this._start;
         if (SnappingManager.GetIsDragging() || !this.props.A.ContentDiv || !this.props.B.ContentDiv || !this.props.LinkDocs.length) {
@@ -115,16 +131,18 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         const bcont = this.props.B.ContentDiv.getElementsByClassName("linkAnchorBox-cont");
         const a = (acont.length ? acont[0] : this.props.A.ContentDiv).getBoundingClientRect();
         const b = (bcont.length ? bcont[0] : this.props.B.ContentDiv).getBoundingClientRect();
-        const apt = Utils.closestPtBetweenRectangles(a.left, a.top, a.width, a.height,
-            b.left, b.top, b.width, b.height,
+        const atop = this.visibleY(this.props.A.ContentDiv);
+        const btop = this.visibleY(this.props.B.ContentDiv);
+        const apt = Utils.closestPtBetweenRectangles(a.left, atop, a.width, a.height,
+            b.left, btop, b.width, b.height,
             a.left + a.width / 2, a.top + a.height / 2);
-        const bpt = Utils.closestPtBetweenRectangles(b.left, b.top, b.width, b.height,
-            a.left, a.top, a.width, a.height,
+        const bpt = Utils.closestPtBetweenRectangles(b.left, btop, b.width, b.height,
+            a.left, atop, a.width, a.height,
             apt.point.x, apt.point.y);
         const pt1 = [apt.point.x, apt.point.y];
         const pt2 = [bpt.point.x, bpt.point.y];
-        const pt1vec = [pt1[0] - (a.left + a.width / 2), pt1[1] - (a.top + a.height / 2)];
-        const pt2vec = [pt2[0] - (b.left + b.width / 2), pt2[1] - (b.top + b.height / 2)];
+        const pt1vec = [pt1[0] - (a.left + a.width / 2), pt1[1] - (atop + a.height / 2)];
+        const pt2vec = [pt2[0] - (b.left + b.width / 2), pt2[1] - (btop + b.height / 2)];
         const pt1len = Math.sqrt((pt1vec[0] * pt1vec[0]) + (pt1vec[1] * pt1vec[1]));
         const pt2len = Math.sqrt((pt2vec[0] * pt2vec[0]) + (pt2vec[1] * pt2vec[1]));
         const ptlen = Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0]) + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1])) / 2;
-- 
cgit v1.2.3-70-g09d2


From 5a4dad460f611cb8138faf08796dda4763f4daf4 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 9 Sep 2020 23:21:05 -0400
Subject: fixed linkEditor menu to show up in the right place.  fixed linklines
 to attach properly.

---
 .../collectionFreeForm/CollectionFreeFormLinkView.tsx        | 12 +++++++-----
 src/client/views/linking/LinkMenu.tsx                        |  2 +-
 2 files changed, 8 insertions(+), 6 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 417b4c1ff..8bc3cdf1b 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -118,7 +118,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
             el = el.parentNode;
         } while (el != document.body);
         // Check its within the document viewport
-        return top;//top <= document.documentElement.clientHeight && getComputedStyle(document.documentElement).overflow === "hidden";
+        return top; //top <= document.documentElement.clientHeight && getComputedStyle(document.documentElement).overflow === "hidden";
     };
 
     @computed get renderData() {
@@ -129,10 +129,12 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         this.props.A.props.ScreenToLocalTransform().transform(this.props.B.props.ScreenToLocalTransform());
         const acont = this.props.A.ContentDiv.getElementsByClassName("linkAnchorBox-cont");
         const bcont = this.props.B.ContentDiv.getElementsByClassName("linkAnchorBox-cont");
-        const a = (acont.length ? acont[0] : this.props.A.ContentDiv).getBoundingClientRect();
-        const b = (bcont.length ? bcont[0] : this.props.B.ContentDiv).getBoundingClientRect();
-        const atop = this.visibleY(this.props.A.ContentDiv);
-        const btop = this.visibleY(this.props.B.ContentDiv);
+        const adiv = (acont.length ? acont[0] : this.props.A.ContentDiv);
+        const bdiv = (bcont.length ? bcont[0] : this.props.B.ContentDiv);
+        const a = adiv.getBoundingClientRect();
+        const b = bdiv.getBoundingClientRect();
+        const atop = this.visibleY(adiv);
+        const btop = this.visibleY(bdiv);
         const apt = Utils.closestPtBetweenRectangles(a.left, atop, a.width, a.height,
             b.left, btop, b.width, b.height,
             a.left + a.width / 2, a.top + a.height / 2);
diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx
index f5a1ae8e7..3b4912d3d 100644
--- a/src/client/views/linking/LinkMenu.tsx
+++ b/src/client/views/linking/LinkMenu.tsx
@@ -96,7 +96,7 @@ export class LinkMenu extends React.Component<Props> {
                 <div className="linkMenu-list" >
                     {this.renderAllGroups(groups)}
                 </div> :
-                <div className="linkMenu-listEditor" style={{ left: this.position.x, top: this.position.b + 15 }}>
+                <div className="linkMenu-listEditor">
                     <LinkEditor sourceDoc={this.props.docView.props.Document} linkDoc={this._editingLink}
                         showLinks={action(() => this._editingLink = undefined)} />
                 </div>
-- 
cgit v1.2.3-70-g09d2


From 75fa8e7e798566962d88fc3012c41c3179580e39 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 10 Sep 2020 10:59:58 -0400
Subject: fixed following links on text hyperlink to use same code as linkMenu.
  fixed hyperlink delete button

---
 src/client/util/DocumentManager.ts                 |  2 +-
 src/client/util/LinkManager.ts                     |  2 +-
 .../views/collections/CollectionDockingView.tsx    |  2 +-
 .../CollectionFreeFormLinkView.tsx                 |  9 ++--
 src/client/views/linking/LinkEditor.tsx            |  2 +-
 src/client/views/linking/LinkMenuGroup.tsx         |  8 +--
 src/client/views/linking/LinkMenuItem.tsx          | 23 ++++-----
 .../formattedText/FormattedTextBoxComment.tsx      | 59 +++++++---------------
 8 files changed, 42 insertions(+), 65 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx')

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 420b29559..37d639a07 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -109,7 +109,7 @@ export class DocumentManager {
         const pairs = DocumentManager.Instance.DocumentViews.reduce((pairs, dv) => {
             const linksList = DocListCast(dv.props.Document.links);
             pairs.push(...linksList.reduce((pairs, link) => {
-                const linkToDoc = link && LinkManager.Instance.getOppositeAnchor(link, dv.props.Document);
+                const linkToDoc = link && LinkManager.getOppositeAnchor(link, dv.props.Document);
                 linkToDoc && DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => {
                     if (dv.props.Document.type !== DocumentType.LINK || dv.props.LayoutTemplateString !== docView1.props.LayoutTemplateString) {
                         pairs.push({ a: dv, b: docView1, l: link });
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 223f0e7ef..c7c45ec61 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -200,7 +200,7 @@ export class LinkManager {
     // finds the opposite anchor of a given anchor in a link
     //TODO This should probably return undefined if there isn't an opposite anchor
     //TODO This should also await the return value of the anchor so we don't filter out promises
-    public getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc | undefined {
+    public static getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc | undefined {
         const a1 = Cast(linkDoc.anchor1, Doc, null);
         const a2 = Cast(linkDoc.anchor2, Doc, null);
         if (Doc.AreProtosEqual(anchor, a1)) return a2;
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index bed7e9735..d7a134eb3 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -292,7 +292,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
             setTimeout(() => {
                 CollectionDockingView.Instance._ignoreStateChange = JSON.stringify(CollectionDockingView.Instance._goldenLayout.toConfig());
                 this.stateChanged();
-                this._flush!.end();
+                this._flush?.end();
                 this._flush = undefined;
             }, 10);
         }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 8bc3cdf1b..79a540210 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -108,18 +108,19 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
     }
 
     visibleY = (el: any) => {
-        var rect = el.getBoundingClientRect(), top = rect.top, height = rect.height,
-            el = el.parentNode;
+        let rect = el.getBoundingClientRect();
+        const top = rect.top, height = rect.height;
+        var el = el.parentNode;
         do {
             rect = el.getBoundingClientRect();
             if (top <= rect.bottom === false && getComputedStyle(el).overflow === "hidden") return rect.bottom;
             // Check if the element is out of view due to a container scrolling
             if ((top + height) <= rect.top && getComputedStyle(el).overflow === "hidden") return rect.top;
             el = el.parentNode;
-        } while (el != document.body);
+        } while (el !== document.body);
         // Check its within the document viewport
         return top; //top <= document.documentElement.clientHeight && getComputedStyle(document.documentElement).overflow === "hidden";
-    };
+    }
 
     @computed get renderData() {
         this._start;
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index d6c3702d1..3713a1026 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -420,7 +420,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
     }
 
     render() {
-        const destination = LinkManager.Instance.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
+        const destination = LinkManager.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
 
         const groups = [this.props.linkDoc].map(groupDoc => {
             return <LinkGroupEditor key={"gred-" + StrCast(groupDoc.linkRelationship)} linkDoc={this.props.linkDoc}
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx
index 8e09052a3..29e1d921c 100644
--- a/src/client/views/linking/LinkMenuGroup.tsx
+++ b/src/client/views/linking/LinkMenuGroup.tsx
@@ -48,7 +48,7 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
             document.removeEventListener("pointermove", this.onLinkButtonMoved);
             document.removeEventListener("pointerup", this.onLinkButtonUp);
 
-            const targets = this.props.group.map(l => LinkManager.Instance.getOppositeAnchor(l, this.props.sourceDoc)).filter(d => d) as Doc[];
+            const targets = this.props.group.map(l => LinkManager.getOppositeAnchor(l, this.props.sourceDoc)).filter(d => d) as Doc[];
             StartLinkTargetsDrag(this._drag.current, this.props.docView, e.x, e.y, this.props.sourceDoc, targets);
         }
         e.stopPropagation();
@@ -68,10 +68,10 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
     render() {
         const set = new Set<Doc>(this.props.group);
         const groupItems = Array.from(set.keys()).map(linkDoc => {
-            const destination = LinkManager.Instance.getOppositeAnchor(linkDoc, this.props.sourceDoc) ||
-                LinkManager.Instance.getOppositeAnchor(linkDoc, Cast(linkDoc.anchor2, Doc, null).annotationOn === this.props.sourceDoc ? Cast(linkDoc.anchor2, Doc, null) : Cast(linkDoc.anchor1, Doc, null));
+            const destination = LinkManager.getOppositeAnchor(linkDoc, this.props.sourceDoc) ||
+                LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.anchor2, Doc, null).annotationOn === this.props.sourceDoc ? Cast(linkDoc.anchor2, Doc, null) : Cast(linkDoc.anchor1, Doc, null));
             if (destination && this.props.sourceDoc) {
-                return <LinkMenuItem key={destination[Id] + this.props.sourceDoc[Id]}
+                return <LinkMenuItem key={linkDoc[Id]}
                     groupType={this.props.groupType}
                     addDocTab={this.props.addDocTab}
                     docView={this.props.docView}
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 17549e3cf..32fc407f6 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -33,7 +33,7 @@ interface LinkMenuItemProps {
 
 // drag links and drop link targets (aliasing them if needed)
 export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: DocumentView, downX: number, downY: number, sourceDoc: Doc, specificLinks?: Doc[]) {
-    const draggedDocs = (specificLinks ? specificLinks : DocListCast(sourceDoc.links)).map(link => LinkManager.Instance.getOppositeAnchor(link, sourceDoc)).filter(l => l) as Doc[];
+    const draggedDocs = (specificLinks ? specificLinks : DocListCast(sourceDoc.links)).map(link => LinkManager.getOppositeAnchor(link, sourceDoc)).filter(l => l) as Doc[];
 
     if (draggedDocs.length) {
         const moddrag: Doc[] = [];
@@ -142,35 +142,34 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
         DocumentLinksButton.EditLink = undefined;
         LinkDocPreview.LinkInfo = undefined;
         e.preventDefault();
-        ContextMenu.Instance.addItem({ description: "Follow Default Link", event: () => this.followDefault(), icon: "arrow-right" });
+        ContextMenu.Instance.addItem({ description: "Follow Default Link", event: () => LinkMenuItem.followDefault(this.props.linkDoc, this.props.sourceDoc, this.props.destinationDoc, this.props.addDocTab), icon: "arrow-right" });
         ContextMenu.Instance.displayMenu(e.clientX, e.clientY);
     }
 
     @action.bound
-    followDefault() {
+    public static followDefault(linkDoc: Doc, sourceDoc: Doc, destinationDoc: Doc, addDocTab: (doc: Doc, where: string) => void) {
         DocumentLinksButton.EditLink = undefined;
         LinkDocPreview.LinkInfo = undefined;
-        const linkDoc = this.props.linkDoc;
 
-        if (linkDoc.followLinkLocation === "openExternal" && this.props.destinationDoc.type === DocumentType.WEB) {
+        if (linkDoc.followLinkLocation === "openExternal" && destinationDoc.type === DocumentType.WEB) {
             window.open(`${StrCast(linkDoc.annotationUri)}#annotations:${StrCast(linkDoc.annotationId)}`, '_blank');
             return;
         }
 
         if (linkDoc.followLinkLocation && linkDoc.followLinkLocation !== "default") {
-            const annotationOn = this.props.destinationDoc.annotationOn as Doc;
-            this.props.addDocTab(annotationOn instanceof Doc ? annotationOn : this.props.destinationDoc, StrCast(linkDoc.followLinkLocation));
+            const annotationOn = destinationDoc.annotationOn as Doc;
+            addDocTab(annotationOn instanceof Doc ? annotationOn : destinationDoc, StrCast(linkDoc.followLinkLocation));
             if (annotationOn) {
                 setTimeout(() => {
-                    const dv = DocumentManager.Instance.getFirstDocumentView(this.props.destinationDoc);
-                    dv?.props.focus(this.props.destinationDoc, false);
+                    const dv = DocumentManager.Instance.getFirstDocumentView(destinationDoc);
+                    dv?.props.focus(destinationDoc, false);
                 });
             }
         } else {
-            DocumentManager.Instance.FollowLink(this.props.linkDoc, this.props.sourceDoc, doc => this.props.addDocTab(doc, "add:right"), false);
+            DocumentManager.Instance.FollowLink(linkDoc, this.props.sourceDoc, doc => addDocTab(doc, "add:right"), false);
         }
 
-        linkDoc.linksToAnnotation && Hypothesis.scrollToAnnotation(StrCast(this.props.linkDoc.annotationId), this.props.destinationDoc);
+        linkDoc.linksToAnnotation && Hypothesis.scrollToAnnotation(StrCast(linkDoc.annotationId), destinationDoc);
     }
 
     @undoBatch
@@ -250,7 +249,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
                                 <div className="destination-icon-wrapper" >
                                     <FontAwesomeIcon className="destination-icon" icon={destinationIcon} size="sm" /></div>
                                 <p className="linkMenu-destination-title"
-                                    onPointerDown={this.followDefault}>
+                                    onPointerDown={() => LinkMenuItem.followDefault(this.props.linkDoc, this.props.sourceDoc, this.props.destinationDoc, this.props.addDocTab)}>
                                     {this.props.linkDoc.linksToAnnotation && Cast(this.props.destinationDoc.data, WebField)?.url.href === this.props.linkDoc.annotationUri ? "Annotation in" : ""} {title}
                                 </p>
                             </div>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index 6c71f08e7..1982cabab 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -1,28 +1,28 @@
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { Tooltip } from "@material-ui/core";
+import { action } from "mobx";
 import { Mark, ResolvedPos } from "prosemirror-model";
 import { EditorState, Plugin } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
 import * as ReactDOM from 'react-dom';
+import wiki from "wikijs";
 import { Doc, DocCastAsync, Opt } from "../../../../fields/Doc";
 import { Cast, FieldValue, NumCast, StrCast } from "../../../../fields/Types";
-import { emptyFunction, returnEmptyString, returnFalse, Utils, emptyPath, returnZero, returnOne, returnEmptyFilter, returnEmptyDoclist } from "../../../../Utils";
+import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, Utils } from "../../../../Utils";
 import { DocServer } from "../../../DocServer";
-import { DocumentManager } from "../../../util/DocumentManager";
-import { schema } from "./schema_rts";
+import { Docs } from "../../../documents/Documents";
+import { DocumentType } from "../../../documents/DocumentTypes";
+import { LinkManager } from "../../../util/LinkManager";
 import { Transform } from "../../../util/Transform";
+import { undoBatch } from "../../../util/UndoManager";
+import { LinkMenuItem } from "../../linking/LinkMenuItem";
 import { ContentFittingDocumentView } from "../ContentFittingDocumentView";
+import { DocumentLinksButton } from "../DocumentLinksButton";
+import { LinkDocPreview } from "../LinkDocPreview";
 import { FormattedTextBox } from "./FormattedTextBox";
 import './FormattedTextBoxComment.scss';
+import { schema } from "./schema_rts";
 import React = require("react");
-import { Docs } from "../../../documents/Documents";
-import wiki from "wikijs";
-import { DocumentType } from "../../../documents/DocumentTypes";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action } from "mobx";
-import { LinkManager } from "../../../util/LinkManager";
-import { LinkDocPreview } from "../LinkDocPreview";
-import { DocumentLinksButton } from "../DocumentLinksButton";
-import { Tooltip } from "@material-ui/core";
-import { undoBatch } from "../../../util/UndoManager";
 
 export let formattedTextBoxCommentPlugin = new Plugin({
     view(editorView) { return new FormattedTextBoxComment(editorView); }
@@ -98,40 +98,18 @@ export class FormattedTextBoxComment {
                 const textBox = FormattedTextBoxComment.textBox;
                 const linkDoc = FormattedTextBoxComment.linkDoc;
                 if (linkDoc && !keep && textBox) {
-                    FormattedTextBoxComment.linkDoc = undefined;
                     if (linkDoc.author) {
                         if (FormattedTextBoxComment._deleteRef?.contains(e.target as any)) {
                             this.deleteLink();
-                        } else if (FormattedTextBoxComment._followRef && FormattedTextBoxComment._followRef.contains(e.target as any)) {
-                            if (linkDoc.type !== DocumentType.LINK) {
-                                textBox.props.addDocTab(linkDoc, e.ctrlKey ? "add" : "add:right");
-                            } else {
-                                const anchor = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.dataDoc) ?
-                                    Cast(linkDoc.anchor2, Doc) : (Cast(linkDoc.anchor1, Doc))
-                                    || linkDoc);
-                                const target = anchor?.annotationOn ? await DocCastAsync(anchor.annotationOn) : anchor;
-
-                                if (linkDoc.follow) {
-                                    if (linkDoc.follow === "default") {
-                                        DocumentManager.Instance.FollowLink(linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "add:right"), false);
-                                    } else if (linkDoc.follow === "Always open in right tab") {
-                                        if (target) { textBox.props.addDocTab(target, "add:right"); }
-                                    } else if (linkDoc.follow === "Always open in new tab") {
-                                        if (target) { textBox.props.addDocTab(target, "add"); }
-                                    }
-                                } else {
-                                    DocumentManager.Instance.FollowLink(linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "add:right"), false);
-                                }
-                            }
                         } else {
+                            FormattedTextBoxComment.linkDoc = undefined;
                             if (linkDoc.type !== DocumentType.LINK) {
                                 textBox.props.addDocTab(linkDoc, e.ctrlKey ? "add" : "add:right");
                             } else {
-                                DocumentManager.Instance.FollowLink(linkDoc, textBox.props.Document,
-                                    (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "add" : followLinkLocation));
+                                const target = LinkManager.getOppositeAnchor(linkDoc, textBox.dataDoc);
+                                target && LinkMenuItem.followDefault(linkDoc, textBox.dataDoc, target, textBox.props.addDocTab);
                             }
                         }
-
                     }
                 } else if (textBox && (FormattedTextBoxComment.tooltipText as any).href) {
                     textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400, useCors: true }), "add:right");
@@ -146,14 +124,13 @@ export class FormattedTextBoxComment {
     }
 
     @undoBatch
-    @action
-    deleteLink = () => {
+    deleteLink = action(() => {
         FormattedTextBoxComment.linkDoc ? LinkManager.Instance.deleteLink(FormattedTextBoxComment.linkDoc) : null;
         LinkDocPreview.LinkInfo = undefined;
         DocumentLinksButton.EditLink = undefined;
         //FormattedTextBoxComment.tooltipText = undefined;
         FormattedTextBoxComment.Hide();
-    }
+    });
 
     public static Hide() {
         FormattedTextBoxComment.textBox = undefined;
-- 
cgit v1.2.3-70-g09d2


From b97e7dcb31f4f8812d86b9b1944b912b544f3824 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 23 Sep 2020 11:56:35 -0400
Subject: fixed link rendering to be less computationally inefficient

---
 src/client/util/DragManager.ts                                    | 2 +-
 src/client/views/PropertiesButtons.tsx                            | 2 +-
 .../collections/collectionFreeForm/CollectionFreeFormLinkView.tsx | 8 +++++---
 .../collectionFreeForm/CollectionFreeFormLinksView.tsx            | 8 +++-----
 src/client/views/nodes/DocumentView.tsx                           | 5 ++---
 5 files changed, 12 insertions(+), 13 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx')

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 91ffab41d..0169b07fc 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -339,7 +339,6 @@ export namespace DragManager {
             DragManager.Root().appendChild(dragDiv);
         }
         dragLabel.style.display = "";
-        SnappingManager.SetIsDragging(true);
         const scaleXs: number[] = [];
         const scaleYs: number[] = [];
         const xs: number[] = [];
@@ -410,6 +409,7 @@ export namespace DragManager {
         const hideSource = options?.hideSource ? true : false;
         eles.map(ele => ele.parentElement && ele.parentElement?.className === dragData.dragDivName ? (ele.parentElement.hidden = hideSource) : (ele.hidden = hideSource));
 
+        SnappingManager.SetIsDragging(true);
         let lastX = downX;
         let lastY = downY;
         const xFromLeft = downX - elesCont.left;
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 00754c416..462091f63 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -397,7 +397,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
             </div>
         </form>
             {Doc.UserDoc().noviceMode ? (null) : <div onPointerDown={this.editOnClickScript} className="onClickFlyout-editScript"> Edit onClick Script</div>}
-        </div>
+        </div>;
     }
 
     @computed
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 79a540210..011e10b88 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -122,9 +122,9 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         return top; //top <= document.documentElement.clientHeight && getComputedStyle(document.documentElement).overflow === "hidden";
     }
 
-    @computed get renderData() {
-        this._start;
-        if (SnappingManager.GetIsDragging() || !this.props.A.ContentDiv || !this.props.B.ContentDiv || !this.props.LinkDocs.length) {
+    @computed.struct get renderData() {
+        this._start; SnappingManager.GetIsDragging();
+        if (!this.props.A.ContentDiv || !this.props.B.ContentDiv || !this.props.LinkDocs.length) {
             return undefined;
         }
         this.props.A.props.ScreenToLocalTransform().transform(this.props.B.props.ScreenToLocalTransform());
@@ -132,6 +132,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         const bcont = this.props.B.ContentDiv.getElementsByClassName("linkAnchorBox-cont");
         const adiv = (acont.length ? acont[0] : this.props.A.ContentDiv);
         const bdiv = (bcont.length ? bcont[0] : this.props.B.ContentDiv);
+        for (let apdiv = adiv; apdiv; apdiv = apdiv.parentElement as any) if ((apdiv as any).hidden) return;
+        for (let apdiv = bdiv; apdiv; apdiv = apdiv.parentElement as any) if ((apdiv as any).hidden) return;
         const a = adiv.getBoundingClientRect();
         const b = bdiv.getBoundingClientRect();
         const atop = this.visibleY(adiv);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 1a2421bfd..6a1a41ca7 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -1,4 +1,4 @@
-import { computed } from "mobx";
+import { computed, trace } from "mobx";
 import { observer } from "mobx-react";
 import { Doc } from "../../../../fields/Doc";
 import { Id } from "../../../../fields/FieldSymbols";
@@ -10,12 +10,10 @@ import React = require("react");
 import { Utils, emptyFunction } from "../../../../Utils";
 import { DocumentType } from "../../../documents/DocumentTypes";
 import { SnappingManager } from "../../../util/SnappingManager";
-import { Cast } from "../../../../fields/Types";
 
 @observer
 export class CollectionFreeFormLinksView extends React.Component {
-    @computed
-    get uniqueConnections() {
+    @computed get uniqueConnections() {
         const connections = DocumentManager.Instance.LinkedDocumentViews.reduce((drawnPairs, connection) => {
             if (!drawnPairs.reduce((found, drawnPair) => {
                 const match1 = (connection.a === drawnPair.a && connection.b === drawnPair.b);
@@ -37,7 +35,7 @@ export class CollectionFreeFormLinksView extends React.Component {
     }
 
     render() {
-        return SnappingManager.GetIsDragging() ? (null) : <div className="collectionfreeformlinksview-container">
+        return <div className="collectionfreeformlinksview-container">
             <svg className="collectionfreeformlinksview-svgCanvas">
                 {this.uniqueConnections}
             </svg>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3d3599476..32c6fce36 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -208,7 +208,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         // this._mainCont.current && (this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this)));
 
         if (!BoolCast(this.rootDoc.dontRegisterView, this.props.dontRegisterView)) {
-            DocumentManager.Instance.DocumentViews.push(this);
+            DocumentManager.Instance.AddView(this);
         }
     }
 
@@ -234,8 +234,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         this._holdDisposer?.();
         Doc.UnBrushDoc(this.props.Document);
         if (!this.props.dontRegisterView) {
-            const index = DocumentManager.Instance.DocumentViews.indexOf(this);
-            index !== -1 && DocumentManager.Instance.DocumentViews.splice(index, 1);
+            DocumentManager.Instance.RemoveView(this);
         }
     }
 
-- 
cgit v1.2.3-70-g09d2


From 5a9653ef22ba81226f1bc7fe4de14d3edced73e0 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 30 Sep 2020 18:53:14 -0400
Subject: added restriction of link lines to stay mostly in their container
 intstead of dangling in space.

---
 .../CollectionFreeFormLinkView.tsx                 | 37 ++++++++++++++++------
 1 file changed, 27 insertions(+), 10 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 011e10b88..8e01d9357 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -26,7 +26,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         this._anchorDisposer?.();
     }
     @action
-    timeout = () => (Date.now() < this._start++ + 1000) && setTimeout(this.timeout, 25)
+    timeout = action(() => (Date.now() < this._start++ + 1000) && (this._timeout = setTimeout(this.timeout, 25)))
     componentDidMount() {
         this._anchorDisposer = reaction(() => [this.props.A.props.ScreenToLocalTransform(), this.props.B.props.ScreenToLocalTransform(), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document)],
             action(() => {
@@ -113,7 +113,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         var el = el.parentNode;
         do {
             rect = el.getBoundingClientRect();
-            if (top <= rect.bottom === false && getComputedStyle(el).overflow === "hidden") return rect.bottom;
+            if (top <= rect.right === false && getComputedStyle(el).overflow === "hidden") return rect.bottom;
             // Check if the element is out of view due to a container scrolling
             if ((top + height) <= rect.top && getComputedStyle(el).overflow === "hidden") return rect.top;
             el = el.parentNode;
@@ -121,6 +121,20 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         // Check its within the document viewport
         return top; //top <= document.documentElement.clientHeight && getComputedStyle(document.documentElement).overflow === "hidden";
     }
+    visibleX = (el: any) => {
+        let rect = el.getBoundingClientRect();
+        const left = rect.left, width = rect.width;
+        var el = el.parentNode;
+        do {
+            rect = el.getBoundingClientRect();
+            if (left <= rect.right === false && getComputedStyle(el).overflow === "hidden") return rect.right;
+            // Check if the element is out of view due to a container scrolling
+            if ((left + width) <= rect.left && getComputedStyle(el).overflow === "hidden") return rect.left;
+            el = el.parentNode;
+        } while (el !== document.body);
+        // Check its within the document viewport
+        return left; //top <= document.documentElement.clientHeight && getComputedStyle(document.documentElement).overflow === "hidden";
+    }
 
     @computed.struct get renderData() {
         this._start; SnappingManager.GetIsDragging();
@@ -138,16 +152,18 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         const b = bdiv.getBoundingClientRect();
         const atop = this.visibleY(adiv);
         const btop = this.visibleY(bdiv);
-        const apt = Utils.closestPtBetweenRectangles(a.left, atop, a.width, a.height,
-            b.left, btop, b.width, b.height,
+        const aleft = this.visibleX(adiv);
+        const bleft = this.visibleX(bdiv);
+        const apt = Utils.closestPtBetweenRectangles(aleft, atop, a.width, a.height,
+            bleft, btop, b.width, b.height,
             a.left + a.width / 2, a.top + a.height / 2);
-        const bpt = Utils.closestPtBetweenRectangles(b.left, btop, b.width, b.height,
-            a.left, atop, a.width, a.height,
+        const bpt = Utils.closestPtBetweenRectangles(bleft, btop, b.width, b.height,
+            aleft, atop, a.width, a.height,
             apt.point.x, apt.point.y);
         const pt1 = [apt.point.x, apt.point.y];
         const pt2 = [bpt.point.x, bpt.point.y];
-        const pt1vec = [pt1[0] - (a.left + a.width / 2), pt1[1] - (atop + a.height / 2)];
-        const pt2vec = [pt2[0] - (b.left + b.width / 2), pt2[1] - (btop + b.height / 2)];
+        const pt1vec = [pt1[0] - (aleft + a.width / 2), pt1[1] - (atop + a.height / 2)];
+        const pt2vec = [pt2[0] - (bleft + b.width / 2), pt2[1] - (btop + b.height / 2)];
         const pt1len = Math.sqrt((pt1vec[0] * pt1vec[0]) + (pt1vec[1] * pt1vec[1]));
         const pt2len = Math.sqrt((pt2vec[0] * pt2vec[0]) + (pt2vec[1] * pt2vec[1]));
         const ptlen = Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0]) + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1])) / 2;
@@ -155,6 +171,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         const pt2norm = [pt2vec[0] / pt2len * ptlen, pt2vec[1] / pt2len * ptlen];
         const aActive = this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document);
         const bActive = this.props.B.isSelected() || Doc.IsBrushed(this.props.B.props.Document);
+        if (aleft !== a.left || atop !== a.top || bleft !== b.left || btop !== b.top) return { a, b, pt1norm: [0, 0], pt2norm: [0, 0], aActive, bActive, textX: undefined, textY: undefined, pt1, pt2 };
 
         const textX = (Math.min(pt1[0], pt2[0]) + Math.max(pt1[0], pt2[0])) / 2 + NumCast(this.props.LinkDocs[0].linkOffsetX);
         const textY = (pt1[1] + pt2[1]) / 2 + NumCast(this.props.LinkDocs[0].linkOffsetY);
@@ -167,9 +184,9 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         return !a.width || !b.width || ((!this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<>
             <path className="collectionfreeformlinkview-linkLine" style={{ opacity: this._opacity, strokeDasharray: "2 2" }}
                 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]}`} />
-            <text className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown} >
+            {textX === undefined ? (null) : <text className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown} >
                 {StrCast(this.props.LinkDocs[0].description)}
-            </text>
+            </text>}
         </>);
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From be8940e0fea4cf2082c444d54173ee7482e8a327 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 30 Sep 2020 23:17:37 -0400
Subject: fixed linking to text hyperlinks from PDFs

---
 src/client/views/GlobalKeyHandler.ts                               | 6 +++---
 .../collections/collectionFreeForm/CollectionFreeFormLinkView.tsx  | 2 +-
 src/client/views/nodes/formattedText/FormattedTextBox.tsx          | 7 ++++---
 3 files changed, 8 insertions(+), 7 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx')

diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 9ca1dbf11..1b2395423 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -52,7 +52,7 @@ export class KeyManager {
 
     public unhandle = action((e: KeyboardEvent) => {
         if (e.key.toLowerCase() === "shift") KeyManager.Instance.ShiftPressed = false;
-    })
+    });
 
     public handle = action(async (e: KeyboardEvent) => {
         if (e.key.toLowerCase() === "shift") KeyManager.Instance.ShiftPressed = true;
@@ -75,7 +75,7 @@ export class KeyManager {
 
         control.stopPropagation && e.stopPropagation();
         control.preventDefault && e.preventDefault();
-    })
+    });
 
     private handleGreedy = action((keyname: string) => {
         switch (keyname) {
@@ -149,7 +149,7 @@ export class KeyManager {
             stopPropagation: stopPropagation,
             preventDefault: preventDefault
         };
-    })
+    });
 
     private alt = action((keyname: string) => {
         const stopPropagation = true;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 8e01d9357..9dcfde7f9 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -26,7 +26,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         this._anchorDisposer?.();
     }
     @action
-    timeout = action(() => (Date.now() < this._start++ + 1000) && (this._timeout = setTimeout(this.timeout, 25)))
+    timeout = action(() => (Date.now() < this._start++ + 1000) && (this._timeout = setTimeout(this.timeout, 25)));
     componentDidMount() {
         this._anchorDisposer = reaction(() => [this.props.A.props.ScreenToLocalTransform(), this.props.B.props.ScreenToLocalTransform(), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document)],
             action(() => {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 15e35ce72..a998386d8 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -60,6 +60,7 @@ import React = require("react");
 import { DocumentManager } from '../../../util/DocumentManager';
 import { CollectionStackingView } from '../../collections/CollectionStackingView';
 import { CollectionViewType } from '../../collections/CollectionView';
+import { SnappingManager } from '../../../util/SnappingManager';
 
 export interface FormattedTextBoxProps {
     makeLink?: () => Opt<Doc>;  // bcz: hack: notifies the text document when the container has made a link.  allows the text doc to react and setup a hyeprlink for any selected text
@@ -1596,7 +1597,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         const active = this.active();
         const scale = this.props.hideOnLeave ? 1 : this.props.ContentScaling() * NumCast(this.layoutDoc._viewScale, 1);
         const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : "";
-        const interactive = Doc.GetSelectedTool() === InkTool.None && !this.layoutDoc._isBackground;
+        const interactive = (Doc.GetSelectedTool() === InkTool.None || SnappingManager.GetIsDragging()) && !this.layoutDoc._isBackground;
         selected && setTimeout(() => this._editorView && RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this.props)); // need to make sure that we update a text box that is selected after updating the one that was deselected
         if (!selected && FormattedTextBoxComment.textBox === this) { FormattedTextBoxComment.Hide(); }
         const minimal = this.props.ignoreAutoHeight;
@@ -1646,13 +1647,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     onDoubleClick={this.onDoubleClick}
                 >
                     <div className={`formattedTextBox-outer`} ref={this._scrollRef}
-                        style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, pointerEvents: !active ? "none" : undefined }}
+                        style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, pointerEvents: !active && !SnappingManager.GetIsDragging() ? "none" : undefined }}
                         onScroll={this.onscrolled} onDrop={this.ondrop} >
                         <div className={minimal ? "formattedTextBox-minimal" : `formattedTextBox-inner${rounded}${selclass}`} ref={this.createDropTarget}
                             style={{
                                 overflow: this.layoutDoc._singleLine ? "hidden" : undefined,
                                 padding: this.layoutDoc._textBoxPadding ? StrCast(this.layoutDoc._textBoxPadding) : `${padding}px`,
-                                pointerEvents: !active ? ((this.layoutDoc.isLinkButton || this.props.onClick) ? "none" : undefined) : undefined
+                                pointerEvents: !active && !SnappingManager.GetIsDragging() ? ((this.layoutDoc.isLinkButton || this.props.onClick) ? "none" : undefined) : undefined
                             }}
                         />
                     </div>
-- 
cgit v1.2.3-70-g09d2

