From 4ea58f2d334485edd1c158ed06b27382e5d68a1c Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 30 Jan 2020 11:32:42 -0500
Subject: support for docs as fields using {{}}.  and added 't' for making a
 template.

---
 src/client/util/RichTextSchema.tsx | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index d1e0f07cb..6821d9858 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -21,6 +21,7 @@ import { FormattedTextBox } from "../views/nodes/FormattedTextBox";
 import { ObjectField } from "../../new_fields/ObjectField";
 import { ComputedField } from "../../new_fields/ScriptField";
 import { observer } from "mobx-react";
+import { Id } from "../../new_fields/FieldSymbols";
 
 const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"],
     preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0];
@@ -759,15 +760,33 @@ export class DashDocView {
             return true;
         };
         const alias = node.attrs.alias;
-        DocServer.GetRefField(node.attrs.docid + alias).then(async dashDoc => {
+
+        const docid = node.attrs.docid || tbox.props.DataDoc?.[Id] || tbox.dataDoc?.[Id];
+        DocServer.GetRefField(docid + alias).then(async dashDoc => {
             if (!(dashDoc instanceof Doc)) {
-                alias && DocServer.GetRefField(node.attrs.docid).then(async dashDocBase => {
+                alias && DocServer.GetRefField(docid).then(async dashDocBase => {
                     if (dashDocBase instanceof Doc) {
-                        self.doRender(Doc.MakeAlias(dashDocBase), removeDoc, node, view, getPos);
+                        if (node.attrs.fieldKey) {
+                            const fieldDoc = await self._textBox.dataDoc[node.attrs.fieldKey];
+                            if (fieldDoc instanceof Doc) {
+                                self.doRender(Doc.MakeAlias(fieldDoc), removeDoc, node, view, getPos);
+                            } else {
+                                this._dashSpan.innerHTML = `field:'${node.attrs.fieldKey}' is not a document`;
+                            }
+                        } else {
+                            self.doRender(Doc.MakeAlias(dashDocBase), removeDoc, node, view, getPos);
+                        }
                     }
                 });
             } else {
-                self.doRender(dashDoc, removeDoc, node, view, getPos);
+                if (node.attrs.fieldKey) {
+                    const fieldDoc = await dashDoc[node.attrs.fieldKey];
+                    if (fieldDoc instanceof Doc) {
+                        self.doRender(fieldDoc, removeDoc, node, view, getPos);
+                    }
+                } else {
+                    self.doRender(dashDoc, removeDoc, node, view, getPos);
+                }
             }
         });
         const self = this;
-- 
cgit v1.2.3-70-g09d2


From fa746ce5faa3f0cd0c1cd53644c6631540284802 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 30 Jan 2020 13:40:32 -0500
Subject: fixes to embedded documents

---
 src/client/util/RichTextSchema.tsx | 24 +++++-------------------
 1 file changed, 5 insertions(+), 19 deletions(-)

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 6821d9858..287a1049b 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -766,27 +766,13 @@ export class DashDocView {
             if (!(dashDoc instanceof Doc)) {
                 alias && DocServer.GetRefField(docid).then(async dashDocBase => {
                     if (dashDocBase instanceof Doc) {
-                        if (node.attrs.fieldKey) {
-                            const fieldDoc = await self._textBox.dataDoc[node.attrs.fieldKey];
-                            if (fieldDoc instanceof Doc) {
-                                self.doRender(Doc.MakeAlias(fieldDoc), removeDoc, node, view, getPos);
-                            } else {
-                                this._dashSpan.innerHTML = `field:'${node.attrs.fieldKey}' is not a document`;
-                            }
-                        } else {
-                            self.doRender(Doc.MakeAlias(dashDocBase), removeDoc, node, view, getPos);
-                        }
+                        const aliasedDoc = Doc.MakeDelegate(dashDocBase, docid + alias);
+                        aliasedDoc.layoutKey = "layout_" + node.attrs.fieldKey;
+                        self.doRender(aliasedDoc, removeDoc, node, view, getPos);
                     }
                 });
             } else {
-                if (node.attrs.fieldKey) {
-                    const fieldDoc = await dashDoc[node.attrs.fieldKey];
-                    if (fieldDoc instanceof Doc) {
-                        self.doRender(fieldDoc, removeDoc, node, view, getPos);
-                    }
-                } else {
-                    self.doRender(dashDoc, removeDoc, node, view, getPos);
-                }
+                self.doRender(dashDoc, removeDoc, node, view, getPos);
             }
         });
         const self = this;
@@ -831,7 +817,7 @@ export class DashDocView {
             }, { fireImmediately: true });
             ReactDOM.render(<DocumentView
                 Document={finalLayout}
-                DataDoc={Doc.AreProtosEqual(this._textBox.Document, dashDoc) ? this._textBox.dataDoc : undefined}
+                DataDoc={!node.attrs.docid ? this._textBox.dataDoc : undefined}
                 LibraryPath={this._textBox.props.LibraryPath}
                 fitToBox={BoolCast(dashDoc._fitToBox)}
                 addDocument={returnFalse}
-- 
cgit v1.2.3-70-g09d2


From f93abfc577225cc04eb94d67c62eec67d7e22bca Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 30 Jan 2020 22:37:44 -0500
Subject: changed hideSidebar to showSidebar.  added contextmenu for choosing
 pivot field.

---
 src/client/documents/Documents.ts                  |  4 +-
 src/client/util/RichTextSchema.tsx                 |  1 -
 src/client/views/ContextMenu.tsx                   |  4 +-
 src/client/views/EditableView.tsx                  | 19 +++++---
 .../views/collections/CollectionPivotView.tsx      | 51 +++++++++++++++++-----
 .../CollectionStackingViewFieldColumn.tsx          |  2 +-
 .../views/collections/CollectionTreeView.tsx       |  1 -
 src/client/views/nodes/FormattedTextBox.tsx        |  6 +--
 8 files changed, 61 insertions(+), 27 deletions(-)

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index fa5707288..49c03a96f 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -75,7 +75,7 @@ export interface DocumentOptions {
     _yMargin?: number; // gap between top edge of dcoument and start of masonry/stacking layouts
     _textTemplate?: RichTextField; // template used by a formattedTextBox to create a text box to render
     _itemIndex?: number; // which item index the carousel viewer is showing
-    _hideSidebar?: boolean;  //whether an annotationsidebar should be displayed for text docuemnts
+    _showSidebar?: boolean;  //whether an annotationsidebar should be displayed for text docuemnts
     x?: number;
     y?: number;
     z?: number;
@@ -340,7 +340,7 @@ export namespace Docs {
     export namespace Create {
 
         const delegateKeys = ["x", "y", "layoutKey", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "_dropAction", "_annotationOn",
-            "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_hideSidebar"];
+            "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar"];
 
         /**
          * This function receives the relevant document prototype and uses
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 287a1049b..9e4f06919 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -790,7 +790,6 @@ export class DashDocView {
     }
     doRender(dashDoc: Doc, removeDoc: any, node: any, view: any, getPos: any) {
         this._dashDoc = dashDoc;
-        dashDoc._hideSidebar = true;
         if (node.attrs.width !== dashDoc._width + "px" || node.attrs.height !== dashDoc._height + "px") {
             try { // bcz: an exception will be thrown if two aliases are open at the same time when a doc view comment is made
                 view.dispatch(view.state.tr.setNodeMarkup(getPos(), null, { ...node.attrs, width: dashDoc._width + "px", height: dashDoc._height + "px" }));
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index ac803d977..4d04d4e89 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -134,13 +134,13 @@ export class ContextMenu extends React.Component {
     }
 
     @action
-    displayMenu = (x: number, y: number) => {
+    displayMenu = (x: number, y: number, initSearch = "") => {
         //maxX and maxY will change if the UI/font size changes, but will work for any amount
         //of items added to the menu
 
         this._pageX = x;
         this._pageY = y;
-        this._searchString = "";
+        this._searchString = initSearch;
         this._shouldDisplay = true;
     }
 
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 780c5b2f4..84c6b0dfd 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -46,6 +46,7 @@ export interface EditableProps {
     onClick?: (e: React.MouseEvent) => boolean;
     isEditingCallback?: (isEditing: boolean) => void;
     menuCallback?: (x: number, y: number) => void;
+    showMenuOnLoad?: boolean;
     HeadingObject?: SchemaHeaderField | undefined;
     HeadingsHack?: number;
     toggle?: () => void;
@@ -77,6 +78,8 @@ export class EditableView extends React.Component<EditableProps> {
         }
     }
 
+    _didShow = false;
+
     @action
     onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
         if (e.key === "Tab") {
@@ -97,16 +100,20 @@ export class EditableView extends React.Component<EditableProps> {
             this._editing = false;
             this.props.isEditingCallback?.(false);
         } else if (e.key === ":") {
-            this.props.menuCallback?.(e.currentTarget.offsetLeft, e.currentTarget.offsetTop);
+            this.props.menuCallback?.(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y);
         }
     }
 
     @action
     onClick = (e: React.MouseEvent) => {
         e.nativeEvent.stopPropagation();
-        if (!this.props.onClick || !this.props.onClick(e)) {
-            this._editing = true;
-            this.props.isEditingCallback?.(true);
+        if (this._ref.current && this.props.showMenuOnLoad) {
+            this.props.menuCallback?.(this._ref.current.getBoundingClientRect().x, this._ref.current.getBoundingClientRect().y);
+        } else {
+            if (!this.props.onClick || !this.props.onClick(e)) {
+                this._editing = true;
+                this.props.isEditingCallback?.(true);
+            }
         }
         e.stopPropagation();
     }
@@ -130,6 +137,7 @@ export class EditableView extends React.Component<EditableProps> {
         return wasFocused !== this._editing;
     }
 
+    _ref = React.createRef<HTMLDivElement>();
     render() {
         if (this._editing && this.props.GetValue() !== undefined) {
             return this.props.autosuggestProps
@@ -156,9 +164,10 @@ export class EditableView extends React.Component<EditableProps> {
                     style={{ display: this.props.display, fontSize: this.props.fontSize }}
                 />;
         } else {
-            if (this.props.autosuggestProps) this.props.autosuggestProps.resetValue();
+            this.props.autosuggestProps?.resetValue();
             return (this.props.contents instanceof ObjectField ? (null) :
                 <div className={`editableView-container-editing${this.props.oneLine ? "-oneLine" : ""}`}
+                    ref={this._ref}
                     style={{ display: this.props.display, minHeight: "20px", height: `${this.props.height ? this.props.height : "auto"}`, maxHeight: `${this.props.maxHeight}` }}
                     onClick={this.onClick}>
                     <span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize }}>{this.props.contents}</span>
diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx
index 440b6856b..1a84a34a0 100644
--- a/src/client/views/collections/CollectionPivotView.tsx
+++ b/src/client/views/collections/CollectionPivotView.tsx
@@ -16,6 +16,10 @@ import "./CollectionPivotView.scss";
 import { CollectionSubView } from "./CollectionSubView";
 import { CollectionTreeView } from "./CollectionTreeView";
 import React = require("react");
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
+import { RichTextField } from "../../../new_fields/RichTextField";
+import { ImageField } from "../../../new_fields/URLField";
 
 @observer
 export class CollectionPivotView extends CollectionSubView(doc => doc) {
@@ -36,7 +40,7 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) {
         }
     }
     bodyPanelWidth = () => this.props.PanelWidth() - this._facetWidth;
-    getTransform = () => this.props.ScreenToLocalTransform().translate(-200, 0);
+    getTransform = () => this.props.ScreenToLocalTransform().translate(-this._facetWidth, 0);
 
     @computed get _allFacets() {
         const facets = new Set<string>();
@@ -98,6 +102,25 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) {
         document.removeEventListener("pointerup", this.onPointerUp);
     }
 
+    menuCallback = (x: number, y: number) => {
+        ContextMenu.Instance.clearItems();
+        const docItems: ContextMenuProps[] = [];
+        const keySet: Set<string> = new Set();
+
+        this.childLayoutPairs.map(pair =>
+            Array.from(Object.keys(Doc.GetProto(pair.layout))).filter(fieldKey => pair.layout[fieldKey] instanceof RichTextField || typeof (pair.layout[fieldKey]) === "string").map(fieldKey =>
+                keySet.add(fieldKey)));
+        keySet.toArray().map(fieldKey =>
+            docItems.push({ description: ":" + fieldKey, event: () => this.props.Document.pivotField = fieldKey, icon: "compress-arrows-alt" }));
+        docItems.push({ description: ":(null)", event: () => this.props.Document.pivotField = undefined, icon: "compress-arrows-alt" })
+        ContextMenu.Instance.addItem({ description: "Pivot Fields ...", subitems: docItems, icon: "eye" });
+        const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y);
+        ContextMenu.Instance.displayMenu(x, y, ":");
+    }
+
+    @observable private collapsed: boolean = false;
+    private toggleVisibility = action(() => this.collapsed = !this.collapsed);
+
     render() {
         const facetCollection = Cast(this.props.Document?._facetCollection, Doc, null);
         const flyout = (
@@ -109,20 +132,24 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) {
                 </label>)}
             </div>
         );
+        const newEditableViewProps = {
+            GetValue: () => "",
+            SetValue: (value: any) => {
+                if (value?.length) {
+                    this.props.Document.pivotField = value;
+                    return true;
+                }
+                return false;
+            },
+            showMenuOnLoad: true,
+            contents: ":" + StrCast(this.props.Document.pivotField),
+            toggle: this.toggleVisibility,
+            color: "#f1efeb" // this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
+        };
         return !facetCollection ? (null) :
             <div className="collectionPivotView" style={{ height: `calc(100%  - ${this.props.Document._chromeStatus === "enabled" ? 51 : 0}px)` }}>
                 <div className={"pivotKeyEntry"}>
-                    <EditableView
-                        contents={this.props.Document.pivotField}
-                        GetValue={() => StrCast(this.props.Document.pivotField)}
-                        SetValue={value => {
-                            if (value && value.length) {
-                                this.props.Document.pivotField = value;
-                                return true;
-                            }
-                            return false;
-                        }}
-                    />
+                    <EditableView {...newEditableViewProps} menuCallback={this.menuCallback} />
                 </div>
                 <div className="collectionPivotView-dragger" key="dragger" onPointerDown={this.onPointerDown} style={{ transform: `translate(${this._facetWidth}px, 0px)` }} >
                     <span title="library View Dragger" style={{ width: "5px", position: "absolute", top: "0" }} />
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 2a9f903bb..d00ddde6a 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -312,7 +312,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
             }
         });
         const pt = this.props.screenToLocalTransform().inverse().transformPoint(x, y);
-        ContextMenu.Instance.displayMenu(pt[0], pt[1]);
+        ContextMenu.Instance.displayMenu(x, y);
     }
 
     render() {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index a7733ab5f..6cc2d6586 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -636,7 +636,6 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                         if (caption instanceof ObjectField) {
                             Doc.GetProto(img).caption = ObjectField.MakeCopy(caption as ObjectField);
                         }
-                        img._hideSidebar = true;
                         d.captions = undefined;
                     });
                 });
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 0d97c3029..675f72011 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -379,7 +379,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
 
     specificContextMenu = (e: React.MouseEvent): void => {
         const funcs: ContextMenuProps[] = [];
-        funcs.push({ description: "Toggle Sidebar", event: () => { e.stopPropagation(); this.toggleSidebar(); }, icon: "expand-arrows-alt" });
+        funcs.push({ description: "Toggle Sidebar", event: () => { e.stopPropagation(); this.props.Document._showSidebar = !this.props.Document._showSidebar }, icon: "expand-arrows-alt" });
         funcs.push({ description: "Record Bullet", event: () => { e.stopPropagation(); this.recordBullet(); }, icon: "expand-arrows-alt" });
         ["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option =>
             funcs.push({
@@ -1101,7 +1101,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
                 <div className={`formattedTextBox-outer`} style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, }} ref={this._scrollRef}>
                     <div className={`formattedTextBox-inner${rounded}`} style={{ whiteSpace: "pre-wrap", pointerEvents: ((this.Document.isButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined }} ref={this.createDropTarget} />
                 </div>
-                {this.props.Document._hideSidebar ? (null) : this.sidebarWidthPercent === "0%" ?
+                {this.props.Document._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ?
                     <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} onClick={e => this.toggleSidebar()} /> :
                     <div className={"formattedTextBox-sidebar" + (InkingControl.Instance.selectedTool !== InkTool.None ? "-inking" : "")}
                         style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
@@ -1118,7 +1118,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
                             whenActiveChanged={this.whenActiveChanged}
                             removeDocument={this.removeDocument}
                             moveDocument={this.moveDocument}
-                            addDocument={(doc: Doc) => { doc._hideSidebar = true; return this.addDocument(doc); }}
+                            addDocument={(doc: Doc) => { doc._showSidebar = false; return this.addDocument(doc); }}
                             CollectionView={undefined}
                             ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth), 0)}
                             renderDepth={this.props.renderDepth + 1}
-- 
cgit v1.2.3-70-g09d2

