From 2c3264bca271af170b620cfc44ecdfafb77aacc0 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 28 Mar 2022 12:20:07 -0400
Subject: enabled dragging documents onto tab bar without shift.  modified link
 pivot document to automatically update when links are added and be a stacking
 view

---
 src/client/views/nodes/DocumentLinksButton.tsx | 35 ++++++++------------------
 1 file changed, 11 insertions(+), 24 deletions(-)

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

diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 7e6ca4248..804e82856 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -2,9 +2,10 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { Tooltip } from "@material-ui/core";
 import { action, computed, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, DocListCast, DocListCastAsync, Opt, WidthSym } from "../../../fields/Doc";
+import { Doc, Opt } from "../../../fields/Doc";
 import { Id } from "../../../fields/FieldSymbols";
-import { Cast, StrCast } from "../../../fields/Types";
+import { ScriptField } from "../../../fields/ScriptField";
+import { StrCast } from "../../../fields/Types";
 import { TraceMobx } from "../../../fields/util";
 import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../../Utils";
 import { DocServer } from "../../DocServer";
@@ -20,7 +21,6 @@ import { DocumentView } from "./DocumentView";
 import { LinkDescriptionPopup } from "./LinkDescriptionPopup";
 import { TaskCompletionBox } from "./TaskCompletedBox";
 import React = require("react");
-import { Transform } from "../../util/Transform";
 
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
@@ -72,31 +72,18 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
     onLinkMenuOpen = (e: React.PointerEvent): void => {
         setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, action((e, doubleTap) => {
             if (doubleTap) {
-                const rootDoc = this.props.View.rootDoc;
-                const docid = Doc.CurrentUserEmail + Doc.GetProto(rootDoc)[Id] + "-pivotish";
-                DocServer.GetRefField(docid).then(async docx => {
+                const linkSource = this.props.View.rootDoc;
+                const docid = Doc.CurrentUserEmail + Doc.GetProto(linkSource)[Id] + "-pivotish";
+                DocServer.GetRefField(docid).then(docx => {
                     const rootAlias = () => {
-                        const rootAlias = Doc.MakeAlias(rootDoc);
+                        const rootAlias = Doc.MakeAlias(linkSource);
                         rootAlias.x = rootAlias.y = 0;
                         return rootAlias;
                     };
-                    let wid = rootDoc[WidthSym]();
-                    const target = ((docx instanceof Doc) && docx) || Docs.Create.FreeformDocument([rootAlias()], { title: this.props.View.Document.title + "-pivot", _width: 500, _height: 500, }, docid);
-                    const docs = await DocListCastAsync(Doc.GetProto(target).data);
-                    if (!target.pivotFocusish) (Doc.GetProto(target).pivotFocusish = target);
-                    DocListCast(rootDoc.links).forEach(link => {
-                        const other = LinkManager.getOppositeAnchor(link, rootDoc);
-                        const otherdoc = !other ? undefined : other.annotationOn ? Cast(other.annotationOn, Doc, null) : other;
-                        if (otherdoc && !docs?.some(d => Doc.AreProtosEqual(d, otherdoc))) {
-                            const alias = Doc.MakeAlias(otherdoc);
-                            alias.x = wid;
-                            alias.y = 0;
-                            alias._lockedPosition = false;
-                            wid += otherdoc[WidthSym]();
-                            Doc.AddDocToList(Doc.GetProto(target), "data", alias);
-                        }
-                    });
-                    LightboxView.SetLightboxDoc(target);
+                    const linkCollection = ((docx instanceof Doc) && docx) || Docs.Create.StackingDocument([/*rootAlias()*/], { title: this.props.View.Document.title + "-pivot", _width: 500, _height: 500, }, docid);
+                    linkCollection.linkSource = linkSource;
+                    if (!linkCollection.reactionScript) linkCollection.reactionScript = ScriptField.MakeScript("updateLinkCollection(self)");
+                    LightboxView.SetLightboxDoc(linkCollection);
                 });
             }
             else DocumentLinksButton.LinkEditorDocView = this.props.View;
-- 
cgit v1.2.3-70-g09d2


From cc4a500d6d3c941d139e6c07dbf76c4eed9c3280 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 29 Mar 2022 10:58:31 -0400
Subject: added a backlinks property category.  fixed context property category
 to update without using search.  fixed double tap on links button to always
 show linkpivot doc.  fixed dragging docs to a tab to not switch to tab
 dragging mode.

---
 .../views/PropertiesDocBacklinksSelector.tsx       | 46 ++++++++++++++++++++++
 src/client/views/PropertiesDocContextSelector.tsx  | 34 ++++++----------
 src/client/views/PropertiesView.tsx                | 26 +++++++++++-
 .../views/collections/CollectionDockingView.scss   |  4 +-
 src/client/views/nodes/DocumentLinksButton.tsx     | 22 ++---------
 src/client/views/nodes/DocumentView.tsx            | 17 ++++++++
 6 files changed, 104 insertions(+), 45 deletions(-)
 create mode 100644 src/client/views/PropertiesDocBacklinksSelector.tsx

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

diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx
new file mode 100644
index 000000000..5ffa93961
--- /dev/null
+++ b/src/client/views/PropertiesDocBacklinksSelector.tsx
@@ -0,0 +1,46 @@
+import { computed } from "mobx";
+import { observer } from "mobx-react";
+import * as React from "react";
+import { Doc, DocListCast } from "../../fields/Doc";
+import { Id } from "../../fields/FieldSymbols";
+import { Cast, NumCast, StrCast } from "../../fields/Types";
+import { LinkManager } from "../util/LinkManager";
+import { CollectionDockingView } from "./collections/CollectionDockingView";
+import { CollectionViewType } from "./collections/CollectionView";
+import './PropertiesDocContextSelector.scss';
+
+type PropertiesDocBacklinksSelectorProps = {
+    Document: Doc,
+    Stack?: any,
+    hideTitle?: boolean,
+    addDocTab(doc: Doc, location: string): void
+};
+
+@observer
+export class PropertiesDocBacklinksSelector extends React.Component<PropertiesDocBacklinksSelectorProps> {
+    @computed get _docs() {
+        const linkSource = this.props.Document;
+        const links = DocListCast(linkSource.links);
+        const collectedLinks = [] as Doc[];
+        links.map(link => {
+            const other = LinkManager.getOppositeAnchor(link, linkSource);
+            const otherdoc = !other ? undefined : other.annotationOn ? Cast(other.annotationOn, Doc, null) : other;
+            if (otherdoc && !collectedLinks.some(d => Doc.AreProtosEqual(d, otherdoc))) {
+                collectedLinks.push(otherdoc);
+            }
+        });
+        return collectedLinks;
+    }
+
+    getOnClick = (col: Doc) => {
+        col = Doc.IsPrototype(col) ? Doc.MakeDelegate(col) : col;
+        this.props.addDocTab(col, "add:right");
+    }
+
+    render() {
+        return <div>
+            {this.props.hideTitle ? (null) : <p key="contexts">Contexts:</p>}
+            {this._docs.map(doc => <p key={doc[Id]}><a onClick={() => this.getOnClick(doc)}>{StrCast(doc.title)}</a></p>)}
+        </div>;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index 427748fe7..45a8b6bf6 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -1,13 +1,12 @@
-import { IReactionDisposer, observable, reaction, runInAction } from "mobx";
+import { computed } from "mobx";
 import { observer } from "mobx-react";
 import * as React from "react";
-import { Doc } from "../../fields/Doc";
+import { Doc, DocListCast } from "../../fields/Doc";
 import { Id } from "../../fields/FieldSymbols";
-import { NumCast, StrCast } from "../../fields/Types";
-import { CollectionViewType } from "./collections/CollectionView";
+import { Cast, NumCast, StrCast } from "../../fields/Types";
 import { CollectionDockingView } from "./collections/CollectionDockingView";
+import { CollectionViewType } from "./collections/CollectionView";
 import './PropertiesDocContextSelector.scss';
-import { SearchUtil } from "../util/SearchUtil";
 
 type PropertiesDocContextSelectorProps = {
     Document: Doc,
@@ -18,24 +17,15 @@ type PropertiesDocContextSelectorProps = {
 
 @observer
 export class PropertiesDocContextSelector extends React.Component<PropertiesDocContextSelectorProps> {
-    @observable private _docs: { col: Doc, target: Doc }[] = [];
-    @observable private _otherDocs: { col: Doc, target: Doc }[] = [];
-    _reaction: IReactionDisposer | undefined;
-
-    componentDidMount() { this._reaction = reaction(() => this.props.Document, () => this.fetchDocuments(), { fireImmediately: true }); }
-    componentWillUnmount() { this._reaction?.(); }
-    async fetchDocuments() {
-        const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document);
-        const containerProtoSets = await Promise.all(aliases.map(async alias => ((await SearchUtil.Search("", true, { fq: `data_l:"${alias[Id]}"` })).docs)));
-        const containerProtos = containerProtoSets.reduce((p, set) => { set.map(s => p.add(s)); return p; }, new Set<Doc>());
-        const containerSets = await Promise.all(Array.from(containerProtos.keys()).map(async container => SearchUtil.GetAliasesOfDocument(container)));
+    @computed get _docs() {
+        const target = this.props.Document;
+        const aliases = DocListCast(target.aliases);
+        const containerProtos = aliases.filter(alias => alias.context).reduce((set, alias) => set.add(Cast(alias.context, Doc, null)), new Set<Doc>());
+        const containerSets = Array.from(containerProtos.keys()).map(container => DocListCast(container.aliases));
         const containers = containerSets.reduce((p, set) => { set.map(s => p.add(s)); return p; }, new Set<Doc>());
-        const doclayoutSets = await Promise.all(Array.from(containers.keys()).map(async (dp) => SearchUtil.GetAliasesOfDocument(dp)));
+        const doclayoutSets = Array.from(containers.keys()).map(dp => DocListCast(dp.aliases));
         const doclayouts = Array.from(doclayoutSets.reduce((p, set) => { set.map(s => p.add(s)); return p; }, new Set<Doc>()).keys());
-        runInAction(() => {
-            this._docs = doclayouts.filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance.props.Document)).filter(doc => !Doc.IsSystem(doc)).map(doc => ({ col: doc, target: this.props.Document }));
-            this._otherDocs = [];
-        });
+        return doclayouts.filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance.props.Document)).filter(doc => !Doc.IsSystem(doc)).map(doc => ({ col: doc, target }));
     }
 
     getOnClick = (col: Doc, target: Doc) => {
@@ -51,8 +41,6 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
         return <div>
             {this.props.hideTitle ? (null) : <p key="contexts">Contexts:</p>}
             {this._docs.map(doc => <p key={doc.col[Id] + doc.target[Id]}><a onClick={() => this.getOnClick(doc.col, doc.target)}>{StrCast(doc.col.title)}</a></p>)}
-            {this._otherDocs.length ? <hr key="hr" /> : null}
-            {this._otherDocs.map(doc => <p key={"p" + doc.col[Id] + doc.target[Id]}><a onClick={() => this.getOnClick(doc.col, doc.target)}>{StrCast(doc.col.title)}</a></p>)}
         </div>;
     }
 }
\ No newline at end of file
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 47a5cd07e..92b52ed5b 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -34,6 +34,7 @@ import "./PropertiesView.scss";
 import { DefaultStyleProvider } from "./StyleProvider";
 import { PresBox } from "./nodes/trails";
 import { IconLookup } from "@fortawesome/fontawesome-svg-core";
+import { PropertiesDocBacklinksSelector } from "./PropertiesDocBacklinksSelector";
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -72,6 +73,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     @observable openFields: boolean = true;
     @observable openLayout: boolean = false;
     @observable openContexts: boolean = true;
+    @observable openBacklinks: boolean = true;
     @observable openAppearance: boolean = true;
     @observable openTransform: boolean = true;
     @observable openFilters: boolean = true; // should be false
@@ -280,6 +282,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return !this.selectedDoc ? (null) : <PropertiesDocContextSelector Document={this.selectedDoc} hideTitle={true} addDocTab={(doc, where) => CollectionDockingView.AddSplit(doc, "right")} />;
     }
 
+    @computed get backlinks() {
+        return !this.selectedDoc ? (null) : <PropertiesDocBacklinksSelector Document={this.selectedDoc} hideTitle={true} addDocTab={(doc, where) => CollectionDockingView.AddSplit(doc, "right")} />;
+    }
+
     @computed get layoutPreview() {
         if (SelectionManager.Views().length > 1) {
             return "-- multiple selected --";
@@ -1080,6 +1086,20 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         </div>;
     }
 
+    @computed get backlinksSubMenu() {
+        return <div className="propertiesView-contexts">
+            <div className="propertiesView-contexts-title"
+                onPointerDown={action(() => this.openBacklinks = !this.openBacklinks)}
+                style={{ backgroundColor: this.openBacklinks ? "black" : "" }}>
+                Backlinks
+                <div className="propertiesView-contexts-title-icon">
+                    <FontAwesomeIcon icon={this.openBacklinks ? "caret-down" : "caret-right"} size="lg" color="white" />
+                </div>
+            </div>
+            {this.openBacklinks ? <div className="propertiesView-contexts-content"  >{this.backlinks}</div> : null}
+        </div>;
+    }
+
     @computed get layoutSubMenu() {
         return <div className="propertiesView-layout">
             <div className="propertiesView-layout-title"
@@ -1331,6 +1351,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         {this.editableTitle}
                     </div>
 
+                    {this.contextsSubMenu}
+
+                    {this.backlinksSubMenu}
+
                     {this.inkSubMenu}
 
                     {this.optionsSubMenu}
@@ -1341,8 +1365,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
                     {isNovice ? null : this.fieldsSubMenu}
 
-                    {isNovice ? null : this.contextsSubMenu}
-
                     {isNovice ? null : this.layoutSubMenu}
                 </div>;
             }
diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss
index b2ee33807..21045a20e 100644
--- a/src/client/views/collections/CollectionDockingView.scss
+++ b/src/client/views/collections/CollectionDockingView.scss
@@ -39,8 +39,8 @@
     padding: 0px;
     opacity: 0.7;
     box-shadow: none;
-    height: 24px;
-    // border-bottom: 1px black;
+    height: 25px;
+    border-bottom: black solid;
 
     .collectionDockingView-gear {
         display: none;
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 804e82856..6d96a9ab6 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -1,6 +1,6 @@
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { Tooltip } from "@material-ui/core";
-import { action, computed, observable, runInAction } from "mobx";
+import { action, computed, observable, runInAction, trace } from "mobx";
 import { observer } from "mobx-react";
 import { Doc, Opt } from "../../../fields/Doc";
 import { Id } from "../../../fields/FieldSymbols";
@@ -72,22 +72,10 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
     onLinkMenuOpen = (e: React.PointerEvent): void => {
         setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, action((e, doubleTap) => {
             if (doubleTap) {
-                const linkSource = this.props.View.rootDoc;
-                const docid = Doc.CurrentUserEmail + Doc.GetProto(linkSource)[Id] + "-pivotish";
-                DocServer.GetRefField(docid).then(docx => {
-                    const rootAlias = () => {
-                        const rootAlias = Doc.MakeAlias(linkSource);
-                        rootAlias.x = rootAlias.y = 0;
-                        return rootAlias;
-                    };
-                    const linkCollection = ((docx instanceof Doc) && docx) || Docs.Create.StackingDocument([/*rootAlias()*/], { title: this.props.View.Document.title + "-pivot", _width: 500, _height: 500, }, docid);
-                    linkCollection.linkSource = linkSource;
-                    if (!linkCollection.reactionScript) linkCollection.reactionScript = ScriptField.MakeScript("updateLinkCollection(self)");
-                    LightboxView.SetLightboxDoc(linkCollection);
-                });
+                DocumentView.showBackLinks(this.props.View.rootDoc);
             }
-            else DocumentLinksButton.LinkEditorDocView = this.props.View;
-        }));
+        }), undefined, undefined,
+            action(() => DocumentLinksButton.LinkEditorDocView = this.props.View));
     }
 
     @undoBatch
@@ -119,8 +107,6 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
                 DocumentLinksButton.StartLinkView = this.props.View;
             }
             //action(() => Doc.BrushDoc(this.props.View.Document));
-        } else if (!this.props.InMenu) {
-            DocumentLinksButton.LinkEditorDocView = this.props.View;
         }
     }
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 955698190..c2d2ef13b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -49,6 +49,7 @@ import { RadialMenu } from './RadialMenu';
 import { ScriptingBox } from "./ScriptingBox";
 import { PresBox } from './trails/PresBox';
 import React = require("react");
+import { DocServer } from "../../DocServer";
 const { Howl } = require('howler');
 
 interface Window {
@@ -225,6 +226,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @computed get onPointerDownHandler() { return this.props.onPointerDown?.() ?? ScriptCast(this.Document.onPointerDown); }
     @computed get onPointerUpHandler() { return this.props.onPointerUp?.() ?? ScriptCast(this.Document.onPointerUp); }
 
+
     componentWillUnmount() { this.cleanupHandlers(true); }
     componentDidMount() { this.setupHandlers(); }
     //componentDidUpdate() { this.setupHandlers(); }
@@ -1144,6 +1146,21 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     public ContentRef = React.createRef<HTMLDivElement>();
     private _disposers: { [name: string]: IReactionDisposer } = {};
 
+    public static showBackLinks(linkSource: Doc) {
+        const docid = Doc.CurrentUserEmail + Doc.GetProto(linkSource)[Id] + "-pivotish";
+        DocServer.GetRefField(docid).then(docx => {
+            const rootAlias = () => {
+                const rootAlias = Doc.MakeAlias(linkSource);
+                rootAlias.x = rootAlias.y = 0;
+                return rootAlias;
+            };
+            const linkCollection = ((docx instanceof Doc) && docx) || Docs.Create.StackingDocument([/*rootAlias()*/], { title: linkSource.title + "-pivot", _width: 500, _height: 500, }, docid);
+            linkCollection.linkSource = linkSource;
+            if (!linkCollection.reactionScript) linkCollection.reactionScript = ScriptField.MakeScript("updateLinkCollection(self)");
+            LightboxView.SetLightboxDoc(linkCollection);
+        });
+    }
+
     @observable public docView: DocumentViewInternal | undefined | null;
 
     get Document() { return this.props.Document; }
-- 
cgit v1.2.3-70-g09d2

