From 5c6dc8fb25c2ac65a9efa534ee86211ac6d68301 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Fri, 8 Nov 2019 15:14:56 -0500
Subject: moved schemaPreview into ContentFittingDOcumentView.  fixed dragging
 link anchors

---
 .../views/nodes/ContentFittingDocumentView.tsx     | 117 +++++++++++++++++++++
 1 file changed, 117 insertions(+)
 create mode 100644 src/client/views/nodes/ContentFittingDocumentView.tsx

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

diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
new file mode 100644
index 000000000..f41c4fc91
--- /dev/null
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -0,0 +1,117 @@
+import React = require("react");
+import { action, computed } from "mobx";
+import { observer } from "mobx-react";
+import "react-table/react-table.css";
+import { Doc } from "../../../new_fields/Doc";
+import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
+import { NumCast, StrCast } from "../../../new_fields/Types";
+import { emptyFunction, returnEmptyString, returnOne } from "../../../Utils";
+import { DragManager } from "../../util/DragManager";
+import { Transform } from "../../util/Transform";
+import { undoBatch } from "../../util/UndoManager";
+import '../DocumentDecorations.scss';
+import { DocumentView } from "../nodes/DocumentView";
+import "./ContentFittingDocumentView.scss";
+import { CollectionView } from "../collections/CollectionView";
+
+interface ContentFittingDocumentViewProps {
+    Document?: Doc;
+    DataDocument?: Doc;
+    childDocs?: Doc[];
+    renderDepth: number;
+    fitToBox?: boolean;
+    fieldKey: string;
+    PanelWidth: () => number;
+    PanelHeight: () => number;
+    ruleProvider: Doc | undefined;
+    focus?: (doc: Doc) => void;
+    showOverlays?: (doc: Doc) => { title?: string, caption?: string };
+    CollectionView?: CollectionView;
+    CollectionDoc?: Doc;
+    onClick?: ScriptField;
+    getTransform: () => Transform;
+    addDocument: (document: Doc) => boolean;
+    moveDocument: (document: Doc, target: Doc, addDoc: ((doc: Doc) => boolean)) => boolean;
+    removeDocument: (document: Doc) => boolean;
+    active: () => boolean;
+    whenActiveChanged: (isActive: boolean) => void;
+    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    pinToPres: (document: Doc) => void;
+    setPreviewScript: (script: string) => void;
+    previewScript?: string;
+}
+
+@observer
+export class ContentFittingDocumentView extends React.Component<ContentFittingDocumentViewProps>{
+    private get layoutDoc() { return this.props.Document && Doc.Layout(this.props.Document); }
+    private get nativeWidth() { return NumCast(this.layoutDoc!.nativeWidth, this.props.PanelWidth()); }
+    private get nativeHeight() { return NumCast(this.layoutDoc!.nativeHeight, this.props.PanelHeight()); }
+    private contentScaling = () => {
+        let wscale = this.props.PanelWidth() / (this.nativeWidth ? this.nativeWidth : this.props.PanelWidth());
+        if (wscale * this.nativeHeight > this.props.PanelHeight()) {
+            return this.props.PanelHeight() / (this.nativeHeight ? this.nativeHeight : this.props.PanelHeight());
+        }
+        return wscale;
+    }
+
+    @undoBatch
+    @action
+    drop = (e: Event, de: DragManager.DropEvent) => {
+        if (de.data instanceof DragManager.DocumentDragData) {
+            this.props.childDocs && this.props.childDocs.map(otherdoc => {
+                let target = Doc.GetProto(otherdoc);
+                target.layout = ComputedField.MakeFunction("this.image_data[0]");
+                target.layoutCustom = Doc.MakeDelegate(de.data.draggedDocuments[0]);
+            });
+            e.stopPropagation();
+        }
+        return true;
+    }
+    private PanelWidth = () => this.nativeWidth && (!this.props.Document || !this.props.Document.fitWidth) ? this.nativeWidth * this.contentScaling() : this.props.PanelWidth();
+    private PanelHeight = () => this.nativeHeight && (!this.props.Document || !this.props.Document.fitWidth) ? this.nativeHeight * this.contentScaling() : this.props.PanelHeight();
+    private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, 0).scale(1 / this.contentScaling());
+    private get centeringOffset() { return this.nativeWidth && (!this.props.Document || !this.props.Document.fitWidth) ? (this.props.PanelWidth() - this.nativeWidth * this.contentScaling()) / 2 : 0; }
+
+    @computed get borderRounding() { return StrCast(this.props.Document!.borderRounding); }
+
+    render() {
+        return (<div className="contentFittingDocumentView" style={{ width: this.props.PanelWidth(), height: this.props.PanelHeight() }}>
+            {!this.props.Document || !this.props.PanelWidth ? (null) : (
+                <div className="contentFittingDocumentView-previewDoc"
+                    style={{
+                        transform: `translate(${this.centeringOffset}px, 0px)`,
+                        borderRadius: this.borderRounding,
+                        height: this.props.PanelHeight(),
+                        width: this.props.PanelWidth()
+                    }}>
+                    <DocumentView {...this.props}
+                        DataDoc={this.props.DataDocument}
+                        Document={this.props.Document}
+                        fitToBox={this.props.fitToBox}
+                        onClick={this.props.onClick}
+                        ruleProvider={this.props.ruleProvider}
+                        showOverlays={this.props.showOverlays}
+                        addDocument={this.props.addDocument}
+                        removeDocument={this.props.removeDocument}
+                        moveDocument={this.props.moveDocument}
+                        whenActiveChanged={this.props.whenActiveChanged}
+                        ContainingCollectionView={this.props.CollectionView}
+                        ContainingCollectionDoc={this.props.CollectionDoc}
+                        addDocTab={this.props.addDocTab}
+                        pinToPres={this.props.pinToPres}
+                        parentActive={this.props.active}
+                        ScreenToLocalTransform={this.getTransform}
+                        renderDepth={this.props.renderDepth + 1}
+                        ContentScaling={this.contentScaling}
+                        PanelWidth={this.PanelWidth}
+                        PanelHeight={this.PanelHeight}
+                        focus={this.props.focus || emptyFunction}
+                        backgroundColor={returnEmptyString}
+                        bringToFront={emptyFunction}
+                        zoomToScale={emptyFunction}
+                        getScale={returnOne}
+                    />
+                </div>)}
+        </div>);
+    }
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 76411ba009c4265751431d255ab3cc9a3cfab69f Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 12 Nov 2019 21:28:39 -0500
Subject: switched link preview to be a document view

---
 src/client/util/RichTextSchema.tsx                 |  1 -
 .../views/nodes/ContentFittingDocumentView.tsx     |  2 +
 src/client/views/nodes/DocumentView.tsx            |  6 ++-
 src/client/views/nodes/FormattedTextBoxComment.tsx | 62 +++++++++++++++++-----
 4 files changed, 54 insertions(+), 17 deletions(-)

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

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 76b8aeaa1..1004cb3d4 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -18,7 +18,6 @@ import { Transform } from "./Transform";
 import React = require("react");
 import { BoolCast, NumCast } from "../../new_fields/Types";
 import { FormattedTextBox } from "../views/nodes/FormattedTextBox";
-import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
 
 const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"],
     preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0];
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index f41c4fc91..751355403 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -37,6 +37,7 @@ interface ContentFittingDocumentViewProps {
     whenActiveChanged: (isActive: boolean) => void;
     addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
     pinToPres: (document: Doc) => void;
+    dontRegisterView?: boolean;
     setPreviewScript: (script: string) => void;
     previewScript?: string;
 }
@@ -108,6 +109,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         focus={this.props.focus || emptyFunction}
                         backgroundColor={returnEmptyString}
                         bringToFront={emptyFunction}
+                        dontRegisterView={this.props.dontRegisterView}
                         zoomToScale={emptyFunction}
                         getScale={returnOne}
                     />
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 93052ea73..4fbb0516f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -74,6 +74,7 @@ export interface DocumentViewProps {
     getScale: () => number;
     animateBetweenIcon?: (maximize: boolean, target: number[]) => void;
     ChromeHeight?: () => number;
+    dontRegisterView?: boolean;
     layoutKey?: string;
 }
 
@@ -98,7 +99,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     @action
     componentDidMount() {
         this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } }));
-        DocumentManager.Instance.DocumentViews.push(this);
+
+        !this.props.dontRegisterView && DocumentManager.Instance.DocumentViews.push(this);
     }
 
     @action
@@ -111,7 +113,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     componentWillUnmount() {
         this._dropDisposer && this._dropDisposer();
         Doc.UnBrushDoc(this.props.Document);
-        DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1);
+        !this.props.dontRegisterView && DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1);
     }
 
     startDragging(x: number, y: number, dropAction: dropActionType, applyAsTemplate?: boolean) {
diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx
index f35ca502f..98cd17972 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/FormattedTextBoxComment.tsx
@@ -2,16 +2,19 @@ import { Plugin, EditorState } from "prosemirror-state";
 import './FormattedTextBoxComment.scss';
 import { ResolvedPos, Mark } from "prosemirror-model";
 import { EditorView } from "prosemirror-view";
-import { Doc } from "../../../new_fields/Doc";
+import { Doc, WidthSym } from "../../../new_fields/Doc";
 import { schema } from "../../util/RichTextSchema";
 import { DocServer } from "../../DocServer";
-import { Utils } from "../../../Utils";
-import { StrCast, Cast, FieldValue } from "../../../new_fields/Types";
+import { Utils, returnTrue, returnFalse, emptyFunction, returnEmptyString, returnOne } from "../../../Utils";
+import { StrCast, Cast, FieldValue, NumCast } from "../../../new_fields/Types";
 import { FormattedTextBox } from "./FormattedTextBox";
-import { DocUtils } from "../../documents/Documents";
-import { isBuffer } from "util";
 import { DocumentManager } from "../../util/DocumentManager";
 import { DocumentType } from "../../documents/DocumentTypes";
+import { DocumentView } from "./DocumentView";
+import React = require("react");
+import * as ReactDOM from 'react-dom';
+import { Transform } from "../../util/Transform";
+import { ContentFittingDocumentView } from "./ContentFittingDocumentView";
 
 export let formattedTextBoxCommentPlugin = new Plugin({
     view(editorView) { return new FormattedTextBoxComment(editorView); }
@@ -67,22 +70,28 @@ export class FormattedTextBoxComment {
             FormattedTextBoxComment.tooltip.className = "FormattedTextBox-tooltip";
             FormattedTextBoxComment.tooltip.style.pointerEvents = "all";
             FormattedTextBoxComment.tooltip.style.maxWidth = "350px";
+            FormattedTextBoxComment.tooltip.style.maxHeight = "250px";
+            FormattedTextBoxComment.tooltip.style.width = "100%";
+            FormattedTextBoxComment.tooltip.style.height = "100%";
+            FormattedTextBoxComment.tooltip.style.overflow = "hidden";
+            FormattedTextBoxComment.tooltip.style.display = "none";
             FormattedTextBoxComment.tooltip.appendChild(input);
             FormattedTextBoxComment.tooltip.onpointerdown = (e: PointerEvent) => {
                 let keep = e.target && (e.target as any).type === "checkbox" ? true : false;
-                if (FormattedTextBoxComment.linkDoc && !keep && FormattedTextBoxComment.textBox) {
-                    DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, FormattedTextBoxComment.textBox.props.Document,
-                        (doc: Doc, maxLocation: string) => FormattedTextBoxComment.textBox!.props.addDocTab(doc, undefined, e.ctrlKey ? "inTab" : "onRight"));
+                const textBox = FormattedTextBoxComment.textBox;
+                if (FormattedTextBoxComment.linkDoc && !keep && textBox) {
+                    DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document,
+                        (doc: Doc, maxLocation: string) => textBox.props.addDocTab(doc, undefined, e.ctrlKey ? "inTab" : "onRight"));
                 }
                 FormattedTextBoxComment.opened = keep || !FormattedTextBoxComment.opened;
-                FormattedTextBoxComment.textBox && FormattedTextBoxComment.start !== undefined && FormattedTextBoxComment.textBox.setAnnotation(
+                textBox && FormattedTextBoxComment.start !== undefined && textBox.setAnnotation(
                     FormattedTextBoxComment.start, FormattedTextBoxComment.end, FormattedTextBoxComment.mark,
                     FormattedTextBoxComment.opened, keep);
                 e.stopPropagation();
             };
             root && root.appendChild(FormattedTextBoxComment.tooltip);
         }
-        this.update(view, undefined);
+        //this.update(view, undefined);
     }
 
     public static Hide() {
@@ -144,9 +153,34 @@ export class FormattedTextBoxComment {
                         if (linkDoc instanceof Doc) {
                             FormattedTextBoxComment.linkDoc = linkDoc;
                             let target = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.props.Document) ? Cast(linkDoc.anchor2, Doc) : Cast(linkDoc.anchor1, Doc));
-                            let ext = (target && target.type !== DocumentType.PDFANNO && Doc.fieldExtensionDoc(target, "data")) || target; // try guessing that the target doc's data is in the 'data' field.  probably need an 'overviewLayout' and then just display the target Document ....
-                            let text = ext && StrCast(ext.text);
-                            ext && (FormattedTextBoxComment.tooltipText.textContent = (target && target.type === DocumentType.PDFANNO ? "Quoted from " : "") + "=> " + (text || StrCast(ext.title)));
+                            try {
+                                ReactDOM.unmountComponentAtNode(FormattedTextBoxComment.tooltipText);
+                            } catch (e) {
+
+                            }
+                            target && ReactDOM.render(<ContentFittingDocumentView
+                                fitToBox={true}
+                                Document={target}
+                                fieldKey={"data"}
+                                moveDocument={returnFalse}
+                                getTransform={Transform.Identity}
+                                active={returnFalse}
+                                setPreviewScript={returnEmptyString}
+                                addDocument={returnFalse}
+                                removeDocument={returnFalse}
+                                ruleProvider={undefined}
+                                addDocTab={returnFalse}
+                                pinToPres={returnFalse}
+                                dontRegisterView={true}
+                                renderDepth={1}
+                                PanelWidth={() => 350}
+                                PanelHeight={() => 250}
+                                focus={emptyFunction}
+                                whenActiveChanged={returnFalse}
+                            />, FormattedTextBoxComment.tooltipText);
+                            // let ext = (target && target.type !== DocumentType.PDFANNO && Doc.fieldExtensionDoc(target, "data")) || target; // try guessing that the target doc's data is in the 'data' field.  probably need an 'overviewLayout' and then just display the target Document ....
+                            // let text = ext && StrCast(ext.text);
+                            // ext && (FormattedTextBoxComment.tooltipText.textContent = (target && target.type === DocumentType.PDFANNO ? "Quoted from " : "") + "=> " + (text || StrCast(ext.title)));
                         }
                     });
                 }
@@ -168,5 +202,5 @@ export class FormattedTextBoxComment {
         FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = set);
     }
 
-    destroy() { FormattedTextBoxComment.tooltip.style.display = "none"; }
+    destroy() { }//FormattedTextBoxComment.tooltip.style.display = "none"; }
 }
-- 
cgit v1.2.3-70-g09d2


From a93ee99c9dd3b5ecc5160f98f9dffeb119b4dcce Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 13 Nov 2019 13:46:23 -0500
Subject: fixed recentlyClosed on startup and added clearAll.  fixed textbox
 comment layout a bit.

---
 src/client/util/SearchUtil.ts                      |  7 ++-
 .../views/collections/CollectionStackingView.tsx   |  1 -
 .../views/collections/CollectionTreeView.tsx       | 13 ++--
 .../views/nodes/ContentFittingDocumentView.tsx     |  1 -
 src/client/views/nodes/FormattedTextBox.tsx        |  5 +-
 .../views/nodes/FormattedTextBoxComment.scss       |  1 -
 src/client/views/nodes/FormattedTextBoxComment.tsx | 71 +++++++++++-----------
 .../views/presentationview/PresElementBox.tsx      |  1 -
 .../authentication/models/current_user_utils.ts    |  2 +
 9 files changed, 56 insertions(+), 46 deletions(-)

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

diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index 6706dcb89..2cf13680a 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -28,6 +28,7 @@ export namespace SearchUtil {
         start?: number;
         rows?: number;
         fq?: string;
+        allowAliases?: boolean;
     }
     export function Search(query: string, returnDocs: true, options?: SearchParams): Promise<DocSearchResult>;
     export function Search(query: string, returnDocs: false, options?: SearchParams): Promise<IdSearchResult>;
@@ -73,7 +74,7 @@ export namespace SearchUtil {
         const docs = ids.map((id: string) => docMap[id]).map(doc => doc as Doc);
         for (let i = 0; i < ids.length; i++) {
             let testDoc = docs[i];
-            if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1) {
+            if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && (options.allowAliases || theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1)) {
                 theDocs.push(testDoc);
                 theLines.push([]);
             }
@@ -88,9 +89,9 @@ export namespace SearchUtil {
         const proto = Doc.GetProto(doc);
         const protoId = proto[Id];
         if (returnDocs) {
-            return (await Search("", returnDocs, { fq: `proto_i:"${protoId}"` })).docs;
+            return (await Search("", returnDocs, { fq: `proto_i:"${protoId}"`, allowAliases: true })).docs;
         } else {
-            return (await Search("", returnDocs, { fq: `proto_i:"${protoId}"` })).ids;
+            return (await Search("", returnDocs, { fq: `proto_i:"${protoId}"`, allowAliases: true })).ids;
         }
         // return Search(`{!join from=id to=proto_i}id:${protoId}`, true);
     }
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 15033e51a..be3bfca0a 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -168,7 +168,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         return <ContentFittingDocumentView
             Document={doc}
             DataDocument={dataDoc}
-            fieldKey={this.props.fieldKey}
             showOverlays={this.overlays}
             renderDepth={this.props.renderDepth}
             ruleProvider={this.props.Document.isRuleProvider && layoutDoc.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 8726726bb..0e3f0d1a9 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -23,7 +23,6 @@ import { EditableView } from "../EditableView";
 import { MainView } from '../MainView';
 import { KeyValueBox } from '../nodes/KeyValueBox';
 import { Templates } from '../Templates';
-import { CollectionViewType } from './CollectionView';
 import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView';
 import { CollectionSubView } from "./CollectionSubView";
 import "./CollectionTreeView.scss";
@@ -177,8 +176,10 @@ class TreeView extends React.Component<TreeViewProps> {
     />)
 
     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 && this.props.document !== CurrentUserUtils.UserDocument.workspaces) {
+        if (!e.isPropagationStopped()) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view
+            if (this.props.document === CurrentUserUtils.UserDocument.recentlyClosed) {
+                ContextMenu.Instance.addItem({ description: "Clear All", event: () => Doc.GetProto(CurrentUserUtils.UserDocument.recentlyClosed as Doc).data = new List<Doc>(), icon: "plus" });
+            } else if (this.props.document !== CurrentUserUtils.UserDocument.workspaces) {
                 ContextMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.document), icon: "tv" });
                 ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, this.templateDataDoc, "inTab"), icon: "folder" });
                 ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, this.templateDataDoc, "onRight"), icon: "caret-square-right" });
@@ -317,7 +318,6 @@ class TreeView extends React.Component<TreeViewProps> {
                 <ContentFittingDocumentView
                     Document={layoutDoc}
                     DataDocument={this.templateDataDoc}
-                    fieldKey={this.fieldKey}
                     renderDepth={this.props.renderDepth}
                     showOverlays={this.noOverlays}
                     ruleProvider={this.props.document.isRuleProvider && layoutDoc.type !== DocumentType.TEXT ? this.props.document : this.props.ruleProvider}
@@ -538,6 +538,11 @@ export class CollectionTreeView extends CollectionSubView(Document) {
             e.stopPropagation();
             e.preventDefault();
             ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
+        } else if (!e.isPropagationStopped() && this.props.Document === CurrentUserUtils.UserDocument.recentlyClosed) {
+            ContextMenu.Instance.addItem({ description: "Clear All", event: () => CurrentUserUtils.UserDocument.recentlyClosed = new List<Doc>(), icon: "plus" });
+            e.stopPropagation();
+            e.preventDefault();
+            ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
         } else {
             let layoutItems: ContextMenuProps[] = [];
             layoutItems.push({ description: this.props.Document.preventTreeViewOpen ? "Persist Treeview State" : "Abandon Treeview State", event: () => this.props.Document.preventTreeViewOpen = !this.props.Document.preventTreeViewOpen, icon: "paint-brush" });
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 751355403..c8255b6fe 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -20,7 +20,6 @@ interface ContentFittingDocumentViewProps {
     childDocs?: Doc[];
     renderDepth: number;
     fitToBox?: boolean;
-    fieldKey: string;
     PanelWidth: () => number;
     PanelHeight: () => number;
     ruleProvider: Doc | undefined;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 65a51b357..8b1e65663 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -843,7 +843,10 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
     }
 
     onPointerUp = (e: React.PointerEvent): void => {
-        if (!(e.nativeEvent as any).formattedHandled) { FormattedTextBoxComment.textBox = this; }
+        if (!(e.nativeEvent as any).formattedHandled) {
+            FormattedTextBoxComment.textBox = this;
+            FormattedTextBoxComment.update(this._editorView!);
+        }
         (e.nativeEvent as any).formattedHandled = true;
 
         if (e.buttons === 1 && this.props.isSelected() && !e.altKey) {
diff --git a/src/client/views/nodes/FormattedTextBoxComment.scss b/src/client/views/nodes/FormattedTextBoxComment.scss
index 792cee182..2dd63ec21 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.scss
+++ b/src/client/views/nodes/FormattedTextBoxComment.scss
@@ -5,7 +5,6 @@
     background: white;
     border: 1px solid silver;
     border-radius: 2px;
-    padding: 2px 10px;
     margin-bottom: 7px;
     -webkit-transform: translateX(-50%);
     transform: translateX(-50%);
diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx
index 98cd17972..29b4b6383 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/FormattedTextBoxComment.tsx
@@ -1,20 +1,18 @@
-import { Plugin, EditorState } from "prosemirror-state";
-import './FormattedTextBoxComment.scss';
-import { ResolvedPos, Mark } from "prosemirror-model";
+import { Mark, ResolvedPos } from "prosemirror-model";
+import { EditorState, Plugin } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
-import { Doc, WidthSym } from "../../../new_fields/Doc";
-import { schema } from "../../util/RichTextSchema";
+import * as ReactDOM from 'react-dom';
+import { Doc } from "../../../new_fields/Doc";
+import { Cast, FieldValue, NumCast } from "../../../new_fields/Types";
+import { emptyFunction, returnEmptyString, returnFalse, Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
-import { Utils, returnTrue, returnFalse, emptyFunction, returnEmptyString, returnOne } from "../../../Utils";
-import { StrCast, Cast, FieldValue, NumCast } from "../../../new_fields/Types";
-import { FormattedTextBox } from "./FormattedTextBox";
 import { DocumentManager } from "../../util/DocumentManager";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { DocumentView } from "./DocumentView";
-import React = require("react");
-import * as ReactDOM from 'react-dom';
+import { schema } from "../../util/RichTextSchema";
 import { Transform } from "../../util/Transform";
 import { ContentFittingDocumentView } from "./ContentFittingDocumentView";
+import { FormattedTextBox } from "./FormattedTextBox";
+import './FormattedTextBoxComment.scss';
+import React = require("react");
 
 export let formattedTextBoxCommentPlugin = new Plugin({
     view(editorView) { return new FormattedTextBoxComment(editorView); }
@@ -107,7 +105,7 @@ export class FormattedTextBoxComment {
         FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "");
     }
 
-    update(view: EditorView, lastState?: EditorState) {
+    static update(view: EditorView, lastState?: EditorState) {
         let state = view.state;
         // Don't do anything if the document/selection didn't change
         if (lastState && lastState.doc.eq(state.doc) &&
@@ -122,6 +120,8 @@ export class FormattedTextBoxComment {
         }
         let set = "none";
         let nbef = 0;
+        FormattedTextBoxComment.tooltip.style.width = "";
+        FormattedTextBoxComment.tooltip.style.height = "";
         // this section checks to see if the insertion point is over text entered by a different user.  If so, it sets ths comment text to indicate the user and the modification date
         if (state.selection.$from) {
             nbef = findStartOfMark(state.selection.$from, view, findOtherUserMark);
@@ -152,32 +152,35 @@ export class FormattedTextBoxComment {
                     docTarget && DocServer.GetRefField(docTarget).then(linkDoc => {
                         if (linkDoc instanceof Doc) {
                             FormattedTextBoxComment.linkDoc = linkDoc;
-                            let target = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.props.Document) ? Cast(linkDoc.anchor2, Doc) : Cast(linkDoc.anchor1, Doc));
+                            const target = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.props.Document) ? Cast(linkDoc.anchor2, Doc) : Cast(linkDoc.anchor1, Doc));
                             try {
                                 ReactDOM.unmountComponentAtNode(FormattedTextBoxComment.tooltipText);
                             } catch (e) {
 
                             }
-                            target && ReactDOM.render(<ContentFittingDocumentView
-                                fitToBox={true}
-                                Document={target}
-                                fieldKey={"data"}
-                                moveDocument={returnFalse}
-                                getTransform={Transform.Identity}
-                                active={returnFalse}
-                                setPreviewScript={returnEmptyString}
-                                addDocument={returnFalse}
-                                removeDocument={returnFalse}
-                                ruleProvider={undefined}
-                                addDocTab={returnFalse}
-                                pinToPres={returnFalse}
-                                dontRegisterView={true}
-                                renderDepth={1}
-                                PanelWidth={() => 350}
-                                PanelHeight={() => 250}
-                                focus={emptyFunction}
-                                whenActiveChanged={returnFalse}
-                            />, FormattedTextBoxComment.tooltipText);
+                            if (target) {
+                                ReactDOM.render(<ContentFittingDocumentView
+                                    fitToBox={true}
+                                    Document={target}
+                                    moveDocument={returnFalse}
+                                    getTransform={Transform.Identity}
+                                    active={returnFalse}
+                                    setPreviewScript={returnEmptyString}
+                                    addDocument={returnFalse}
+                                    removeDocument={returnFalse}
+                                    ruleProvider={undefined}
+                                    addDocTab={returnFalse}
+                                    pinToPres={returnFalse}
+                                    dontRegisterView={true}
+                                    renderDepth={1}
+                                    PanelWidth={() => Math.min(350, NumCast(target.width, 350))}
+                                    PanelHeight={() => Math.min(250, NumCast(target.height, 250))}
+                                    focus={emptyFunction}
+                                    whenActiveChanged={returnFalse}
+                                />, FormattedTextBoxComment.tooltipText);
+                                FormattedTextBoxComment.tooltip.style.width = NumCast(target.width) ? `${NumCast(target.width)}` : "100%";
+                                FormattedTextBoxComment.tooltip.style.height = NumCast(target.height) ? `${NumCast(target.height)}` : "100%";
+                            }
                             // let ext = (target && target.type !== DocumentType.PDFANNO && Doc.fieldExtensionDoc(target, "data")) || target; // try guessing that the target doc's data is in the 'data' field.  probably need an 'overviewLayout' and then just display the target Document ....
                             // let text = ext && StrCast(ext.text);
                             // ext && (FormattedTextBoxComment.tooltipText.textContent = (target && target.type === DocumentType.PDFANNO ? "Quoted from " : "") + "=> " + (text || StrCast(ext.title)));
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 17b2094ec..f50a3a0ef 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -172,7 +172,6 @@ export class PresElementBox extends DocComponent<FieldViewProps, PresDocument>(P
                 <ContentFittingDocumentView
                     fitToBox={StrCast(this.targetDoc.type).indexOf(DocumentType.COL) !== -1}
                     Document={this.targetDoc}
-                    fieldKey={this.props.fieldKey}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
                     ruleProvider={undefined}
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 833e44bf6..466e2d707 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -185,6 +185,8 @@ export class CurrentUserUtils {
         (doc.curPresentation === undefined) && CurrentUserUtils.setupDefaultPresentation(doc);
         (doc.sidebarButtons === undefined) && CurrentUserUtils.setupSidebarButtons(doc);
 
+        // this is equivalent to using PrefetchProxies to make sure the recentlyClosed doc is ready
+        PromiseValue(Cast(doc.recentlyClosed, Doc)).then(recent => recent && PromiseValue(recent.data).then(DocListCast));
         // this is equivalent to using PrefetchProxies to make sure all the sidebarButtons and noteType internal Doc's have been retrieved.
         PromiseValue(Cast(doc.noteTypes, Doc)).then(noteTypes => noteTypes && PromiseValue(noteTypes.data).then(DocListCast));
         PromiseValue(Cast(doc.sidebarButtons, Doc)).then(stackingDoc => {
-- 
cgit v1.2.3-70-g09d2

