From d1debe4de37edfcafdd3446c4918488521af3a84 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 31 Jul 2019 19:26:22 -0400
Subject: fixed treeview omitting documents

---
 .../views/collections/CollectionTreeView.tsx       | 46 +++++++++-------------
 1 file changed, 19 insertions(+), 27 deletions(-)

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

diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index b1e6eada0..fa75c680a 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -70,30 +70,16 @@ class TreeView extends React.Component<TreeViewProps> {
     private _header?: React.RefObject<HTMLDivElement> = React.createRef();
     private _treedropDisposer?: DragManager.DragDropDisposer;
     private _dref = React.createRef<HTMLDivElement>();
-    @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, "data"); }
+    @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, this.fieldKey); }
     @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.document.maxEmbedHeight, 300); }
     @observable _collapsed: boolean = true;
 
     @computed get fieldKey() {
-        let target = this.props.document;
-        let keys = Array.from(Object.keys(target));  // bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set
-        if (target.proto instanceof Doc) {
-            let arr = Array.from(Object.keys(target.proto));// bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set
-            keys.push(...arr);
-            while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1);
-        }
-        let keyList: string[] = [];
-        keys.map(key => {
-            let docList = Cast(this.dataDoc[key], listSpec(Doc));
-            if (docList && docList.length > 0) {
-                keyList.push(key);
-            }
-        });
         let layout = StrCast(this.props.document.layout);
-        if (layout.indexOf("fieldKey={\"") !== -1 && layout.indexOf("fieldExt=") === -1) {
+        if (layout.indexOf("fieldKey={\"") !== -1) {
             return layout.split("fieldKey={\"")[1].split("\"")[0];
         }
-        return keyList.length ? keyList[0] : "data";
+        return "data";
     }
 
     @computed get dataDoc() { return this.resolvedDataDoc ? this.resolvedDataDoc : this.props.document; }
@@ -104,7 +90,7 @@ class TreeView extends React.Component<TreeViewProps> {
             // this document as the data document for the layout.
             return this.props.document;
         }
-        return this.props.dataDoc ? this.props.dataDoc : undefined;
+        return this.props.dataDoc;
     }
 
     protected createTreeDropTarget = (ele: HTMLDivElement) => {
@@ -202,8 +188,8 @@ class TreeView extends React.Component<TreeViewProps> {
         let headerElements = (
             <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView}
                 onPointerDown={action(() => {
-                    this.props.document.treeViewExpandedView = this.treeViewExpandedView === "data" ? "fields" :
-                        this.treeViewExpandedView === "fields" && this.props.document.layout ? "layout" : "data";
+                    this.props.document.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? "fields" :
+                        this.treeViewExpandedView === "fields" && this.props.document.layout ? "layout" : this.fieldKey;
                     this._collapsed = false;
                 })}>
                 {this.treeViewExpandedView}
@@ -382,17 +368,20 @@ class TreeView extends React.Component<TreeViewProps> {
 
     render() {
         let contentElement: (JSX.Element | null) = null;
-        let docList = Cast(this.dataDoc[this.fieldKey], listSpec(Doc));
         let remDoc = (doc: Doc) => this.remove(doc, this.fieldKey);
         let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc, addBefore, before);
 
         if (!this._collapsed) {
-            if (this.treeViewExpandedView === "data") {
-                let doc = Cast(this.props.document[this.fieldKey], Doc);
+            if (this.treeViewExpandedView === this.fieldKey) {
+                let layout = this.props.document.layout as Doc;
+                let childDocs = (this.props.dataDoc ? Cast(this.props.dataDoc[this.fieldKey], listSpec(Doc)) : undefined) ||
+                    (layout ? Cast(layout[this.fieldKey], listSpec(Doc)) : undefined) ||
+                    Cast(this.props.document[this.fieldKey], listSpec(Doc));
                 contentElement = <ul key={this.fieldKey + "more"}>
                     {this.fieldKey === "links" ? this.renderLinks() :
-                        TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this.props.document, this.resolvedDataDoc, this.fieldKey, addDoc, remDoc, this.move,
-                            this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth)}
+                        !childDocs ? (null) :
+                            TreeView.GetChildElements(childDocs as Doc[], this.props.treeViewId, layout, this.resolvedDataDoc, this.fieldKey, addDoc, remDoc, this.move,
+                                this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth)}
                 </ul >;
             } else if (this.treeViewExpandedView === "fields") {
                 contentElement = <ul><div ref={this._dref} style={{ display: "inline-block" }} key={this.props.document[Id] + this.props.document.title}>
@@ -454,6 +443,8 @@ class TreeView extends React.Component<TreeViewProps> {
         let docList = docs.filter(child => !child.excludeFromLibrary);
         let rowWidth = () => panelWidth() - 20;
         return docList.map((child, i) => {
+            let pair = Doc.GetLayoutDataDocPair(containingCollection, dataDoc, key, child);
+
             let indent = i === 0 ? undefined : () => {
                 if (StrCast(docList[i - 1].layout).indexOf("CollectionView") !== -1) {
                     let fieldKeysub = StrCast(docList[i - 1].layout).split("fieldKey")[1];
@@ -470,8 +461,8 @@ class TreeView extends React.Component<TreeViewProps> {
                 return aspect ? Math.min(child[WidthSym](), rowWidth()) / aspect : child[HeightSym]();
             };
             return <TreeView
-                document={child}
-                dataDoc={dataDoc}
+                document={pair.layout}
+                dataDoc={pair.data}
                 containingCollection={containingCollection}
                 treeViewId={treeViewId}
                 key={child[Id]}
@@ -572,6 +563,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
 
 
     render() {
+        console.log("DTITLE + " + this.props.Document.title);
         Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey);
         let dropAction = StrCast(this.props.Document.dropAction) as dropActionType;
         let addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before);
-- 
cgit v1.2.3-70-g09d2


From d4accdd22cabdd78fc7bd76dd7ce3cb59e4b102f Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 1 Aug 2019 00:31:50 -0400
Subject: more treeview cleanup and fixes.

---
 src/client/util/SelectionManager.ts                |   1 +
 src/client/views/DocumentDecorations.tsx           |   4 +-
 .../views/collections/CollectionTreeView.tsx       | 340 +++++++++------------
 .../authentication/models/current_user_utils.ts    |   2 +-
 4 files changed, 145 insertions(+), 202 deletions(-)

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

diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 9efef888d..ee623d082 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -4,6 +4,7 @@ import { DocumentView } from "../views/nodes/DocumentView";
 import { FormattedTextBox } from "../views/nodes/FormattedTextBox";
 import { NumCast, StrCast } from "../../new_fields/Types";
 import { InkingControl } from "../views/InkingControl";
+import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
 
 export namespace SelectionManager {
 
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 40f2c3da9..eccfc7c30 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -29,6 +29,7 @@ import { LinkManager } from '../util/LinkManager';
 import { ObjectField } from '../../new_fields/ObjectField';
 import { MetadataEntryMenu } from './MetadataEntryMenu';
 import { ImageBox } from './nodes/ImageBox';
+import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -144,7 +145,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     @computed
     get Bounds(): { x: number, y: number, b: number, r: number } {
         return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => {
-            if (documentView.props.renderDepth === 0) {
+            if (documentView.props.renderDepth === 0 ||
+                Doc.AreProtosEqual(documentView.props.Document, CurrentUserUtils.UserDocument)) {
                 return bounds;
             }
             let transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse();
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index fa75c680a..7f5d78313 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -25,7 +25,6 @@ import { CollectionSchemaPreview } from './CollectionSchemaView';
 import { CollectionSubView } from "./CollectionSubView";
 import "./CollectionTreeView.scss";
 import React = require("react");
-import { LinkManager } from '../../util/LinkManager';
 import { ComputedField } from '../../../new_fields/ScriptField';
 import { KeyValueBox } from '../nodes/KeyValueBox';
 
@@ -67,22 +66,24 @@ library.add(faPlus, faMinus);
  * Component that takes in a document prop and a boolean whether it's collapsed or not.
  */
 class TreeView extends React.Component<TreeViewProps> {
+    static loadId = "";
     private _header?: React.RefObject<HTMLDivElement> = React.createRef();
     private _treedropDisposer?: DragManager.DragDropDisposer;
     private _dref = React.createRef<HTMLDivElement>();
-    @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, this.fieldKey); }
-    @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.document.maxEmbedHeight, 300); }
     @observable _collapsed: boolean = true;
-
+    @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, "fields"); }
+    @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.document.maxEmbedHeight, 300); }
+    @computed get dataDoc() { return this.resolvedDataDoc ? this.resolvedDataDoc : this.props.document; }
     @computed get fieldKey() {
-        let layout = StrCast(this.props.document.layout);
-        if (layout.indexOf("fieldKey={\"") !== -1) {
-            return layout.split("fieldKey={\"")[1].split("\"")[0];
-        }
-        return "data";
+        let splits = StrCast(this.props.document.layout).split("fieldKey={\"");
+        return splits.length > 1 ? splits[1].split("\"")[0] : "data";
+    }
+    @computed get childDocs() {
+        let layout = this.props.document.layout as Doc;
+        return (this.props.dataDoc ? Cast(this.props.dataDoc[this.fieldKey], listSpec(Doc)) : undefined) ||
+            (layout ? Cast(layout[this.fieldKey], listSpec(Doc)) : undefined) ||
+            Cast(this.props.document[this.fieldKey], listSpec(Doc));
     }
-
-    @computed get dataDoc() { return this.resolvedDataDoc ? this.resolvedDataDoc : this.props.document; }
     @computed get resolvedDataDoc() {
         if (this.props.dataDoc === undefined && this.props.document.layout instanceof Doc) {
             // if there is no dataDoc (ie, we're not rendering a template layout), but this document
@@ -92,16 +93,30 @@ class TreeView extends React.Component<TreeViewProps> {
         }
         return this.props.dataDoc;
     }
+    @computed get boundsOfCollectionDocument() {
+        return StrCast(this.props.document.type).indexOf(DocumentType.COL) === -1 ? undefined :
+            Doc.ComputeContentBounds(DocListCast(this.props.document.data));
+    }
 
-    protected createTreeDropTarget = (ele: HTMLDivElement) => {
-        this._treedropDisposer && this._treedropDisposer();
-        if (ele) {
-            this._treedropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.treeDrop.bind(this) } });
+    @undoBatch delete = () => this.props.deleteDoc(this.dataDoc);
+    @undoBatch openRight = () => this.props.addDocTab(this.props.document, undefined, "onRight");
+    @undoBatch indent = () => this.props.addDocument(this.props.document) && this.delete();
+    @undoBatch move = (doc: Doc, target: Doc, addDoc: (doc: Doc) => boolean) => {
+        return this.props.document !== target && this.props.deleteDoc(doc) && addDoc(doc);
+    }
+    @undoBatch @action remove = (document: Document, key: string): boolean => {
+        let children = Cast(this.dataDoc[key], listSpec(Doc), []);
+        if (children.indexOf(document) !== -1) {
+            children.splice(children.indexOf(document), 1);
+            return true;
         }
+        return false;
     }
 
-    @undoBatch delete = () => this.props.deleteDoc(this.dataDoc);
-    @undoBatch openRight = async () => this.props.addDocTab(this.props.document, undefined, "onRight");
+    protected createTreeDropTarget = (ele: HTMLDivElement) => {
+        this._treedropDisposer && this._treedropDisposer();
+        ele && (this._treedropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.treeDrop.bind(this) } }));
+    }
 
     onPointerDown = (e: React.PointerEvent) => e.stopPropagation();
     onPointerEnter = (e: React.PointerEvent): void => {
@@ -130,34 +145,6 @@ class TreeView extends React.Component<TreeViewProps> {
         e.stopPropagation();
     }
 
-    @action
-    remove = (document: Document, key: string): boolean => {
-        let children = Cast(this.dataDoc[key], listSpec(Doc), []);
-        if (children.indexOf(document) !== -1) {
-            children.splice(children.indexOf(document), 1);
-            return true;
-        }
-        return false;
-    }
-
-    @action
-    move: DragManager.MoveFunction = (doc: Doc, target: Doc, addDoc) => {
-        return this.props.document !== target && this.props.deleteDoc(doc) && addDoc(doc);
-    }
-    @action
-    indent = () => this.props.addDocument(this.props.document) && this.delete()
-
-    renderBullet() {
-        let docList = Cast(this.dataDoc[this.fieldKey], listSpec(Doc));
-        let doc = Cast(this.dataDoc[this.fieldKey], Doc);
-        let isDoc = doc instanceof Doc || docList;
-        let c;
-        return <div className="bullet" onClick={action(() => this._collapsed = !this._collapsed)} style={{ color: StrCast(this.props.document.color, "black"), opacity: 0.4 }}>
-            {<FontAwesomeIcon icon={this._collapsed ? (isDoc ? "caret-square-right" : "caret-right") : (isDoc ? "caret-square-down" : "caret-down")} />}
-        </div>;
-    }
-
-    static loadId = "";
     editableView = (key: string, style?: string) => (<EditableView
         oneLine={true}
         display={"inline"}
@@ -178,43 +165,6 @@ class TreeView extends React.Component<TreeViewProps> {
         OnTab={() => this.props.indentDocument && this.props.indentDocument()}
     />)
 
-    /**
-     * Renders the EditableView title element for placement into the tree.
-     */
-    renderTitle() {
-        let reference = React.createRef<HTMLDivElement>();
-        let onItemDown = SetupDrag(reference, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId, true);
-
-        let headerElements = (
-            <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView}
-                onPointerDown={action(() => {
-                    this.props.document.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? "fields" :
-                        this.treeViewExpandedView === "fields" && this.props.document.layout ? "layout" : this.fieldKey;
-                    this._collapsed = false;
-                })}>
-                {this.treeViewExpandedView}
-            </span>);
-        let dataDocs = CollectionDockingView.Instance ? Cast(CollectionDockingView.Instance.props.Document[this.fieldKey], listSpec(Doc), []) : [];
-        let openRight = dataDocs && dataDocs.indexOf(this.dataDoc) !== -1 ? (null) : (
-            <div className="treeViewItem-openRight" onPointerDown={this.onPointerDown} onClick={this.openRight}>
-                <FontAwesomeIcon icon="angle-right" size="lg" />
-            </div>);
-        return <>
-            <div className="docContainer" id={`docContainer-${this.props.parentKey}`} ref={reference} onPointerDown={onItemDown}
-                style={{
-                    background: BoolCast(this.props.document.libraryBrush) ? "#06121212" : "0",
-                    outline: BoolCast(this.props.document.workspaceBrush) ? "dashed 1px #06123232" : undefined,
-                    pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? "all" : "none"
-                }}
-            >
-                {this.editableView("title")}
-                {/* {<div className="delete-button" onClick={this.delete}><FontAwesomeIcon icon="trash-alt" size="xs" /></div>} */}
-            </div >
-            {headerElements}
-            {openRight}
-        </>;
-    }
-
     onWorkspaceContextMenu = (e: React.MouseEvent): void => {
         if (!e.isPropagationStopped()) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
             if (NumCast(this.props.document.viewType) !== CollectionViewType.Docking) {
@@ -275,39 +225,6 @@ class TreeView extends React.Component<TreeViewProps> {
         let finalXf = this.props.ScreenToLocalTransform().translate(offset[0], offset[1]);
         return finalXf;
     }
-
-    renderLinks = () => {
-        let ele: JSX.Element[] = [];
-        let remDoc = (doc: Doc) => this.remove(doc, this.fieldKey);
-        let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.props.document, this.fieldKey, doc, addBefore, before);
-        let groups = LinkManager.Instance.getRelatedGroupedLinks(this.props.document);
-        groups.forEach((groupLinkDocs, groupType) => {
-            // let destLinks = groupLinkDocs.map(d => LinkManager.Instance.getOppositeAnchor(d, this.props.document));
-            let destLinks: Doc[] = [];
-            groupLinkDocs.forEach((doc) => {
-                let opp = LinkManager.Instance.getOppositeAnchor(doc, this.props.document);
-                if (opp) {
-                    destLinks.push(opp);
-                }
-            });
-            ele.push(
-                <div key={"treeviewlink-" + groupType + "subtitle"}>
-                    <div className="collectionTreeView-subtitle">{groupType}:</div>
-                    {
-                        TreeView.GetChildElements(destLinks, this.props.treeViewId, this.props.document, this.props.dataDoc, "treeviewlink-" + groupType, addDoc, remDoc, this.move,
-                            this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth)
-                    }
-                </div>
-            );
-        });
-        return ele;
-    }
-
-    @computed get boundsOfCollectionDocument() {
-        if (StrCast(this.props.document.type).indexOf(DocumentType.COL) === -1) return undefined;
-        let layoutDoc = this.props.document;
-        return Doc.ComputeContentBounds(DocListCast(layoutDoc.data));
-    }
     docWidth = () => {
         let aspect = NumCast(this.props.document.nativeHeight) / NumCast(this.props.document.nativeWidth);
         if (aspect) return Math.min(this.props.document[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.panelWidth() - 5));
@@ -323,39 +240,29 @@ class TreeView extends React.Component<TreeViewProps> {
         })());
     }
 
-    noOverlays = (doc: Doc) => ({ title: "", caption: "" });
-
-    expandedField = (doc?: Doc) => {
-        if (!doc) return <div />;
-        let realDoc = doc;
-
+    expandedField = (doc: Doc) => {
         let ids: { [key: string]: string } = {};
-        Object.keys(doc).forEach(key => {
-            if (!(key in ids) && realDoc[key] !== ComputedField.undefined) {
-                ids[key] = key;
-            }
-        });
+        doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
 
         let rows: JSX.Element[] = [];
         for (let key of Object.keys(ids).sort()) {
-            let contents = realDoc[key] ? realDoc[key] : undefined;
+            let contents = doc[key];
             let contentElement: JSX.Element[] | JSX.Element = [];
 
             if (contents instanceof Doc || Cast(contents, listSpec(Doc))) {
-                let docList = contents;
                 let remDoc = (doc: Doc) => this.remove(doc, key);
                 let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before);
-                contentElement = key === "links" ? this.renderLinks() :
-                    TreeView.GetChildElements(docList instanceof Doc ? [docList] : DocListCast(docList), this.props.treeViewId, realDoc, undefined, key, addDoc, remDoc, this.move,
-                        this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth);
+                contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] :
+                    DocListCast(contents), this.props.treeViewId, doc, undefined, key, addDoc, remDoc, this.move,
+                    this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth);
             } else {
                 contentElement = <EditableView
                     key="editableView"
-                    contents={contents ? contents.toString() : "null"}
+                    contents={contents !== undefined ? contents.toString() : "null"}
                     height={13}
                     fontSize={12}
-                    GetValue={() => Field.toKeyValueString(realDoc, key)}
-                    SetValue={(value: string) => KeyValueBox.SetField(realDoc, key, value)} />;
+                    GetValue={() => Field.toKeyValueString(doc, key)}
+                    SetValue={(value: string) => KeyValueBox.SetField(doc, key, value)} />;
             }
             rows.push(<div style={{ display: "flex" }} key={key}>
                 <span style={{ fontWeight: "bold" }}>{key + ":"}</span>
@@ -366,59 +273,100 @@ class TreeView extends React.Component<TreeViewProps> {
         return rows;
     }
 
-    render() {
-        let contentElement: (JSX.Element | null) = null;
-        let remDoc = (doc: Doc) => this.remove(doc, this.fieldKey);
-        let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc, addBefore, before);
+    noOverlays = (doc: Doc) => ({ title: "", caption: "" });
 
-        if (!this._collapsed) {
-            if (this.treeViewExpandedView === this.fieldKey) {
-                let layout = this.props.document.layout as Doc;
-                let childDocs = (this.props.dataDoc ? Cast(this.props.dataDoc[this.fieldKey], listSpec(Doc)) : undefined) ||
-                    (layout ? Cast(layout[this.fieldKey], listSpec(Doc)) : undefined) ||
-                    Cast(this.props.document[this.fieldKey], listSpec(Doc));
-                contentElement = <ul key={this.fieldKey + "more"}>
-                    {this.fieldKey === "links" ? this.renderLinks() :
-                        !childDocs ? (null) :
-                            TreeView.GetChildElements(childDocs as Doc[], this.props.treeViewId, layout, this.resolvedDataDoc, this.fieldKey, addDoc, remDoc, this.move,
-                                this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth)}
-                </ul >;
-            } else if (this.treeViewExpandedView === "fields") {
-                contentElement = <ul><div ref={this._dref} style={{ display: "inline-block" }} key={this.props.document[Id] + this.props.document.title}>
-                    {this.expandedField(this.dataDoc)}
-                </div></ul>;
-            } else {
-                let layoutDoc = this.props.document;
-                contentElement = <div ref={this._dref} style={{ display: "inline-block", height: this.docHeight() }} key={this.props.document[Id] + this.props.document.title}>
-                    <CollectionSchemaPreview
-                        Document={layoutDoc}
-                        DataDocument={this.resolvedDataDoc}
-                        renderDepth={this.props.renderDepth}
-                        showOverlays={this.noOverlays}
-                        fitToBox={this.boundsOfCollectionDocument !== undefined}
-                        width={this.docWidth}
-                        height={this.docHeight}
-                        getTransform={this.docTransform}
-                        CollectionView={undefined}
-                        addDocument={emptyFunction as any}
-                        moveDocument={this.props.moveDocument}
-                        removeDocument={emptyFunction as any}
-                        active={this.props.active}
-                        whenActiveChanged={emptyFunction as any}
-                        addDocTab={this.props.addDocTab}
-                        setPreviewScript={emptyFunction}>
-                    </CollectionSchemaPreview>
-                </div>;
-            }
+    @computed get renderContent() {
+        if (this.treeViewExpandedView === this.fieldKey) {
+            let remDoc = (doc: Doc) => this.remove(doc, this.fieldKey);
+            let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc, addBefore, before);
+            return <ul key={this.fieldKey + "more"}>
+                {!this.childDocs ? (null) :
+                    TreeView.GetChildElements(this.childDocs as Doc[], this.props.treeViewId, this.props.document.layout as Doc,
+                        this.resolvedDataDoc, this.fieldKey, addDoc, remDoc, this.move,
+                        this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform,
+                        this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth)}
+            </ul >;
+        } else if (this.treeViewExpandedView === "fields") {
+            return <ul><div ref={this._dref} style={{ display: "inline-block" }} key={this.props.document[Id] + this.props.document.title}>
+                {this.dataDoc ? this.expandedField(this.dataDoc) : (null)}
+            </div></ul>;
+        } else {
+            let layoutDoc = this.props.document;
+            return <div ref={this._dref} style={{ display: "inline-block", height: this.docHeight() }} key={this.props.document[Id] + this.props.document.title}>
+                <CollectionSchemaPreview
+                    Document={layoutDoc}
+                    DataDocument={this.resolvedDataDoc}
+                    renderDepth={this.props.renderDepth}
+                    showOverlays={this.noOverlays}
+                    fitToBox={this.boundsOfCollectionDocument !== undefined}
+                    width={this.docWidth}
+                    height={this.docHeight}
+                    getTransform={this.docTransform}
+                    CollectionView={undefined}
+                    addDocument={emptyFunction as any}
+                    moveDocument={this.props.moveDocument}
+                    removeDocument={emptyFunction as any}
+                    active={this.props.active}
+                    whenActiveChanged={emptyFunction as any}
+                    addDocTab={this.props.addDocTab}
+                    setPreviewScript={emptyFunction}>
+                </CollectionSchemaPreview>
+            </div>;
         }
+    }
+
+    @computed
+    get renderBullet() {
+        return <div className="bullet" onClick={action(() => this._collapsed = !this._collapsed)} style={{ color: StrCast(this.props.document.color, "black"), opacity: 0.4 }}>
+            {<FontAwesomeIcon icon={this._collapsed ? (this.childDocs ? "caret-square-right" : "caret-right") : (this.childDocs ? "caret-square-down" : "caret-down")} />}
+        </div>;
+    }
+    /**
+     * Renders the EditableView title element for placement into the tree.
+     */
+    @computed
+    get renderTitle() {
+        let reference = React.createRef<HTMLDivElement>();
+        let onItemDown = SetupDrag(reference, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId, true);
+
+        let headerElements = (
+            <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView}
+                onPointerDown={action(() => {
+                    this.props.document.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? "fields" :
+                        this.treeViewExpandedView === "fields" && this.props.document.layout ? "layout" :
+                            this.childDocs ? this.fieldKey : "fields";
+                    this._collapsed = false;
+                })}>
+                {this.treeViewExpandedView}
+            </span>);
+        let dataDocs = CollectionDockingView.Instance ? Cast(CollectionDockingView.Instance.props.Document[this.fieldKey], listSpec(Doc), []) : [];
+        let openRight = dataDocs && dataDocs.indexOf(this.dataDoc) !== -1 ? (null) : (
+            <div className="treeViewItem-openRight" onPointerDown={this.onPointerDown} onClick={this.openRight}>
+                <FontAwesomeIcon icon="angle-right" size="lg" />
+            </div>);
+        return <>
+            <div className="docContainer" id={`docContainer-${this.props.parentKey}`} ref={reference} onPointerDown={onItemDown}
+                style={{
+                    background: BoolCast(this.props.document.libraryBrush) ? "#06121212" : "0",
+                    outline: BoolCast(this.props.document.workspaceBrush) ? "dashed 1px #06123232" : undefined,
+                    pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? "all" : "none"
+                }} >
+                {this.editableView("title")}
+            </div >
+            {headerElements}
+            {openRight}
+        </>;
+    }
+
+    render() {
         return <div className="treeViewItem-container" ref={this.createTreeDropTarget} onContextMenu={this.onWorkspaceContextMenu}>
             <li className="collection-child">
                 <div className="treeViewItem-header" ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
-                    {this.renderBullet()}
-                    {this.renderTitle()}
+                    {this.renderBullet}
+                    {this.renderTitle}
                 </div>
                 <div className="treeViewItem-border">
-                    {contentElement}
+                    {this._collapsed ? (null) : this.renderContent}
                 </div>
             </li>
         </div>;
@@ -488,7 +436,9 @@ export class CollectionTreeView extends CollectionSubView(Document) {
     private treedropDisposer?: DragManager.DragDropDisposer;
     private _mainEle?: HTMLDivElement;
 
-    @computed get chromeCollapsed() { return this.props.chromeCollapsed; }
+    @observable static NotifsCol: Opt<Doc>;
+
+    @computed get resolvedDataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document; }
 
     protected createTreeDropTarget = (ele: HTMLDivElement) => {
         this.treedropDisposer && this.treedropDisposer();
@@ -520,21 +470,15 @@ export class CollectionTreeView extends CollectionSubView(Document) {
             ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
         }
     }
-
-    @computed get resolvedDataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document; }
-
     outerXf = () => Utils.GetScreenTransform(this._mainEle!);
     onTreeDrop = (e: React.DragEvent) => this.onDrop(e, {});
-
-
-    @observable static NotifsCol: Opt<Doc>;
-
     openNotifsCol = () => {
         if (CollectionTreeView.NotifsCol && CollectionDockingView.Instance) {
             CollectionDockingView.Instance.AddRightSplit(CollectionTreeView.NotifsCol, undefined);
         }
     }
-    @computed get notifsButton() {
+
+    @computed get renderNotifsButton() {
         const length = CollectionTreeView.NotifsCol ? DocListCast(CollectionTreeView.NotifsCol.data).length : 0;
         const notifsRef = React.createRef<HTMLDivElement>();
         const dragNotifs = action(() => CollectionTreeView.NotifsCol!);
@@ -550,20 +494,16 @@ export class CollectionTreeView extends CollectionSubView(Document) {
             </div>
         </div >;
     }
-    @computed get clearButton() {
+    @computed get renderClearButton() {
         return <div id="toolbar" key="toolbar">
-            <div >
-                <button className="toolbar-button round-button" title="Notifs"
-                    onClick={undoBatch(action(() => Doc.GetProto(this.props.Document)[this.props.fieldKey] = undefined))}>
-                    <FontAwesomeIcon icon={faTrash} size="sm" />
-                </button>
-            </div>
+            <button className="toolbar-button round-button" title="Notifs"
+                onClick={undoBatch(action(() => Doc.GetProto(this.props.Document)[this.props.fieldKey] = undefined))}>
+                <FontAwesomeIcon icon={faTrash} size="sm" />
+            </button>
         </div >;
     }
 
-
     render() {
-        console.log("DTITLE + " + this.props.Document.title);
         Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey);
         let dropAction = StrCast(this.props.Document.dropAction) as dropActionType;
         let addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before);
@@ -588,8 +528,8 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                         TreeView.loadId = doc[Id];
                         Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true);
                     }} />
-                {this.props.Document.workspaceLibrary ? this.notifsButton : (null)}
-                {this.props.Document.allowClear ? this.clearButton : (null)}
+                {this.props.Document.workspaceLibrary ? this.renderNotifsButton : (null)}
+                {this.props.Document.allowClear ? this.renderClearButton : (null)}
                 <ul className="no-indent" style={{ width: "max-content" }} >
                     {
                         TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.Document, this.props.DataDoc, this.props.fieldKey, addDoc, this.remove,
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 1c52a3f11..91d7ba87d 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -71,7 +71,7 @@ export class CurrentUserUtils {
             doc.sidebar = sidebar;
         }
         StrCast(doc.title).indexOf("@") !== -1 && (doc.title = StrCast(doc.title).split("@")[0] + "'s Library");
-
+        doc.width = 100;
     }
 
     public static loadCurrentUser() {
-- 
cgit v1.2.3-70-g09d2


From e0fb04a7748666a41a7cd500dcdd23027ef12b6f Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 2 Aug 2019 12:56:37 -0400
Subject: links

---
 src/client/documents/Documents.ts                  |  7 +++++-
 src/client/util/LinkManager.ts                     | 13 ++++++++--
 .../views/collections/CollectionTreeView.tsx       | 28 +++++++++++++++-------
 src/client/views/nodes/KeyValuePair.tsx            | 17 ++++++-------
 4 files changed, 43 insertions(+), 22 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 63b4d4e32..818383765 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -38,7 +38,7 @@ import { CollectionDockingView } from "../views/collections/CollectionDockingVie
 import { LinkManager } from "../util/LinkManager";
 import { DocumentManager } from "../util/DocumentManager";
 import DirectoryImportBox from "../util/Import & Export/DirectoryImportBox";
-import { Scripting } from "../util/Scripting";
+import { Scripting, CompileScript } from "../util/Scripting";
 import { ButtonBox } from "../views/nodes/ButtonBox";
 import { SchemaHeaderField, RandomPastel } from "../../new_fields/SchemaHeaderField";
 import { ComputedField } from "../../new_fields/ScriptField";
@@ -623,6 +623,11 @@ export namespace DocUtils {
 
             LinkManager.Instance.addLink(linkDoc);
 
+            let script = `return links(self)};`;
+            let computed = CompileScript(script, { params: { this: "Doc" }, capturedVariables: { self: source }, typecheck: false });
+            computed.compiled && (Doc.GetProto(source).links = new ComputedField(computed));
+            computed.compiled && (Doc.GetProto(target).links = new ComputedField(computed));
+
         }, "make link");
         return linkDoc;
     }
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index a647f22c1..448a8e9cf 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -6,6 +6,7 @@ import { List } from "../../new_fields/List";
 import { Id } from "../../new_fields/FieldSymbols";
 import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
 import { Docs } from "../documents/Documents";
+import { Scripting } from "./Scripting";
 
 
 /* 
@@ -42,7 +43,12 @@ export class LinkManager {
     }
 
     public getAllLinks(): Doc[] {
-        return LinkManager.Instance.LinkManagerDoc ? LinkManager.Instance.LinkManagerDoc.allLinks ? DocListCast(LinkManager.Instance.LinkManagerDoc.allLinks) : [] : [];
+        let ldoc = LinkManager.Instance.LinkManagerDoc;
+        if (ldoc) {
+            let docs = DocListCast(ldoc.allLinks);
+            return docs;
+        }
+        return [];
     }
 
     public addLink(linkDoc: Doc): boolean {
@@ -242,4 +248,7 @@ export class LinkManager {
             return Cast(linkDoc.anchor1, Doc, null);
         }
     }
-}
\ No newline at end of file
+}
+Scripting.addGlobal(function links(doc: any) {
+    return new List(LinkManager.Instance.getAllRelatedLinks(doc));
+});
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 7f5d78313..02b2583cd 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -27,6 +27,7 @@ import "./CollectionTreeView.scss";
 import React = require("react");
 import { ComputedField } from '../../../new_fields/ScriptField';
 import { KeyValueBox } from '../nodes/KeyValueBox';
+import { exportNamedDeclaration } from 'babel-types';
 
 
 export interface TreeViewProps {
@@ -79,11 +80,17 @@ class TreeView extends React.Component<TreeViewProps> {
         return splits.length > 1 ? splits[1].split("\"")[0] : "data";
     }
     @computed get childDocs() {
-        let layout = this.props.document.layout as Doc;
+        let layout = this.props.document.layout instanceof Doc ? this.props.document.layout : undefined;
         return (this.props.dataDoc ? Cast(this.props.dataDoc[this.fieldKey], listSpec(Doc)) : undefined) ||
             (layout ? Cast(layout[this.fieldKey], listSpec(Doc)) : undefined) ||
             Cast(this.props.document[this.fieldKey], listSpec(Doc));
     }
+    @computed get childLinks() {
+        let layout = this.props.document.layout instanceof Doc ? this.props.document.layout : undefined;
+        return (this.props.dataDoc ? Cast(this.props.dataDoc.links, listSpec(Doc)) : undefined) ||
+            (layout instanceof Doc ? Cast(layout.links, listSpec(Doc)) : undefined) ||
+            Cast(this.props.document.links, listSpec(Doc));
+    }
     @computed get resolvedDataDoc() {
         if (this.props.dataDoc === undefined && this.props.document.layout instanceof Doc) {
             // if there is no dataDoc (ie, we're not rendering a template layout), but this document
@@ -276,13 +283,15 @@ class TreeView extends React.Component<TreeViewProps> {
     noOverlays = (doc: Doc) => ({ title: "", caption: "" });
 
     @computed get renderContent() {
-        if (this.treeViewExpandedView === this.fieldKey) {
-            let remDoc = (doc: Doc) => this.remove(doc, this.fieldKey);
-            let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc, addBefore, before);
-            return <ul key={this.fieldKey + "more"}>
-                {!this.childDocs ? (null) :
-                    TreeView.GetChildElements(this.childDocs as Doc[], this.props.treeViewId, this.props.document.layout as Doc,
-                        this.resolvedDataDoc, this.fieldKey, addDoc, remDoc, this.move,
+        const expandKey = this.treeViewExpandedView === this.fieldKey ? this.fieldKey : this.treeViewExpandedView === "links" ? "links" : undefined;
+        if (expandKey !== undefined) {
+            let remDoc = (doc: Doc) => this.remove(doc, expandKey);
+            let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before);
+            let docs = expandKey === "links" ? this.childLinks : this.childDocs;
+            return <ul key={expandKey + "more"}>
+                {!docs ? (null) :
+                    TreeView.GetChildElements(docs as Doc[], this.props.treeViewId, this.props.document.layout as Doc,
+                        this.resolvedDataDoc, expandKey, addDoc, remDoc, this.move,
                         this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform,
                         this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth)}
             </ul >;
@@ -334,7 +343,8 @@ class TreeView extends React.Component<TreeViewProps> {
                 onPointerDown={action(() => {
                     this.props.document.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? "fields" :
                         this.treeViewExpandedView === "fields" && this.props.document.layout ? "layout" :
-                            this.childDocs ? this.fieldKey : "fields";
+                            this.treeViewExpandedView === "layout" && this.props.document.links ? "links" :
+                                this.childDocs ? this.fieldKey : "fields";
                     this._collapsed = false;
                 })}>
                 {this.treeViewExpandedView}
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 3775f0f47..534a42efc 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -1,22 +1,19 @@
 import { action, observable } from 'mobx';
 import { observer } from "mobx-react";
 import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
-import { emptyFunction, returnFalse, returnZero, returnTrue, returnOne } from '../../../Utils';
-import { CompileScript, CompiledScript, ScriptOptions } from "../../util/Scripting";
+import { Doc, Field } from '../../../new_fields/Doc';
+import { emptyFunction, returnFalse, returnOne, returnZero } from '../../../Utils';
+import { Docs } from '../../documents/Documents';
 import { Transform } from '../../util/Transform';
+import { undoBatch } from '../../util/UndoManager';
+import { CollectionDockingView } from '../collections/CollectionDockingView';
+import { ContextMenu } from '../ContextMenu';
 import { EditableView } from "../EditableView";
 import { FieldView, FieldViewProps } from './FieldView';
+import { KeyValueBox } from './KeyValueBox';
 import "./KeyValueBox.scss";
 import "./KeyValuePair.scss";
 import React = require("react");
-import { Doc, Opt, Field } from '../../../new_fields/Doc';
-import { FieldValue } from '../../../new_fields/Types';
-import { KeyValueBox } from './KeyValueBox';
-import { DragManager, SetupDrag } from '../../util/DragManager';
-import { ContextMenu } from '../ContextMenu';
-import { Docs } from '../../documents/Documents';
-import { CollectionDockingView } from '../collections/CollectionDockingView';
-import { undoBatch } from '../../util/UndoManager';
 
 // Represents one row in a key value plane
 
-- 
cgit v1.2.3-70-g09d2


From 243beedb3a9e8be526d026fade0e8d48b507148a Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 7 Aug 2019 14:15:25 -0400
Subject: fixed defaults for treeview expansion.

---
 src/client/views/collections/CollectionTreeView.tsx | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

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

diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 02b2583cd..571967743 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -27,7 +27,6 @@ import "./CollectionTreeView.scss";
 import React = require("react");
 import { ComputedField } from '../../../new_fields/ScriptField';
 import { KeyValueBox } from '../nodes/KeyValueBox';
-import { exportNamedDeclaration } from 'babel-types';
 
 
 export interface TreeViewProps {
@@ -71,8 +70,9 @@ class TreeView extends React.Component<TreeViewProps> {
     private _header?: React.RefObject<HTMLDivElement> = React.createRef();
     private _treedropDisposer?: DragManager.DragDropDisposer;
     private _dref = React.createRef<HTMLDivElement>();
+    get defaultExpandedView() { return this.childDocs ? this.fieldKey : "fields"; }
     @observable _collapsed: boolean = true;
-    @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, "fields"); }
+    @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, this.defaultExpandedView); }
     @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.document.maxEmbedHeight, 300); }
     @computed get dataDoc() { return this.resolvedDataDoc ? this.resolvedDataDoc : this.props.document; }
     @computed get fieldKey() {
@@ -341,10 +341,12 @@ class TreeView extends React.Component<TreeViewProps> {
         let headerElements = (
             <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView}
                 onPointerDown={action(() => {
-                    this.props.document.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? "fields" :
-                        this.treeViewExpandedView === "fields" && this.props.document.layout ? "layout" :
-                            this.treeViewExpandedView === "layout" && this.props.document.links ? "links" :
-                                this.childDocs ? this.fieldKey : "fields";
+                    if (!this._collapsed) {
+                        this.props.document.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? "fields" :
+                            this.treeViewExpandedView === "fields" && this.props.document.layout ? "layout" :
+                                this.treeViewExpandedView === "layout" && this.props.document.links ? "links" :
+                                    this.childDocs ? this.fieldKey : "fields";
+                    }
                     this._collapsed = false;
                 })}>
                 {this.treeViewExpandedView}
-- 
cgit v1.2.3-70-g09d2


From ebddce0975fa7e224e022cc075eee71abeacbe1d Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 7 Aug 2019 23:27:21 -0400
Subject: changed pdfs to render regions as collections.  changed libraryBrush
 implementation.

---
 src/client/views/SearchItem.tsx                    |  6 ++--
 .../views/collections/CollectionDockingView.tsx    |  2 +-
 .../views/collections/CollectionSchemaView.tsx     |  2 +-
 .../views/collections/CollectionTreeView.tsx       |  8 ++---
 src/client/views/nodes/DocumentView.tsx            | 37 ++++++++++-----------
 src/client/views/nodes/FormattedTextBox.tsx        |  2 +-
 src/client/views/pdf/PDFViewer.tsx                 |  3 +-
 src/client/views/pdf/Page.tsx                      |  9 ++---
 .../views/presentationview/PresentationElement.tsx |  4 +--
 src/client/views/search/SearchItem.tsx             | 38 +++++++---------------
 src/new_fields/Doc.ts                              | 18 ++++++++++
 src/new_fields/util.ts                             |  1 -
 src/scraping/buxton/scraper.py                     |  9 ++---
 13 files changed, 65 insertions(+), 74 deletions(-)

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

diff --git a/src/client/views/SearchItem.tsx b/src/client/views/SearchItem.tsx
index 13e4b88f7..fd4b2420d 100644
--- a/src/client/views/SearchItem.tsx
+++ b/src/client/views/SearchItem.tsx
@@ -37,12 +37,10 @@ export class SearchItem extends React.Component<SearchProps> {
         return <FontAwesomeIcon icon={button} className="documentView-minimizedIcon" />;
     }
     onPointerEnter = (e: React.PointerEvent) => {
-        this.props.doc.libraryBrush = true;
-        Doc.SetOnPrototype(this.props.doc, "protoBrush", true);
+        Doc.BrushDoc(this.props.doc);
     }
     onPointerLeave = (e: React.PointerEvent) => {
-        this.props.doc.libraryBrush = false;
-        Doc.SetOnPrototype(this.props.doc, "protoBrush", false);
+        Doc.UnBrushDoc(this.props.doc);
     }
 
     collectionRef = React.createRef<HTMLDivElement>();
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index f559480ed..3af92cbe3 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -405,7 +405,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
                             handlers: { dragComplete: emptyFunction },
                             hideSource: false
                         });
-                    }}><FontAwesomeIcon icon="file" size="lg" /></span>, dragSpan);
+                    }}><FontAwesomeIcon icon="file" color={["white", "maroon", "blue"][Doc.IsBrushedDegree(doc)]} size="lg" /></span>, dragSpan);
                 ReactDOM.render(<ParentDocSelector Document={doc} addDocTab={doc => CollectionDockingView.Instance.AddTab(stack, doc, dataDoc)} />, upDiv);
                 tab.reactComponents = [dragSpan, upDiv];
                 tab.element.append(dragSpan);
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 75787c0a8..ebfa737be 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -50,7 +50,7 @@ const columnTypes: Map<string, ColumnType> = new Map([
     ["title", ColumnType.String],
     ["x", ColumnType.Number], ["y", ColumnType.Number], ["width", ColumnType.Number], ["height", ColumnType.Number],
     ["nativeWidth", ColumnType.Number], ["nativeHeight", ColumnType.Number], ["isPrototype", ColumnType.Boolean],
-    ["page", ColumnType.Number], ["curPage", ColumnType.Number], ["libraryBrush", ColumnType.Boolean], ["zIndex", ColumnType.Number]
+    ["page", ColumnType.Number], ["curPage", ColumnType.Number], ["zIndex", ColumnType.Number]
 ]);
 
 @observer
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 571967743..24bd24d11 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -127,19 +127,19 @@ class TreeView extends React.Component<TreeViewProps> {
 
     onPointerDown = (e: React.PointerEvent) => e.stopPropagation();
     onPointerEnter = (e: React.PointerEvent): void => {
-        this.props.active() && (this.props.document.libraryBrush = true);
+        this.props.active() && Doc.BrushDoc(this.dataDoc);
         if (e.buttons === 1 && SelectionManager.GetIsDragging()) {
             this._header!.current!.className = "treeViewItem-header";
             document.addEventListener("pointermove", this.onDragMove, true);
         }
     }
     onPointerLeave = (e: React.PointerEvent): void => {
-        this.props.document.libraryBrush = false;
+        Doc.UnBrushDoc(this.dataDoc);
         this._header!.current!.className = "treeViewItem-header";
         document.removeEventListener("pointermove", this.onDragMove, true);
     }
     onDragMove = (e: PointerEvent): void => {
-        this.props.document.libraryBrush = false;
+        Doc.UnBrushDoc(this.dataDoc);
         let x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY);
         let rect = this._header!.current!.getBoundingClientRect();
         let bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
@@ -359,7 +359,7 @@ class TreeView extends React.Component<TreeViewProps> {
         return <>
             <div className="docContainer" id={`docContainer-${this.props.parentKey}`} ref={reference} onPointerDown={onItemDown}
                 style={{
-                    background: BoolCast(this.props.document.libraryBrush) ? "#06121212" : "0",
+                    background: Doc.IsBrushed(this.props.document) ? "#06121212" : "0",
                     outline: BoolCast(this.props.document.workspaceBrush) ? "dashed 1px #06123232" : undefined,
                     pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? "all" : "none"
                 }} >
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index a7b4f33db..e911dc47c 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -303,7 +303,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             fullScreenAlias.showCaption = true;
             this.props.addDocTab(fullScreenAlias, this.dataDoc, "inTab");
             SelectionManager.DeselectAll();
-            this.props.Document.libraryBrush = false;
+            Doc.UnBrushDoc(this.props.Document);
         }
         else if (CurrentUserUtils.MainDocId !== this.props.Document[Id] &&
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
@@ -445,13 +445,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             targetDoc.targetContext = de.data.targetContext;
             let annotations = await DocListCastAsync(annotationDoc.annotations);
             if (annotations) {
-                annotations.forEach(anno => {
-                    anno.target = targetDoc;
-                });
+                annotations.forEach(anno => anno.target = targetDoc);
             }
-            let pdfDoc = await Cast(annotationDoc.pdfDoc, Doc);
-            if (pdfDoc) {
-                DocUtils.MakeLink(annotationDoc, targetDoc, this.props.ContainingCollectionView!.props.Document, `Annotation from ${StrCast(pdfDoc.title)}`, "", StrCast(pdfDoc.title));
+            let annotDoc = await Cast(annotationDoc.annotationOn, Doc);
+            if (annotDoc) {
+                DocUtils.MakeLink(annotationDoc, targetDoc, this.props.ContainingCollectionView!.props.Document, `Annotation from ${StrCast(annotDoc.title)}`, "", StrCast(annotDoc.title));
             }
         }
         if (de.data instanceof DragManager.LinkDragData) {
@@ -647,8 +645,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         });
     }
 
-    onPointerEnter = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = true; };
-    onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; };
+    onPointerEnter = (e: React.PointerEvent): void => { Doc.BrushDoc(this.props.Document); };
+    onPointerLeave = (e: React.PointerEvent): void => { Doc.UnBrushDoc(this.props.Document); };
 
     isSelected = () => SelectionManager.IsSelected(this);
     @action select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); };
@@ -695,22 +693,23 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             });
         }
         let showTextTitle = showTitle && StrCast(this.layoutDoc.layout).startsWith("<FormattedTextBox") ? showTitle : undefined;
+        let brushDegree = Doc.IsBrushedDegree(this.layoutDoc);
         return (
             <div className={`documentView-node${this.topMost ? "-topmost" : ""}`}
                 ref={this._mainCont}
                 style={{
                     pointerEvents: this.layoutDoc.isBackground && !this.isSelected() ? "none" : "all",
                     color: foregroundColor,
-                    outlineColor: "maroon",
-                    outlineStyle: "dashed",
-                    outlineWidth: BoolCast(this.layoutDoc.libraryBrush) && !StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
-                        `${this.props.ScreenToLocalTransform().Scale}px` : "0px",
-                    marginLeft: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
-                        `${-1 * this.props.ScreenToLocalTransform().Scale}px` : undefined,
-                    marginTop: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
-                        `${-1 * this.props.ScreenToLocalTransform().Scale}px` : undefined,
-                    border: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
-                        `dashed maroon ${this.props.ScreenToLocalTransform().Scale}px` : undefined,
+                    outlineColor: ["transparent", "maroon", "maroon"][brushDegree],
+                    outlineStyle: ["none", "dashed", "solid"][brushDegree],
+                    outlineWidth: brushDegree && !StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
+                        `${brushDegree * this.props.ScreenToLocalTransform().Scale}px` : "0px",
+                    marginLeft: brushDegree && StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
+                        `${-brushDegree * this.props.ScreenToLocalTransform().Scale}px` : undefined,
+                    marginTop: brushDegree && StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
+                        `${-brushDegree * this.props.ScreenToLocalTransform().Scale}px` : undefined,
+                    border: brushDegree && StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
+                        `${["none", "dashed", "solid"][brushDegree]} ${["transparent", "maroon", "maroon"][brushDegree]} ${this.props.ScreenToLocalTransform().Scale}px` : undefined,
                     borderRadius: "inherit",
                     background: backgroundColor,
                     width: nativeWidth,
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 9dd0643df..44b5d2c21 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -674,7 +674,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 style={{
                     height: this.props.height ? this.props.height : undefined,
                     background: this.props.hideOnLeave ? "rgba(0,0,0,0.4)" : undefined,
-                    opacity: this.props.hideOnLeave ? (this._entered || this.props.isSelected() || this.props.Document.libraryBrush ? 1 : 0.1) : 1,
+                    opacity: this.props.hideOnLeave ? (this._entered || this.props.isSelected() || Doc.IsBrushed(this.props.Document) ? 1 : 0.1) : 1,
                     color: this.props.color ? this.props.color : this.props.hideOnLeave ? "white" : "inherit",
                     pointerEvents: interactive,
                     fontSize: "13px"
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 95df10c58..7cd62f4e0 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -184,7 +184,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
             annoDoc.color = color;
             annoDoc.type = AnnotationTypes.Region;
             annoDocs.push(annoDoc);
-            annoDoc.isBackground = true;
+            annoDoc.isButton = true;
             anno.remove();
             this.props.addDocument && this.props.addDocument(annoDoc, false);
             mainAnnoDoc = annoDoc;
@@ -208,7 +208,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
             mainAnnoDocProto.y = Math.max(minY, 0);
             mainAnnoDocProto.annotations = new List<Doc>(annoDocs);
         }
-        mainAnnoDocProto.pdfDoc = this.props.Document;
         mainAnnoDocProto.title = "Annotation on " + StrCast(this.props.Document.title);
         mainAnnoDocProto.annotationOn = this.props.Document;
         if (sourceDoc && createLink) {
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index 4986f44d5..6bd98cbaa 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -112,8 +112,8 @@ export default class Page extends React.Component<IPageProps> {
                         if (!BoolCast(annotationDoc.linkedToDoc)) {
                             let annotations = await DocListCastAsync(annotationDoc.annotations);
                             annotations && annotations.forEach(anno => anno.target = targetDoc);
-                            let pdfDoc = await Cast(annotationDoc.pdfDoc, Doc);
-                            pdfDoc && DocUtils.MakeLink(annotationDoc, targetDoc, dragData.targetContext, `Annotation from ${StrCast(pdfDoc.title)}`, "", StrCast(pdfDoc.title))
+                            let parentDoc = await Cast(annotationDoc.annotationOn, Doc);
+                            parentDoc && DocUtils.MakeLink(annotationDoc, targetDoc, dragData.targetContext, `Annotation from ${StrCast(parentDoc.title)}`, "", StrCast(parentDoc.title))
                         }
                     }
                 },
@@ -144,10 +144,7 @@ export default class Page extends React.Component<IPageProps> {
     onPointerDown = (e: React.PointerEvent): void => {
         // if alt+left click, drag and annotate
         if (NumCast(this.props.Document.scale, 1) !== 1) return;
-        if (e.altKey && e.button === 0) {
-            e.stopPropagation();
-        }
-        else if (e.button === 0) {
+        if (!e.altKey && e.button === 0) {
             PDFMenu.Instance.StartDrag = this.startDrag;
             PDFMenu.Instance.Highlight = this.highlight;
             PDFMenu.Instance.Snippet = this.createSnippet;
diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx
index e2d8daea9..d98b66324 100644
--- a/src/client/views/presentationview/PresentationElement.tsx
+++ b/src/client/views/presentationview/PresentationElement.tsx
@@ -706,7 +706,7 @@ export default class PresentationElement extends React.Component<PresentationEle
      * It makes it possible to show dropping lines on drop targets.
      */
     onDragMove = (e: PointerEvent): void => {
-        this.props.document.libraryBrush = false;
+        Doc.UnBrushDoc(this.props.document);
         let x = this.ScreenToLocalListTransform(e.clientX, e.clientY);
         let rect = this.header!.getBoundingClientRect();
         let bounds = this.ScreenToLocalListTransform(rect.left, rect.top + rect.height / 2);
@@ -889,7 +889,7 @@ export default class PresentationElement extends React.Component<PresentationEle
                 style={{
                     outlineColor: "maroon",
                     outlineStyle: "dashed",
-                    outlineWidth: BoolCast(p.document.libraryBrush) ? `1px` : "0px",
+                    outlineWidth: Doc.IsBrushed(p.document) ? `1px` : "0px",
                 }}
                 onClick={e => { p.gotoDocument(p.index, NumCast(this.props.mainDocument.selectedDoc)); e.stopPropagation(); }}>
                 <strong className="presentationView-name">
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index c4af30f5c..8201aa374 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -105,23 +105,11 @@ export interface LinkMenuProps {
 @observer
 export class LinkContextMenu extends React.Component<LinkMenuProps> {
 
-    highlightDoc = (doc: Doc) => {
-        return () => {
-            doc.libraryBrush = true;
-        };
-    }
+    highlightDoc = (doc: Doc) => () => Doc.BrushDoc(doc);
 
-    unHighlightDoc = (doc: Doc) => {
-        return () => {
-            doc.libraryBrush = false;
-        };
-    }
+    unHighlightDoc = (doc: Doc) => () => Doc.UnBrushDoc(doc);
 
-    getOnClick(col: Doc) {
-        return () => {
-            CollectionDockingView.Instance.AddRightSplit(col, undefined);
-        };
-    }
+    getOnClick = (col: Doc) => () => CollectionDockingView.Instance.AddRightSplit(col, undefined);
 
     render() {
         return (
@@ -286,14 +274,12 @@ export class SearchItem extends React.Component<SearchItemProps> {
 
                 let doc1 = Cast(this.props.doc.anchor1, Doc, null);
                 let doc2 = Cast(this.props.doc.anchor2, Doc, null);
-                doc1 && (doc1.libraryBrush = true);
-                doc2 && (doc2.libraryBrush = true);
+                Doc.BrushDoc(doc1);
+                Doc.BrushDoc(doc2);
             }
         } else {
-            let docViews: DocumentView[] = DocumentManager.Instance.getAllDocumentViews(this.props.doc);
-            docViews.forEach(element => {
-                element.props.Document.libraryBrush = true;
-            });
+            DocumentManager.Instance.getAllDocumentViews(this.props.doc).forEach(element =>
+                Doc.BrushDoc(element.props.Document));
         }
     }
 
@@ -303,14 +289,12 @@ export class SearchItem extends React.Component<SearchItemProps> {
 
                 let doc1 = Cast(this.props.doc.anchor1, Doc, null);
                 let doc2 = Cast(this.props.doc.anchor2, Doc, null);
-                doc1 && (doc1.libraryBrush = false);
-                doc2 && (doc2.libraryBrush = false);
+                Doc.UnBrushDoc(doc1);
+                Doc.UnBrushDoc(doc2);
             }
         } else {
-            let docViews: DocumentView[] = DocumentManager.Instance.getAllDocumentViews(this.props.doc);
-            docViews.forEach(element => {
-                element.props.Document.libraryBrush = false;
-            });
+            DocumentManager.Instance.getAllDocumentViews(this.props.doc).
+                forEach(element => Doc.UnBrushDoc(element.props.Document));
         }
     }
 
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index c01f4e8cf..b3d1dc109 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -542,4 +542,22 @@ export namespace Doc {
             }
         });
     }
+
+    export class DocBrush {
+        @observable BrushedDoc: Doc[] = [];
+    }
+    const manager = new DocBrush();
+    export function IsBrushed(doc: Doc) {
+        return manager.BrushedDoc.some(d => Doc.AreProtosEqual(d, doc));
+    }
+    export function IsBrushedDegree(doc: Doc) {
+        return manager.BrushedDoc.some(d => d === doc) ? 2 : Doc.IsBrushed(doc) ? 1 : 0;
+    }
+    export function BrushDoc(doc: Doc) {
+        if (manager.BrushedDoc.indexOf(doc) === -1) runInAction(() => manager.BrushedDoc.push(doc));
+    }
+    export function UnBrushDoc(doc: Doc) {
+        let index = manager.BrushedDoc.indexOf(doc);
+        if (index !== -1) runInAction(() => manager.BrushedDoc.splice(index, 1));
+    }
 }
\ No newline at end of file
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index c6f693f7f..48ae9f216 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -6,7 +6,6 @@ import { RefField } from "./RefField";
 import { ObjectField } from "./ObjectField";
 import { action } from "mobx";
 import { Parent, OnUpdate, Update, Id, SelfProxy, Self } from "./FieldSymbols";
-import { ComputedField } from "./ScriptField";
 
 function _readOnlySetter(): never {
     throw new Error("Documents can't be modified in read-only mode");
diff --git a/src/scraping/buxton/scraper.py b/src/scraping/buxton/scraper.py
index f0f45d8f9..29cb8a256 100644
--- a/src/scraping/buxton/scraper.py
+++ b/src/scraping/buxton/scraper.py
@@ -88,8 +88,7 @@ def write_schema(parse_results, display_fields, storage_key):
             "panX": 0,
             "panY": 0,
             "zoomBasis": 1,
-            "zIndex": 2,
-            "libraryBrush": False,
+            "zIndex": 2
             "viewType": 2
         },
         "__type": "Doc"
@@ -130,8 +129,7 @@ def write_text_doc(content):
             "x": 10,
             "y": 10,
             "width": 400,
-            "zIndex": 2,
-            "libraryBrush": False
+            "zIndex": 2
         },
         "__type": "Doc"
     }
@@ -183,8 +181,7 @@ def write_image(folder, name):
             "x": 10,
             "y": 10,
             "width": min(800, native_width),
-            "zIndex": 2,
-            "libraryBrush": False
+            "zIndex": 2
         },
         "__type": "Doc"
     }
-- 
cgit v1.2.3-70-g09d2

