From 9b8f4fa46bfdc9ee435a9fa300a60310ede56112 Mon Sep 17 00:00:00 2001
From: Melissa Zhang <mzhang19096@gmail.com>
Date: Thu, 13 Aug 2020 10:10:45 -0700
Subject: fixed empty string bug, small expander UI change

---
 src/client/views/collections/CollectionSchemaCells.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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

diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 49d75e6de..4c0a82e83 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -254,7 +254,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
         };
 
         let contents: any = "incorrect type";
-        if (type === undefined) contents = <FieldView {...props} fieldKey={fieldKey} />;
+        if (type === undefined) contents = StrCast(field) === "" ? "--" : <FieldView {...props} fieldKey={fieldKey} />;
         if (type === "number") contents = typeof field === "number" ? NumCast(field) : "--" + typeof field + "--";
         if (type === "string") contents = typeof field === "string" ? (StrCast(field) === "" ? "--" : StrCast(field)) : "--" + typeof field + "--";
         if (type === "boolean") contents = typeof field === "boolean" ? (BoolCast(field) ? "true" : "false") : "--" + typeof field + "--";
-- 
cgit v1.2.3-70-g09d2


From efbdaf80423b82270f6d3eefc2427b1490ad36d1 Mon Sep 17 00:00:00 2001
From: Melissa Zhang <mzhang19096@gmail.com>
Date: Thu, 13 Aug 2020 12:21:12 -0700
Subject: fix text field display in SchemaView

---
 src/client/views/collections/CollectionSchemaCells.tsx | 6 +++++-
 src/client/views/collections/SchemaTable.tsx           | 2 +-
 2 files changed, 6 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 4c0a82e83..7aa8f42b0 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -256,7 +256,11 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
         let contents: any = "incorrect type";
         if (type === undefined) contents = StrCast(field) === "" ? "--" : <FieldView {...props} fieldKey={fieldKey} />;
         if (type === "number") contents = typeof field === "number" ? NumCast(field) : "--" + typeof field + "--";
-        if (type === "string") contents = typeof field === "string" ? (StrCast(field) === "" ? "--" : StrCast(field)) : "--" + typeof field + "--";
+        if (type === "string") {
+            fieldKey === "text" ?
+                contents = Cast(field, RichTextField)?.Text :
+                contents = typeof field === "string" ? (StrCast(field) === "" ? "--" : StrCast(field)) : "--" + typeof field + "--";
+        }
         if (type === "boolean") contents = typeof field === "boolean" ? (BoolCast(field) ? "true" : "false") : "--" + typeof field + "--";
         if (type === "document") {
             const doc = FieldValue(Cast(field, Doc));
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index d3837c49f..24c2ee1ee 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -42,7 +42,7 @@ enum ColumnType {
 
 // this map should be used for keys that should have a const type of value
 const columnTypes: Map<string, ColumnType> = new Map([
-    ["title", ColumnType.String],
+    ["title", ColumnType.String], ["text", 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], ["currentTimecode", ColumnType.Number], ["zIndex", ColumnType.Number]
-- 
cgit v1.2.3-70-g09d2


From c628c9305ea5e28f577b5b040a30d7c8aaea3e8c Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 14 Aug 2020 10:56:37 -0400
Subject: fixed crash in schemaCell

---
 src/client/views/collections/CollectionSchemaCells.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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

diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 7aa8f42b0..bb5acc48a 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -301,7 +301,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             if (start !== -1) {
                 positions.push(start);
             }
-            while (start < contents.length && start !== -1) {
+            while (start < contents?.length && start !== -1) {
                 term = term.slice(start + search.length + 1);
                 tally += start + search.length + 1;
                 start = term.indexOf(search);
-- 
cgit v1.2.3-70-g09d2


From 291d2fb28fa878eff190daf813854d9c0477ccb6 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 14 Aug 2020 17:29:55 -0400
Subject: cleaned up invocation of RichTextMenu

---
 src/client/util/CurrentUserUtils.ts                |  2 +-
 src/client/views/AntimodeMenu.tsx                  |  4 ++-
 src/client/views/DocumentDecorations.tsx           |  4 +--
 src/client/views/MainView.tsx                      |  1 -
 src/client/views/collections/CollectionMenu.tsx    |  8 ++---
 .../views/collections/CollectionSchemaCells.tsx    |  5 ++--
 .../collectionFreeForm/FormatShapePane.tsx         |  4 +--
 .../collectionFreeForm/MarqueeOptionsMenu.tsx      |  4 +--
 .../views/nodes/formattedText/FormattedTextBox.tsx | 13 +++++----
 .../views/nodes/formattedText/RichTextMenu.tsx     | 34 +++++++++-------------
 src/client/views/pdf/PDFMenu.tsx                   |  4 +--
 11 files changed, 40 insertions(+), 43 deletions(-)

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

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 68d02cd94..bd22b8e9d 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -451,7 +451,7 @@ export class CurrentUserUtils {
             // { title: "use stamp", icon: "stamp", click: 'activateStamp(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc },
             // { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activeInkPen, this)`, backgroundColor: "pink", activeInkPen: doc },
             // { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activeInkPen = this;', ischecked: `sameDocs(this.activeInkPen, this)`, backgroundColor: "white", activeInkPen: doc },
-            { toolTip: "Tap to create a document previewer in a new pane, drag for a document previewer", title: "Prev", icon: "expand", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory,true)', dragFactory: doc.emptyDocHolder as Doc },
+            { toolTip: "Tap to create a document previewer in a new pane, drag for a document previewer", title: "Prev", icon: "expand", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyDocHolder as Doc },
             { toolTip: "Toggle a Calculator REPL", title: "repl", icon: "calculator", click: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' },
             { toolTip: "Connect a Google Account", title: "Google Account", icon: "external-link-alt", click: 'GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken(true)' },
         ];
diff --git a/src/client/views/AntimodeMenu.tsx b/src/client/views/AntimodeMenu.tsx
index 68ccefcb5..9f16d0fe1 100644
--- a/src/client/views/AntimodeMenu.tsx
+++ b/src/client/views/AntimodeMenu.tsx
@@ -1,12 +1,14 @@
 import React = require("react");
 import { observable, action } from "mobx";
 import "./AntimodeMenu.scss";
+export interface AntimodeMenuProps {
+}
 
 /**
  * This is an abstract class that serves as the base for a PDF-style or Marquee-style
  * menu. To use this class, look at PDFMenu.tsx or MarqueeOptionsMenu.tsx for an example.
  */
-export default abstract class AntimodeMenu extends React.Component {
+export default abstract class AntimodeMenu<T extends AntimodeMenuProps> extends React.Component<T, {}> {
     protected _offsetY: number = 0;
     protected _offsetX: number = 0;
     protected _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 03746a1d2..3f16dd7e7 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -659,8 +659,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         if (bounds.y > bounds.b) {
             bounds.y = bounds.b - (this._resizeBorderWidth + this._linkBoxHeight + this._titleHeight);
         }
-        var offset = 0;
-        let useRotation = seldoc.rootDoc.type === DocumentType.INK;
+        let offset = 0;
+        const useRotation = seldoc.rootDoc.type === DocumentType.INK;
 
         return (<div className="documentDecorations" style={{ background: darkScheme }} >
             <div className="documentDecorations-background" style={{
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 059e1f566..5a2488bb6 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -817,7 +817,6 @@ export class MainView extends React.Component {
             <DocumentDecorations />
             {this.search}
             <CollectionMenu />
-            <div style={{ display: "none" }}><RichTextMenu key="rich" /></div>
             <FormatShapePane />
             {LinkDescriptionPopup.descriptionPopup ? <LinkDescriptionPopup /> : null}
             {DocumentLinksButton.EditLink ? <LinkMenu docView={DocumentLinksButton.EditLink} addDocTab={DocumentLinksButton.EditLink.props.addDocTab} changeFlyout={emptyFunction} /> : (null)}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 5119ff6c9..0b3be8739 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -21,7 +21,7 @@ import { CurrentUserUtils } from "../../util/CurrentUserUtils";
 import { DragManager } from "../../util/DragManager";
 import { SelectionManager } from "../../util/SelectionManager";
 import { undoBatch } from "../../util/UndoManager";
-import AntimodeMenu from "../AntimodeMenu";
+import AntimodeMenu, { AntimodeMenuProps } from "../AntimodeMenu";
 import { EditableView } from "../EditableView";
 import GestureOverlay from "../GestureOverlay";
 import { ActiveFillColor, ActiveInkColor, SetActiveArrowEnd, SetActiveArrowStart, SetActiveBezierApprox, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth } from "../InkingStroke";
@@ -32,13 +32,13 @@ import "./CollectionMenu.scss";
 import { CollectionViewType, COLLECTION_BORDER_WIDTH } from "./CollectionView";
 
 @observer
-export default class CollectionMenu extends AntimodeMenu {
+export default class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> {
     static Instance: CollectionMenu;
 
     @observable SelectedCollection: DocumentView | undefined;
     @observable FieldKey: string;
 
-    constructor(props: Readonly<{}>) {
+    constructor(props: any) {
         super(props);
         this.FieldKey = "";
         CollectionMenu.Instance = this;
@@ -655,7 +655,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
                     </> :
                     (null)
                 }
-                {this.isText ? <RichTextMenu key="rich" /> : null}
+                {this.isText ? <RichTextMenu /> : null}
             </div>;
     }
 }
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 20ce6b76d..11470e940 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -82,9 +82,8 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             const doc = Doc.GetProto(this.props.rowProps.original);
             const aliasdoc = await SearchUtil.GetAliasesOfDocument(doc);
             if (aliasdoc.length > 0) {
-                const targetContext = Cast(aliasdoc[0].context, Doc) as Doc;
-                console.log(StrCast(targetContext.title));
-                runInAction(() => this.contents = StrCast(targetContext.title));
+                const targetContext = Cast(aliasdoc[0].context, Doc, null);
+                targetContext && runInAction(() => this.contents = StrCast(targetContext.title));
             }
         }
 
diff --git a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
index 1ffa2fbed..a7f44bbbf 100644
--- a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
+++ b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
@@ -9,13 +9,13 @@ import { InkField } from "../../../../fields/InkField";
 import { BoolCast, Cast, NumCast } from "../../../../fields/Types";
 import { DocumentType } from "../../../documents/DocumentTypes";
 import { SelectionManager } from "../../../util/SelectionManager";
-import AntimodeMenu from "../../AntimodeMenu";
+import AntimodeMenu, { AntimodeMenuProps } from "../../AntimodeMenu";
 import "./FormatShapePane.scss";
 import { undoBatch } from "../../../util/UndoManager";
 import { ColorState, SketchPicker } from 'react-color';
 
 @observer
-export default class FormatShapePane extends AntimodeMenu {
+export default class FormatShapePane extends AntimodeMenu<AntimodeMenuProps> {
     static Instance: FormatShapePane;
 
     private _lastFill = "#D0021B";
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
index f1df7998b..2cfe0183c 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
@@ -1,5 +1,5 @@
 import React = require("react");
-import AntimodeMenu from "../../AntimodeMenu";
+import AntimodeMenu, { AntimodeMenuProps } from "../../AntimodeMenu";
 import { observer } from "mobx-react";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { unimplementedFunction } from "../../../../Utils";
@@ -7,7 +7,7 @@ import { undoBatch } from "../../../util/UndoManager";
 import { Tooltip } from "@material-ui/core";
 
 @observer
-export default class MarqueeOptionsMenu extends AntimodeMenu {
+export default class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> {
     static Instance: MarqueeOptionsMenu;
 
     public createCollection: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 8c05d3603..c31e7469f 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -34,7 +34,7 @@ import { DictationManager } from '../../../util/DictationManager';
 import { DragManager } from "../../../util/DragManager";
 import { makeTemplate } from '../../../util/DropConverter';
 import buildKeymap, { updateBullets } from "./ProsemirrorExampleTransfer";
-import RichTextMenu from './RichTextMenu';
+import RichTextMenu, { RichTextMenuPlugin } from './RichTextMenu';
 import { RichTextRules } from "./RichTextRules";
 
 //import { DashDocView } from "./DashDocView";
@@ -1306,7 +1306,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
 
         // jump rich text menu to this textbox
         const bounds = this._ref.current?.getBoundingClientRect();
-        if (bounds && this.layoutDoc._chromeStatus !== "disabled") {
+        if (bounds && this.layoutDoc._chromeStatus !== "disabled" && RichTextMenu.Instance) {
             const x = Math.min(Math.max(bounds.left, 0), window.innerWidth - RichTextMenu.Instance.width);
             let y = Math.min(Math.max(0, bounds.top - RichTextMenu.Instance.height - 50), window.innerHeight - RichTextMenu.Instance.height);
             if (coords && coords.left > x && coords.left < x + RichTextMenu.Instance.width && coords.top > y && coords.top < y + RichTextMenu.Instance.height + 50) {
@@ -1410,11 +1410,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         }
     }
 
+    menuPlugin: any;
+
     richTextMenuPlugin() {
+        const self = this;
         return new Plugin({
             view(newView) {
-                RichTextMenu.Instance?.changeView(newView);
-                return RichTextMenu.Instance;
+                self.props.isSelected(true) && (RichTextMenu.Instance.view = newView);
+                return self.menuPlugin = new RichTextMenuPlugin({ editorProps: this.props });
             }
         });
     }
@@ -1524,7 +1527,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         const scale = this.props.hideOnLeave ? 1 : this.props.ContentScaling() * NumCast(this.layoutDoc._viewScale, 1);
         const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : "";
         const interactive = Doc.GetSelectedTool() === InkTool.None && !this.layoutDoc.isBackground;
-        setTimeout(() => this._editorView && RichTextMenu.Instance.updateFromDash(this._editorView, undefined, this.props), this.props.isSelected() ? 10 : 0); // need to make sure that we update a text box that is selected after updating the one that was deselected
+        setTimeout(() => this._editorView && RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this.props), this.props.isSelected() ? 10 : 0); // need to make sure that we update a text box that is selected after updating the one that was deselected
         if (!this.props.isSelected() && FormattedTextBoxComment.textBox === this) {
             setTimeout(() => FormattedTextBoxComment.Hide(), 0);
         }
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index b683fb25d..25b0279ba 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -16,7 +16,7 @@ import { unimplementedFunction, Utils } from "../../../../Utils";
 import { DocServer } from "../../../DocServer";
 import { LinkManager } from "../../../util/LinkManager";
 import { SelectionManager } from "../../../util/SelectionManager";
-import AntimodeMenu from "../../AntimodeMenu";
+import AntimodeMenu, { AntimodeMenuProps } from "../../AntimodeMenu";
 import { FieldViewProps } from "../FieldView";
 import { FormattedTextBox, FormattedTextBoxProps } from "./FormattedTextBox";
 import { updateBullets } from "./ProsemirrorExampleTransfer";
@@ -31,11 +31,11 @@ library.add(faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSup
 
 
 @observer
-export default class RichTextMenu extends AntimodeMenu {
+export default class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
     static Instance: RichTextMenu;
     public overMenu: boolean = false; // kind of hacky way to prevent selects not being selectable
 
-    private view?: EditorView;
+    public view?: EditorView;
     public editorProps: FieldViewProps & FormattedTextBoxProps | undefined;
 
     public _brushMap: Map<string, Set<Mark>> = new Map();
@@ -156,21 +156,7 @@ export default class RichTextMenu extends AntimodeMenu {
     public delayHide = () => this._delayHide = true;
 
     @action
-    changeView(view: EditorView) {
-        if ((view as any)?.TextView?.props.isSelected(true)) {
-            this.view = view;
-        }
-    }
-
-    update(view: EditorView, lastState: EditorState | undefined) {
-        RichTextMenu.Instance.updateFromDash(view, lastState, this.editorProps);
-    }
-
-    @action
-    public async updateFromDash(view: EditorView, lastState: EditorState | undefined, props: any) {
-        RichTextMenu.Instance.finalUpdateFromDash(view, lastState, props);
-    }
-    public async finalUpdateFromDash(view: EditorView, lastState: EditorState | undefined, props: any) {
+    public updateMenu(view: EditorView, lastState: EditorState | undefined, props: any) {
         if (!view || !(view as any).TextView?.props.isSelected(true)) {
             return;
         }
@@ -199,8 +185,7 @@ export default class RichTextMenu extends AntimodeMenu {
         this.activeHighlightColor = !activeHighlights.length ? "" : activeHighlights.length === 1 ? String(activeHighlights[0]) : "...";
 
         // update link in current selection
-        const targetTitle = await this.getTextLinkTargetTitle();
-        this.setCurrentLink(targetTitle);
+        this.getTextLinkTargetTitle().then(targetTitle => this.setCurrentLink(targetTitle));
     }
 
     setMark = (mark: Mark, state: EditorState<any>, dispatch: any, dontToggle: boolean = false) => {
@@ -1070,4 +1055,13 @@ export class ButtonDropdown extends React.Component<ButtonDropdownProps> {
             </div>
         );
     }
+}
+
+
+interface RichTextMenuPluginProps {
+    editorProps: any;
+}
+export class RichTextMenuPlugin extends React.Component<RichTextMenuPluginProps> {
+    render() { return null; }
+    update(view: EditorView, lastState: EditorState | undefined) { RichTextMenu.Instance?.updateMenu(view, lastState, this.props.editorProps); }
 }
\ No newline at end of file
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index 7bea8d01b..bee282d9b 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -4,14 +4,14 @@ import { observable, action, computed, } from "mobx";
 import { observer } from "mobx-react";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { unimplementedFunction, returnFalse, Utils } from "../../../Utils";
-import AntimodeMenu from "../AntimodeMenu";
+import AntimodeMenu, { AntimodeMenuProps } from "../AntimodeMenu";
 import { Doc, Opt } from "../../../fields/Doc";
 import { ColorState } from "react-color";
 import { ButtonDropdown } from "../nodes/formattedText/RichTextMenu";
 
 
 @observer
-export default class PDFMenu extends AntimodeMenu {
+export default class PDFMenu extends AntimodeMenu<AntimodeMenuProps> {
     static Instance: PDFMenu;
 
     private _commentCont = React.createRef<HTMLButtonElement>();
-- 
cgit v1.2.3-70-g09d2


From bb2a9c80d1512d120d95dc1f603d1e3729dbb981 Mon Sep 17 00:00:00 2001
From: Melissa Zhang <mzhang19096@gmail.com>
Date: Sat, 15 Aug 2020 00:42:02 -0700
Subject: cleanup

---
 src/client/views/collections/CollectionSchemaCells.tsx | 2 +-
 src/client/views/collections/SchemaTable.tsx           | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 700c42ef6..24088575a 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -633,7 +633,7 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell {
         if (typeof this._field === "object" && this._doc && this._docTitle) {
             return (
                 <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1}
-                    onPointerDown={(e) => { this.onDown(e); }}
+                    onPointerDown={this.onDown}
                     onPointerEnter={(e) => { this.showPreview(true, e); }}
                     onPointerLeave={(e) => { this.showPreview(false, e); }}
                 >
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index b37e6a287..2c7950453 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -378,7 +378,6 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
 
     @action
     onKeyDown = (e: KeyboardEvent): void => {
-        console.log("headerIsEditing", this.props.headerIsEditing);
         if (!this._cellIsEditing && !this.props.headerIsEditing && this.props.isFocused(this.props.Document, true)) {// && this.props.isSelected(true)) {
             const direction = e.key === "Tab" ? "tab" : e.which === 39 ? "right" : e.which === 37 ? "left" : e.which === 38 ? "up" : e.which === 40 ? "down" : "";
             this._focusedCell = this.changeFocusedCellByDirection(direction, this._focusedCell.row, this._focusedCell.col);
-- 
cgit v1.2.3-70-g09d2


From 0f50185738a1bef1e5f015b269ae022c60eba8e6 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 15 Aug 2020 20:38:39 -0400
Subject: cleaned up console.logs.  fixed updating lastModified for SOLR

---
 src/client/views/collections/CollectionSchemaCells.tsx | 9 ---------
 src/client/views/collections/CollectionSchemaView.tsx  | 1 -
 src/client/views/nodes/formattedText/DashDocView.tsx   | 4 ++--
 src/server/websocket.ts                                | 3 +++
 4 files changed, 5 insertions(+), 12 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 81b63cbcd..003a1e9ff 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -69,16 +69,9 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
     protected _document = this.props.rowProps.original;
     protected _dropDisposer?: DragManager.DragDropDisposer;
 
-    async componentWillMount() {
-
-    }
-
     async componentDidMount() {
         document.addEventListener("keydown", this.onKeyDown);
-        console.log("mounted");
-        console.log(this.type);
         if (this.type === "context") {
-            console.log("mounted2");
             const doc = Doc.GetProto(this.props.rowProps.original);
             const aliasdoc = await SearchUtil.GetAliasesOfDocument(doc);
             if (aliasdoc.length > 0) {
@@ -425,14 +418,12 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
                             />
                             :
                             this.returnHighlights(() => {
-                                console.log(props.fieldKey);
                                 const dateCheck: Date | undefined = this.props.rowProps.original[this.props.rowProps.column.id as string] instanceof DateField ? DateCast(this.props.rowProps.original[this.props.rowProps.column.id as string]).date : undefined;
                                 if (dateCheck !== undefined) {
                                     cfield = dateCheck.toLocaleString();
                                 }
                                 if (props.fieldKey === "context") {
                                     cfield = this.contents;
-                                    console.log("this should work");
                                 }
                                 if (props.fieldKey === "*lastModified") {
                                     if (FieldValue(props.Document["data-lastModified"]) !== undefined) {
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 9c64178a8..6f8fb53ec 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -523,7 +523,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
 
     @action
     onTablePointerDown = (e: React.PointerEvent): void => {
-        console.log("TB ptr " + e.screenX + " " + e.screenY);
         this.setFocused(this.props.Document);
         if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey && this.props.isSelected(true)) {
             e.stopPropagation();
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 212da3f3d..145ee8c2e 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -114,7 +114,7 @@ export class DashDocView extends React.Component<IDashDocView> {
     }
     /*endregion*/
 
-    componentWillMount = () => {
+    componentWillUnmount = () => {
         this._reactionDisposer?.();
     }
 
@@ -254,7 +254,7 @@ export class DashDocView extends React.Component<IDashDocView> {
                             whenActiveChanged={returnFalse}
                             bringToFront={emptyFunction}
                             dontRegisterView={false}
-                            docFilters={this.props.tbox?.props.docFilters||returnEmptyFilter}
+                            docFilters={this.props.tbox?.props.docFilters || returnEmptyFilter}
                             ContainingCollectionView={this._textBox.props.ContainingCollectionView}
                             ContainingCollectionDoc={this._textBox.props.ContainingCollectionDoc}
                             ContentScaling={this.contentScaling}
diff --git a/src/server/websocket.ts b/src/server/websocket.ts
index ec351c283..b33e76c0b 100644
--- a/src/server/websocket.ts
+++ b/src/server/websocket.ts
@@ -290,6 +290,9 @@ export namespace WebSocket {
             if (term !== undefined) {
                 const { suffix, value } = term;
                 update[key + suffix] = { set: value };
+                if (key.endsWith('lastModified')) {
+                    update["lastModified" + suffix] = value;
+                }
             }
         }
         if (dynfield) {
-- 
cgit v1.2.3-70-g09d2


From d7b5f5f6199b36af556e68370b5b7c462db7869f Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 17 Aug 2020 09:43:13 -0400
Subject: fixed behavior of schemaHeader menu (except when pan or zoom occurs).
  Changed search to show aliases by default.

---
 src/client/util/HypothesisUtils.ts                       |  2 +-
 src/client/util/SearchUtil.ts                            |  6 +++++-
 src/client/views/collections/CollectionSchemaCells.tsx   | 11 +----------
 src/client/views/collections/CollectionSchemaHeaders.tsx |  3 +--
 src/client/views/collections/CollectionSchemaView.tsx    | 12 ++++++------
 src/client/views/collections/SchemaTable.tsx             |  7 ++++---
 src/client/views/search/SearchBox.tsx                    |  9 +++++----
 7 files changed, 23 insertions(+), 27 deletions(-)

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

diff --git a/src/client/util/HypothesisUtils.ts b/src/client/util/HypothesisUtils.ts
index 9ede94e4b..04e937878 100644
--- a/src/client/util/HypothesisUtils.ts
+++ b/src/client/util/HypothesisUtils.ts
@@ -34,7 +34,7 @@ export namespace Hypothesis {
 
         const results: Doc[] = [];
         await SearchUtil.Search("web", true).then(action(async (res: SearchUtil.DocSearchResult) => {
-            const docs = await Promise.all(res.docs.map(async doc => (await Cast(doc.extendsDoc, Doc)) || doc));
+            const docs = res.docs;
             const filteredDocs = docs.filter(doc =>
                 doc.author === Doc.CurrentUserEmail && doc.type === DocumentType.WEB && doc.data
             );
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index b63fc8991..6dafbd58e 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -29,6 +29,7 @@ export namespace SearchUtil {
         rows?: number;
         fq?: string;
         allowAliases?: boolean;
+        onlyAliases?: boolean;
         "facet"?: string;
         "facet.field"?: string;
     }
@@ -37,7 +38,10 @@ export namespace SearchUtil {
     export async function Search(query: string, returnDocs: boolean, options: SearchParams = {}) {
         query = query || "*"; //If we just have a filter query, search for * as the query
         const rpquery = Utils.prepend("/dashsearch");
-        const replacedQuery = query.replace(/type_t:([^ )])/g, (substring, arg) => `{!join from=id to=proto_i}type_t:${arg}`);
+        let replacedQuery = query.replace(/type_t:([^ )])/g, (substring, arg) => `{!join from=id to=proto_i}type_t:${arg}`);
+        if (options.onlyAliases) {
+            replacedQuery = `{!join from=id to=proto_i}DEFAULT:${replacedQuery}`;
+        }
         const gotten = await rp.get(rpquery, { qs: { ...options, sort: "lastModified_d desc", q: replacedQuery } });
         const result: IdSearchResult = gotten.startsWith("<") ? { ids: [], docs: [], numFound: 0, lines: [] } : JSON.parse(gotten);
         if (!returnDocs) {
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 003a1e9ff..d46aa3574 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -71,15 +71,6 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
 
     async componentDidMount() {
         document.addEventListener("keydown", this.onKeyDown);
-        if (this.type === "context") {
-            const doc = Doc.GetProto(this.props.rowProps.original);
-            const aliasdoc = await SearchUtil.GetAliasesOfDocument(doc);
-            if (aliasdoc.length > 0) {
-                const targetContext = Cast(aliasdoc[0].context, Doc, null);
-                targetContext && runInAction(() => this.contents = StrCast(targetContext.title));
-            }
-        }
-
     }
 
     @observable contents: string = "";
@@ -303,7 +294,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
         //     </div>
         // );   
         const positions = [];
-        let cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
+        let cfield = props.Document[props.fieldKey];
         this.type = props.fieldKey;
         if (StrCast(this.props.Document._searchString).toLowerCase() !== "") {
             let term = Field.toString(cfield as Field);
diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx
index a4b689e2f..be25bf9de 100644
--- a/src/client/views/collections/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/CollectionSchemaHeaders.tsx
@@ -496,7 +496,6 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
     get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; }
 
     @computed get scriptField() {
-        console.log("we kinda made it");
         const scriptText = "setDocFilter(containingTreeView, heading, this.title, checked)";
         const script = ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name });
         return script ? () => script : undefined;
@@ -507,7 +506,7 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
     render() {
         return (
             <div style={{ display: "flex" }}>
-                <FontAwesomeIcon onClick={e => { this.props.openHeader(this.props.col, e.clientX, e.clientY); }} icon={this.props.icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} />
+                <FontAwesomeIcon onClick={e => { this.props.openHeader(this.props.col, e.clientX, e.clientY); e.stopPropagation(); }} icon={this.props.icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} />
 
                 {/* <FontAwesomeIcon icon={fa.faSearchMinus} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} onClick={e => {
                     runInAction(() => { this._isOpen === undefined ? this._isOpen = true : this._isOpen = !this._isOpen })
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 6f8fb53ec..abaee0e16 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -328,7 +328,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
     @action
     openHeader = (col: any, screenx: number, screeny: number) => {
         this._col = col;
-        this._headerOpen = !this._headerOpen;
+        this._headerOpen = true;
         this._pointerX = screenx;
         this._pointerY = screeny;
     }
@@ -360,7 +360,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
 
     @action
     onHeaderClick = (e: React.PointerEvent) => {
-        this.props.active(true);
         e.stopPropagation();
     }
 
@@ -499,6 +498,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
             documentKeys={this.documentKeys}
             headerIsEditing={this._headerIsEditing}
             openHeader={this.openHeader}
+            onClick={e => { e.stopPropagation(); this.closeHeader(); }}
             onPointerDown={this.onTablePointerDown}
             onResizedChange={this.onResizedChange}
             setColumns={this.setColumns}
@@ -527,8 +527,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
         if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey && this.props.isSelected(true)) {
             e.stopPropagation();
         }
-        this._pointerY = e.screenY;
-        this._pointerX = e.screenX;
+        // this.closeHeader();
     }
 
     onResizedChange = (newResized: Resize[], event: any) => {
@@ -581,6 +580,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
         if (this.props.Document._searchDoc !== undefined) {
             name = "collectionSchemaView-searchContainer";
         }
+        if (!this.props.active()) setTimeout(() => this.closeHeader(), 0);
         TraceMobx();
         const menuContent = this.renderMenuContent;
         const menu = <div className="collectionSchema-header-menu"
@@ -588,7 +588,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
             onPointerDown={e => this.onHeaderClick(e)}
             style={{
                 position: "fixed", background: "white", border: "black 1px solid",
-                transform: `translate(${(this.menuCoordinates[0] / this.scale)}px, ${(this.menuCoordinates[1] / this.scale)}px)`
+                transform: `translate(${(this.menuCoordinates[0])}px, ${(this.menuCoordinates[1])}px)`
             }}>
             <Measure offset onResize={action((r: any) => {
                 const dim = this.props.ScreenToLocalTransform().inverse().transformDirection(r.offset.width, r.offset.height);
@@ -614,7 +614,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
             </div>
             {this.dividerDragger}
             {!this.previewWidth() ? (null) : this.previewPanel}
-            {this._headerOpen ? menu : null}
+            {this._headerOpen && this.props.active() ? menu : null}
         </div>;
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index 7324dd6df..763e5a410 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -75,6 +75,7 @@ export interface SchemaTableProps {
     documentKeys: any[];
     headerIsEditing: boolean;
     openHeader: (column: any, screenx: number, screeny: number) => void;
+    onClick: (e: React.MouseEvent) => void;
     onPointerDown: (e: React.PointerEvent) => void;
     onResizedChange: (newResized: Resize[], event: any) => void;
     setColumns: (columns: SchemaHeaderField[]) => void;
@@ -230,7 +231,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
 
             return {
                 Header: <MovableColumn columnRenderer={header} columnValue={col} allColumns={this.props.columns} reorderColumns={this.props.reorderColumns} ScreenToLocalTransform={this.props.ScreenToLocalTransform} />,
-                accessor: (doc: Doc) => doc ? doc[col.heading] : 0,
+                accessor: (doc: Doc) => doc ? Field.toString(doc[col.heading] as Field) : 0,
                 id: col.heading,
                 Cell: (rowProps: CellInfo) => {
                     const rowIndex = rowProps.index;
@@ -322,7 +323,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
             this.props.Document._schemaHeaders = new List<SchemaHeaderField>(newSchemaHeaders);
         } else if (this.props.Document._schemaHeaders === undefined) {
             this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb"), new SchemaHeaderField("author", "#f1efeb"), new SchemaHeaderField("*lastModified", "#f1efeb"),
-            new SchemaHeaderField("text", "#f1efeb"), new SchemaHeaderField("type", "#f1efeb"), new SchemaHeaderField("context", "#f1efeb")]);
+            new SchemaHeaderField("text", "#f1efeb"), new SchemaHeaderField("type", "#f1efeb"), new SchemaHeaderField("context", "#f1efeb", ColumnType.Doc)]);
         }
     }
 
@@ -598,7 +599,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     render() {
         const preview = "";
         return <div className="collectionSchemaView-table" style={{ overflow: this.props.Document._searchDoc ? undefined : "auto" }}
-            onPointerDown={this.props.onPointerDown} onWheel={e => this.props.active(true) && e.stopPropagation()}
+            onPointerDown={this.props.onPointerDown} onClick={this.props.onClick} onWheel={e => this.props.active(true) && e.stopPropagation()}
             onDrop={e => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} >
             {this.reactTable}
             {StrCast(this.props.Document.type) !== "search" ? <div className="collectionSchemaView-addRow" onClick={() => this.createRow()}>+ new</div>
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 99db78778..07f1485c3 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -239,6 +239,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
     @observable private _authorFieldStatus: boolean = true;
     //this also serves as an indicator if the collection status filter is applied
     @observable public _deletedDocsStatus: boolean = false;
+    @observable public _onlyAliases: boolean = true;
     @observable private _collectionStatus = false;
 
 
@@ -607,7 +608,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         const types = ["preselement", "docholder", "search", "searchitem", "fonticonbox"]; // this.filterTypes;
         const baseExpr = "NOT system_b:true";
         const includeDeleted = this.getDataStatus() ? "" : " NOT deleted_b:true";
-        const typeExpr = !types ? "" : `(type_t:* OR {!join from=id to=proto_i}type_t:*) ${types.map(type => `NOT ({!join from=id to=proto_i}type_t:${type}) AND NOT type_t:${type}`).join(" AND ")}`;
+        const typeExpr = this._onlyAliases ? "NOT {!join from=id to=proto_i}type_t:*" : `(type_t:* OR {!join from=id to=proto_i}type_t:*) ${types.map(type => `NOT ({!join from=id to=proto_i}type_t:${type}) AND NOT type_t:${type}`).join(" AND ")}`;
         // fq: type_t:collection OR {!join from=id to=proto_i}type_t:collection   q:text_t:hello
         const query = [baseExpr, includeDeleted, typeExpr].join(" AND ").replace(/AND $/, "");
         return query;
@@ -623,7 +624,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         }
         this.lockPromise = new Promise(async res => {
             while (this._results.length <= this._endIndex && (this._numTotalResults === -1 || this._maxSearchIndex < this._numTotalResults)) {
-                this._curRequest = SearchUtil.Search(query, true, { fq: this.filterQuery, start: this._maxSearchIndex, rows: this.NumResults, hl: true, "hl.fl": "*", }).then(action(async (res: SearchUtil.DocSearchResult) => {
+                this._curRequest = SearchUtil.Search(query, true, { onlyAliases: true, allowAliases: true, fq: this.filterQuery, start: this._maxSearchIndex, rows: this.NumResults, hl: true, "hl.fl": "*", }).then(action(async (res: SearchUtil.DocSearchResult) => {
                     // happens at the beginning
                     this.realTotalResults = res.numFound <= 0 ? 0 : res.numFound;
                     if (res.numFound !== this._numTotalResults && this._numTotalResults === -1) {
@@ -633,7 +634,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                     const highlightList = res.docs.map(doc => highlighting[doc[Id]]);
                     const lines = new Map<string, string[]>();
                     res.docs.map((doc, i) => lines.set(doc[Id], res.lines[i]));
-                    const docs = await Promise.all(res.docs.map(async doc => (await Cast(doc.extendsDoc, Doc)) || doc));
+                    const docs = res.docs;
                     const highlights: typeof res.highlighting = {};
                     docs.forEach((doc, index) => highlights[doc[Id]] = highlightList[index]);
                     const filteredDocs = this.filterDocsByType(docs);
@@ -877,7 +878,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                     <div style={{ position: "relative", display: "flex", width: 400 }}>
                         <input value={this.newsearchstring} autoComplete="off" onChange={this.onChange} type="text" placeholder="Search..." id="search-input" ref={this.inputRef}
                             className="searchBox-barChild searchBox-input" onPointerDown={this.openSearch} onKeyPress={this.enter} onFocus={this.openSearch}
-                            style={{ padding: 1, paddingLeft: 20, paddingRight: 20, color: "black", height: 20, width: 250 }} />
+                            style={{ padding: 1, paddingLeft: 20, paddingRight: 60, color: "black", height: 20, width: 250 }} />
                         <div style={{ display: "flex", alignItems: "center" }}>
                             <div style={{ position: "absolute", left: 10 }}>
                                 <Tooltip title={<div className="dash-tooltip" >drag search results as collection</div>}>
-- 
cgit v1.2.3-70-g09d2


From ab89ef62d3f11c11f3f6e7162ca0e112bac1517e Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 17 Aug 2020 15:55:17 -0400
Subject: added sort to solr search options.  removed delete field assignment
 when removing Documents.  Allowed ToScriptScript and ToString to go through
 regardless of ACLs

---
 solr-8.3.1/server/solr/dash/conf/schema.xml            |  2 +-
 src/client/util/SearchUtil.ts                          |  3 ++-
 src/client/views/DocComponent.tsx                      |  1 -
 src/client/views/collections/CollectionSchemaCells.tsx |  2 +-
 src/client/views/collections/CollectionView.tsx        |  1 -
 src/client/views/search/SearchBox.tsx                  | 17 +++++++++++++++--
 src/fields/Doc.ts                                      | 16 +++++-----------
 src/fields/util.ts                                     |  4 ++--
 8 files changed, 26 insertions(+), 20 deletions(-)

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

diff --git a/solr-8.3.1/server/solr/dash/conf/schema.xml b/solr-8.3.1/server/solr/dash/conf/schema.xml
index 4f6ae57b2..74c4b494c 100644
--- a/solr-8.3.1/server/solr/dash/conf/schema.xml
+++ b/solr-8.3.1/server/solr/dash/conf/schema.xml
@@ -51,7 +51,7 @@
   <field name="proto" type="string" indexed="true" stored="true" uninvertible="false"  />
 
   <!-- <dynamicField name="*_s" type="string" indexed="true" stored="false" uninvertible="false" docValues="true"/> -->
-  <dynamicField name="*_t" type="text" indexed="true" stored="true" uninvertible="false" docValues="false"/>
+  <dynamicField name="*_t" type="text" indexed="true" stored="true" uninvertible="true" docValues="false"/>
   <dynamicField name="*_n" type="pdouble" indexed="true" stored="true" uninvertible="false" docValues="false"/>
   <dynamicField name="*_d" type="pdate" indexed="true" stored="true" uninvertible="false" docValues="true"/>
   <dynamicField name="*_l" type="list" indexed="true" stored="true" uninvertible="false" docValues="false" multiValued="true"/>
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index 6dafbd58e..ce96ab67b 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;
+        sort?: string;
         allowAliases?: boolean;
         onlyAliases?: boolean;
         "facet"?: string;
@@ -42,7 +43,7 @@ export namespace SearchUtil {
         if (options.onlyAliases) {
             replacedQuery = `{!join from=id to=proto_i}DEFAULT:${replacedQuery}`;
         }
-        const gotten = await rp.get(rpquery, { qs: { ...options, sort: "lastModified_d desc", q: replacedQuery } });
+        const gotten = await rp.get(rpquery, { qs: { ...options, q: replacedQuery } });
         const result: IdSearchResult = gotten.startsWith("<") ? { ids: [], docs: [], numFound: 0, lines: [] } : JSON.parse(gotten);
         if (!returnDocs) {
             return result;
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 8c8bb6fde..23ce71c4f 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -135,7 +135,6 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
                     toRemove.forEach(doc => {
                         Doc.RemoveDocFromList(targetDataDoc, this.props.fieldKey + "-annotations", doc);
                         recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true);
-                        doc.deleted = true;
                     });
                     return true;
                 }
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index d46aa3574..fa4d8c51b 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -297,7 +297,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
         let cfield = props.Document[props.fieldKey];
         this.type = props.fieldKey;
         if (StrCast(this.props.Document._searchString).toLowerCase() !== "") {
-            let term = Field.toString(cfield as Field);
+            let term = (cfield instanceof Promise) ? "...promise pending..." : Field.toString(cfield as Field);
             term = term.toLowerCase();
             const search = StrCast(this.props.Document._searchString).toLowerCase();
             let start = term.indexOf(search);
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 9d305145e..2064b0be4 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -208,7 +208,6 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 toRemove.forEach(doc => {
                     Doc.RemoveDocFromList(targetDataDoc, this.props.fieldKey, doc);
                     recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true);
-                    doc.deleted = true;
                 });
                 return true;
             }
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 07f1485c3..847bda137 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -4,7 +4,7 @@ import { action, computed, observable, runInAction, reaction, IReactionDisposer
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import * as rp from 'request-promise';
-import { Doc, DocListCast } from '../../../fields/Doc';
+import { Doc, DocListCast, Opt } from '../../../fields/Doc';
 import { documentSchema } from "../../../fields/documentSchemas";
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
@@ -24,6 +24,7 @@ import { ViewBoxBaseComponent } from "../DocComponent";
 import { DocumentView } from '../nodes/DocumentView';
 import { FieldView, FieldViewProps } from '../nodes/FieldView';
 import "./SearchBox.scss";
+import { ColumnType } from "../collections/CollectionSchemaView";
 
 export const searchSchema = createSchema({
     id: "string",
@@ -616,6 +617,18 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
 
     getDataStatus() { return this._deletedDocsStatus; }
 
+    @computed get primarySort() {
+        const suffixMap = (type: ColumnType) => {
+            switch (type) {
+                case ColumnType.Date: return "_d";
+                case ColumnType.String: return "_t";
+                case ColumnType.Boolean: return "_b";
+                case ColumnType.Number: return "_n";
+            }
+        }
+        const headers = Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []);
+        return headers.reduce((p: Opt<string>, header: SchemaHeaderField) => p || (header.desc !== undefined && suffixMap(header.type) ? (header.heading + suffixMap(header.type) + (header.desc ? " desc" : " asc")) : undefined), undefined);
+    }
     private NumResults = 50;
     private lockPromise?: Promise<void>;
     getResults = async (query: string) => {
@@ -624,7 +637,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         }
         this.lockPromise = new Promise(async res => {
             while (this._results.length <= this._endIndex && (this._numTotalResults === -1 || this._maxSearchIndex < this._numTotalResults)) {
-                this._curRequest = SearchUtil.Search(query, true, { onlyAliases: true, allowAliases: true, fq: this.filterQuery, start: this._maxSearchIndex, rows: this.NumResults, hl: true, "hl.fl": "*", }).then(action(async (res: SearchUtil.DocSearchResult) => {
+                this._curRequest = SearchUtil.Search(query, true, { onlyAliases: true, allowAliases: true, sort: this.primarySort, fq: this.filterQuery, start: 0, rows: this.NumResults, hl: true, "hl.fl": "*", }).then(action(async (res: SearchUtil.DocSearchResult) => {
                     // happens at the beginning
                     this.realTotalResults = res.numFound <= 0 ? 0 : res.numFound;
                     if (res.numFound !== this._numTotalResults && this._numTotalResults === -1) {
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 5f5fe98bc..0dcb8ab42 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -195,6 +195,8 @@ export class Doc extends RefField {
 
     @observable
     private ___fieldKeys: any = {};
+    @observable
+    public [AclSym]: { [key: string]: symbol };
 
     private [UpdatingFromServer]: boolean = false;
 
@@ -204,17 +206,9 @@ export class Doc extends RefField {
 
     private [Self] = this;
     private [SelfProxy]: any;
-    public [FieldsSym] = (clear?: boolean) => {
-        if (clear) {
-            this.___fields = {};
-            this.___fieldKeys = {};
-        }
-        return this.___fields;
-    }
-    @observable
-    public [AclSym]: { [key: string]: symbol };
-    public [WidthSym] = () => NumCast(this[SelfProxy]._width);
-    public [HeightSym] = () => NumCast(this[SelfProxy]._height);
+    public [FieldsSym](clear?: boolean) { return clear ? this.___fields = this.___fieldKeys = {} : this.___fields; }
+    public [WidthSym]() { return NumCast(this[SelfProxy]._width); }
+    public [HeightSym]() { return NumCast(this[SelfProxy]._height); }
     public [ToScriptString]() { return `DOC-"${this[Self][Id]}"-`; }
     public [ToString]() { return `Doc(${GetEffectiveAcl(this) === AclPrivate ? "-inaccessible-" : this.title})`; }
     public get [LayoutSym]() { return this[SelfProxy].__LAYOUT__; }
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 3d832636f..e3d9ed2ef 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -5,7 +5,7 @@ import { ProxyField, PrefetchProxy } from "./Proxy";
 import { RefField } from "./RefField";
 import { ObjectField } from "./ObjectField";
 import { action, trace } from "mobx";
-import { Parent, OnUpdate, Update, Id, SelfProxy, Self, HandleUpdate } from "./FieldSymbols";
+import { Parent, OnUpdate, Update, Id, SelfProxy, Self, HandleUpdate, ToString, ToScriptString } from "./FieldSymbols";
 import { DocServer } from "../client/DocServer";
 import { ComputedField } from "./ScriptField";
 import { ScriptCast, StrCast } from "./Types";
@@ -286,7 +286,7 @@ export function setter(target: any, in_prop: string | symbol | number, value: an
 export function getter(target: any, in_prop: string | symbol | number, receiver: any): any {
     let prop = in_prop;
 
-    if (in_prop === FieldsSym || in_prop === Id || in_prop === HandleUpdate || in_prop === CachedUpdates) return target.__fields[prop] || target[prop];
+    if (in_prop === ToString || in_prop === ToScriptString || in_prop === FieldsSym || in_prop === Id || in_prop === HandleUpdate || in_prop === CachedUpdates) return target.__fields[prop] || target[prop];
     if (in_prop === AclSym) return _overrideAcl ? undefined : target[AclSym];
     if (GetEffectiveAcl(target) === AclPrivate && !_overrideAcl) return prop === HeightSym || prop === WidthSym ? returnZero : undefined;
     if (prop === LayoutSym) {
-- 
cgit v1.2.3-70-g09d2


From 681460e3ef16cd6031447108d62a4d160eb3266f Mon Sep 17 00:00:00 2001
From: Melissa Zhang <mzhang19096@gmail.com>
Date: Mon, 17 Aug 2020 14:55:14 -0700
Subject: Fix SchemaView undefined/empty string values

---
 src/client/views/collections/CollectionSchemaCells.tsx | 9 +++++----
 src/client/views/collections/SchemaTable.tsx           | 6 +++---
 src/fields/RichTextField.ts                            | 2 +-
 3 files changed, 9 insertions(+), 8 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index d46aa3574..545315cfb 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -257,7 +257,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
         };
 
         let contents: any = "incorrect type";
-        if (type === undefined) contents = StrCast(field) === "" ? "--" : <FieldView {...props} fieldKey={fieldKey} />;
+        if (type === undefined) contents = field === undefined ? undefined : Field.toString(field as Field);//StrCast(field) === "" ? "--" : <FieldView {...props} fieldKey={fieldKey} />;
         if (type === "number") contents = typeof field === "number" ? NumCast(field) : "--" + typeof field + "--";
         if (type === "string") {
             fieldKey === "text" ?
@@ -320,6 +320,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             search = true;
         }
 
+        const placeholder = type === "number" ? "0" : contents === "" ? "--" : "undefined";
         return (
             <div className="collectionSchemaView-cellContainer" style={{ cursor: fieldIsDoc ? "grab" : "auto" }}
                 ref={dragRef} onPointerDown={this.onPointerDown} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}>
@@ -329,16 +330,16 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
                         {!search ?
                             <EditableView
                                 positions={positions.length > 0 ? positions : undefined}
-                                search={StrCast(this.props.Document._searchString) ? StrCast(this.props.Document._searchString) : undefined}
+                                search={Cast(this.props.Document._searchString, "string", null)}
                                 editing={this._isEditing}
                                 isEditingCallback={this.isEditingCallback}
                                 display={"inline"}
-                                contents={contents ? contents : type === "number" ? "0" : "undefined"}
+                                contents={contents}
                                 highlight={positions.length > 0 ? true : undefined}
                                 //contents={StrCast(contents)}
                                 height={"auto"}
                                 maxHeight={Number(MAX_ROW_HEIGHT)}
-                                placeholder={"undefined"}
+                                placeholder={placeholder}
                                 bing={() => {
                                     const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
                                     if (cfield !== undefined) {
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index 763e5a410..abbb7f6b5 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -42,7 +42,7 @@ enum ColumnType {
 
 // this map should be used for keys that should have a const type of value
 const columnTypes: Map<string, ColumnType> = new Map([
-    ["title", ColumnType.String], ["text", ColumnType.String],
+    ["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], ["currentTimecode", ColumnType.Number], ["zIndex", ColumnType.Number]
@@ -322,8 +322,8 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
             const newSchemaHeaders = oldSchemaHeaders.map(i => typeof i === "string" ? new SchemaHeaderField(i, "#f1efeb") : i);
             this.props.Document._schemaHeaders = new List<SchemaHeaderField>(newSchemaHeaders);
         } else if (this.props.Document._schemaHeaders === undefined) {
-            this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb"), new SchemaHeaderField("author", "#f1efeb"), new SchemaHeaderField("*lastModified", "#f1efeb"),
-            new SchemaHeaderField("text", "#f1efeb"), new SchemaHeaderField("type", "#f1efeb"), new SchemaHeaderField("context", "#f1efeb", ColumnType.Doc)]);
+            this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb"), new SchemaHeaderField("author", "#f1efeb"), new SchemaHeaderField("*lastModified", "#f1efeb", ColumnType.Date),
+            new SchemaHeaderField("text", "#f1efeb", ColumnType.String), new SchemaHeaderField("type", "#f1efeb"), new SchemaHeaderField("context", "#f1efeb", ColumnType.Doc)]);
         }
     }
 
diff --git a/src/fields/RichTextField.ts b/src/fields/RichTextField.ts
index 2ca5ac082..9c6233af5 100644
--- a/src/fields/RichTextField.ts
+++ b/src/fields/RichTextField.ts
@@ -28,7 +28,7 @@ export class RichTextField extends ObjectField {
     }
 
     [ToScriptString]() {
-        return `new RichTextField("${this.Data}", "${this.Text}")`;
+        return `new RichTextField("${this.Data.replace(/"/g, "'")}", "${this.Text}")`;
     }
     [ToString]() {
         return this.Text;
-- 
cgit v1.2.3-70-g09d2


From 2563f68413594248823b26e68aa3b866ab1566a4 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 17 Aug 2020 23:43:57 -0400
Subject: fixed schema view scripts to allow for layout or data doc assignment.
  fixed rich text field ToScriptField

---
 src/client/views/collections/CollectionSchemaCells.tsx | 5 +++--
 src/client/views/collections/CollectionView.tsx        | 1 -
 src/client/views/search/SearchBox.tsx                  | 2 +-
 src/fields/RichTextField.ts                            | 2 +-
 4 files changed, 5 insertions(+), 5 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index c566be7de..f95de5201 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -381,8 +381,9 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
                                 SetValue={action((value: string) => {
                                     let retVal = false;
 
-                                    if (value.startsWith(":=")) {
-                                        retVal = this.props.setComputed(value.substring(2), props.Document, this.props.rowProps.column.id!, this.props.row, this.props.col);
+                                    if (value.startsWith(":=") || value.startsWith("=:=")) {
+                                        const script = value.substring(value.startsWith("=:=") ? 3 : 2);
+                                        retVal = this.props.setComputed(script, value.startsWith(":=") ? Doc.GetProto(props.Document) : props.Document, this.props.rowProps.column.id!, this.props.row, this.props.col);
                                     } else {
                                         const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
                                         if (script.compiled) {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 2064b0be4..0aaceb7f4 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -289,7 +289,6 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
         subItems.push({ description: "Tree", event: () => func(CollectionViewType.Tree), icon: "tree" });
         subItems.push({ description: "Stacking", event: () => func(CollectionViewType.Stacking), icon: "ellipsis-v" });
         subItems.push({ description: "Stacking (AutoHeight)", event: () => func(CollectionViewType.Stacking)._autoHeight = true, icon: "ellipsis-v" });
-        subItems.push({ description: "Staff", event: () => func(CollectionViewType.Staff), icon: "music" });
         subItems.push({ description: "Multicolumn", event: () => func(CollectionViewType.Multicolumn), icon: "columns" });
         subItems.push({ description: "Multirow", event: () => func(CollectionViewType.Multirow), icon: "columns" });
         subItems.push({ description: "Masonry", event: () => func(CollectionViewType.Masonry), icon: "columns" });
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 847bda137..000bdd965 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -625,7 +625,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                 case ColumnType.Boolean: return "_b";
                 case ColumnType.Number: return "_n";
             }
-        }
+        };
         const headers = Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []);
         return headers.reduce((p: Opt<string>, header: SchemaHeaderField) => p || (header.desc !== undefined && suffixMap(header.type) ? (header.heading + suffixMap(header.type) + (header.desc ? " desc" : " asc")) : undefined), undefined);
     }
diff --git a/src/fields/RichTextField.ts b/src/fields/RichTextField.ts
index 9c6233af5..ae5f301d0 100644
--- a/src/fields/RichTextField.ts
+++ b/src/fields/RichTextField.ts
@@ -28,7 +28,7 @@ export class RichTextField extends ObjectField {
     }
 
     [ToScriptString]() {
-        return `new RichTextField("${this.Data.replace(/"/g, "'")}", "${this.Text}")`;
+        return `new RichTextField("${this.Data.replace(/"/g, "\\\"")}", "${this.Text}")`;
     }
     [ToString]() {
         return this.Text;
-- 
cgit v1.2.3-70-g09d2


From 5b7d51d47a967e679d17560771efe71522ada13a Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 19 Aug 2020 22:30:57 -0400
Subject: more cleanup of SearchBox.  made searchMatch be a tri-state for
 forward/backward/nomatch

---
 .../views/collections/CollectionSchemaCells.tsx    | 195 ++++++---------------
 .../views/collections/CollectionTreeView.tsx       |   2 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  11 +-
 src/client/views/pdf/PDFViewer.tsx                 |   2 +-
 4 files changed, 58 insertions(+), 152 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index f95de5201..626ddf288 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -35,6 +35,7 @@ import { DateField } from "../../../fields/DateField";
 import { RichTextField } from "../../../fields/RichTextField";
 import { DocumentManager } from "../../util/DocumentManager";
 import { SearchUtil } from "../../util/SearchUtil";
+import { DocumentType } from "../../documents/DocumentTypes";
 const path = require('path');
 
 library.add(faExpand);
@@ -146,10 +147,8 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
     }
 
     protected dropRef = (ele: HTMLElement | null) => {
-        this._dropDisposer && this._dropDisposer();
-        if (ele) {
-            this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this));
-        }
+        this._dropDisposer?.();
+        ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)));
     }
 
     // expandDoc = (e: React.PointerEvent) => {
@@ -326,7 +325,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
                 ref={dragRef} onPointerDown={this.onPointerDown} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}>
                 <div className={className} ref={this._focusRef} onPointerDown={onItemDown} tabIndex={-1}>
                     <div className="collectionSchemaView-cellContents"
-                        ref={type === undefined || type === "document" ? this.dropRef : null} key={props.Document[Id]}>
+                        ref={type === undefined || type === "document" ? this.dropRef : null}>
                         {!search ?
                             <EditableView
                                 positions={positions.length > 0 ? positions : undefined}
@@ -439,30 +438,22 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
         );
     }
 
-    render() {
-        return this.renderCellWithType(undefined);
-    }
+    render() { return this.renderCellWithType(undefined); }
 }
 
 @observer
 export class CollectionSchemaNumberCell extends CollectionSchemaCell {
-    render() {
-        return this.renderCellWithType("number");
-    }
+    render() { return this.renderCellWithType("number"); }
 }
 
 @observer
 export class CollectionSchemaBooleanCell extends CollectionSchemaCell {
-    render() {
-        return this.renderCellWithType("boolean");
-    }
+    render() { return this.renderCellWithType("boolean"); }
 }
 
 @observer
 export class CollectionSchemaStringCell extends CollectionSchemaCell {
-    render() {
-        return this.renderCellWithType("string");
-    }
+    render() { return this.renderCellWithType("string"); }
 }
 
 @observer
@@ -792,25 +783,14 @@ export class CollectionSchemaListCell extends CollectionSchemaCell {
         this._opened = open;
     }
 
-    // @action
-    // onChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
-    //     this._text = e.target.value;
-
-    //     // change if its a document
-    //     this._optionsList[this._selectedNum] = this._text;
-    // }
-
     @action
     onSetValue = (value: string) => {
-
-
         this._text = value;
 
         // change if its a document
         this._optionsList[this._selectedNum] = this._text;
 
         (this.prop.Document[this.prop.fieldKey] as List<any>).splice(this._selectedNum, 1, value);
-
     }
 
     @action
@@ -824,55 +804,34 @@ export class CollectionSchemaListCell extends CollectionSchemaCell {
         this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
     }
 
-
     render() {
-
-        const dragRef: React.RefObject<HTMLDivElement> = React.createRef();
-
         let type = "list";
-
         let link = false;
-        let doc = false;
         const reference = React.createRef<HTMLDivElement>();
 
         if (typeof this._field === "object" && this._optionsList[0]) {
-
-            const options = this._optionsList.map((element, index) => {
-
-                if (element instanceof Doc) {
-                    doc = true;
-                    type = "document";
-                    if (this.prop.fieldKey.toLowerCase() === "links") {
-                        link = true;
-                        type = "link";
+            const options = !this._opened ? (null) : <div>
+                {this._optionsList.map((element, index) => {
+                    let title = "";
+                    if (element instanceof Doc) {
+                        type = "document";
+                        if (this.prop.fieldKey.toLowerCase() === "links") {
+                            link = true;
+                            type = "link";
+                        }
+                        title = StrCast(element.title);
                     }
-                    const document = FieldValue(Cast(element, Doc));
-                    const title = element.title;
-                    return <div
-                        className="collectionSchemaView-dropdownOption"
-                        onPointerDown={(e) => { this.onSelected(StrCast(element.title), index); }}
-                        style={{ padding: "6px" }}>
+                    return <div className="collectionSchemaView-dropdownOption" style={{ padding: "6px" }}
+                        onPointerDown={(e) => this.onSelected(StrCast(element), index)} >
+                        {element}
                         {title}
                     </div>;
-
-                } else {
-                    return <div
-                        className="collectionSchemaView-dropdownOption"
-                        onPointerDown={(e) => { this.onSelected(StrCast(element), index); }}
-                        style={{ padding: "6px" }}>{element}</div>;
-                }
-            });
+                })}
+            </div>;
 
             const plainText = <div style={{ padding: "5.9px" }}>{this._text}</div>;
-            // const textarea = <textarea onChange={this.onChange} value={this._text}
-            //     onFocus={doc ? this.onFocus : undefined}
-            //     onBlur={doc ? e => this._overlayDisposer?.() : undefined}
-            //     style={{ resize: "none" }}
-            //     placeholder={"select an item"}></textarea>;
-
-            const textarea = <div className="collectionSchemaView-cellContents"
-                style={{ padding: "5.9px" }}
-                ref={type === undefined || type === "document" ? this.dropRef : null} key={this.prop.Document[Id]}>
+            const textarea = <div className="collectionSchemaView-cellContents" key={this.prop.Document[Id]} style={{ padding: "5.9px" }}
+                ref={type === undefined || type === "document" ? this.dropRef : null} >
                 <EditableView
                     editing={this._isEditing}
                     isEditingCallback={this.isEditingCallback}
@@ -880,11 +839,8 @@ export class CollectionSchemaListCell extends CollectionSchemaCell {
                     contents={this._text}
                     height={"auto"}
                     maxHeight={Number(MAX_ROW_HEIGHT)}
-                    GetValue={() => {
-                        return this._text;
-                    }}
+                    GetValue={() => this._text}
                     SetValue={action((value: string) => {
-
                         // add special for params 
                         this.onSetValue(value);
                         return true;
@@ -893,37 +849,26 @@ export class CollectionSchemaListCell extends CollectionSchemaCell {
             </div >;
 
             //☰
-
-            const dropdown = <div>
-                {options}
-            </div>;
-
             return (
                 <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
                     <div className="collectionSchemaView-cellContents" key={this._document[Id]} ref={reference}>
                         <div className="collectionSchemaView-dropDownWrapper">
-                            <button type="button" className="collectionSchemaView-dropdownButton" onClick={(e) => { this.toggleOpened(!this._opened); }}
-                                style={{ right: "length", position: "relative" }}>
-                                {this._opened ? <FontAwesomeIcon icon="caret-up" size="lg" ></FontAwesomeIcon>
-                                    : <FontAwesomeIcon icon="caret-down" size="lg" ></FontAwesomeIcon>}
+                            <button type="button" className="collectionSchemaView-dropdownButton" style={{ right: "length", position: "relative" }}
+                                onClick={e => this.toggleOpened(!this._opened)} >
+                                <FontAwesomeIcon icon={this._opened ? "caret-up" : "caret-down"} size="lg" />
                             </button>
                             <div className="collectionSchemaView-dropdownText"> {link ? plainText : textarea} </div>
                         </div>
-
-                        {this._opened ? dropdown : null}
+                        {options}
                     </div >
                 </div>
             );
-        } else {
-            return this.renderCellWithType("list");
         }
+        return this.renderCellWithType("list");
     }
 }
 
 
-
-
-
 @observer
 export class CollectionSchemaCheckboxCell extends CollectionSchemaCell {
     @observable private _isChecked: boolean = typeof this.props.rowProps.original[this.props.rowProps.column.id as string] === "boolean" ? BoolCast(this.props.rowProps.original[this.props.rowProps.column.id as string]) : false;
@@ -932,15 +877,13 @@ export class CollectionSchemaCheckboxCell extends CollectionSchemaCell {
     toggleChecked = (e: React.ChangeEvent<HTMLInputElement>) => {
         this._isChecked = e.target.checked;
         const script = CompileScript(e.target.checked.toString(), { requiredType: "boolean", addReturn: true, params: { this: Doc.name } });
-        if (script.compiled) {
-            this.applyToDoc(this._document, this.props.row, this.props.col, script.run);
-        }
+        script.compiled && this.applyToDoc(this._document, this.props.row, this.props.col, script.run);
     }
 
     render() {
         const reference = React.createRef<HTMLDivElement>();
         const onItemDown = (e: React.PointerEvent) => {
-            (!this.props.CollectionView || !this.props.CollectionView.props.isSelected() ? undefined :
+            (!this.props.CollectionView?.props.isSelected() ? undefined :
                 SetupDrag(reference, () => this._document, this.props.moveDocument, this.props.Document.schemaDoc ? "copy" : undefined)(e));
         };
         return (
@@ -956,62 +899,28 @@ export class CollectionSchemaCheckboxCell extends CollectionSchemaCell {
 
 @observer
 export class CollectionSchemaButtons extends CollectionSchemaCell {
-
     render() {
+        const doc = this.props.rowProps.original;
+        const searchMatch = (backward: boolean = true) => { doc.searchMatch = undefined; setTimeout(() => doc.searchMatch = backward, 0); };
         // const reference = React.createRef<HTMLDivElement>();
         // const onItemDown = (e: React.PointerEvent) => {
         //     (!this.props.CollectionView || !this.props.CollectionView.props.isSelected() ? undefined :
         //         SetupDrag(reference, () => this._document, this.props.moveDocument, this.props.Document.schemaDoc ? "copy" : undefined)(e));
         // };
-        const doc = this.props.rowProps.original;
-        let buttons: JSX.Element | undefined = undefined;
-        buttons = <div style={{
-            paddingTop: 8,
-            paddingLeft: 3,
-        }}><button onClick={() => {
-            doc.searchMatch = false;
-            setTimeout(() => doc.searchMatch = true, 0);
-        }} style={{ padding: 2, left: 77 }}>
-                <FontAwesomeIcon icon="arrow-up" size="sm" />
-            </button>
-            <button onClick={() => {
-                {
-                    doc.searchMatchAlt = false;
-                    setTimeout(() => doc.searchMatchAlt = true, 0);
-                }
-            }} style={{ padding: 2 }}>
-                <FontAwesomeIcon icon="arrow-down" size="sm" />
-            </button></div>;
-        const type = StrCast(doc.type);
-        if (type === "pdf") {
-            buttons = <div><button
-                style={{
-                    position: "relative",
-                    height: 30,
-                    width: 28,
-                    left: 1,
-                }}
-
-                onClick={() => {
-                    doc.searchMatch = false;
-                    setTimeout(() => doc.searchMatch = true, 0);
-                }}>
-                <FontAwesomeIcon icon="arrow-down" size="sm" />
-            </button></div >;
-        }
-        else if (type !== "rtf") {
-            buttons = undefined;
-        }
-
-        if (BoolCast(this.props.Document._searchDoc) === true) {
-
-        }
-        else {
-            buttons = undefined;
-        }
-        return (
-            <div> {buttons}</div>
-        );
-    }
-}
-
+        return !BoolCast(this.props.Document._searchDoc) ? <></>
+            : StrCast(doc.type) === DocumentType.PDF ?
+                <button style={{ position: "relative", height: 30, width: 28, left: 1, }} onClick={() => searchMatch(false)}>
+                    <FontAwesomeIcon icon="arrow-down" size="sm" />
+                </button>
+                : StrCast(doc.type) === DocumentType.RTF ?
+                    <div style={{ paddingTop: 8, paddingLeft: 3, }} >
+                        <button style={{ padding: 2, left: 77 }} onClick={() => searchMatch(true)}>
+                            <FontAwesomeIcon icon="arrow-up" size="sm" />
+                        </button>
+                        <button style={{ padding: 2 }} onClick={() => searchMatch(false)} >
+                            <FontAwesomeIcon icon="arrow-down" size="sm" />
+                        </button>
+                    </div> :
+                    <></>;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index f23fa8eb6..0f6274663 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -469,7 +469,7 @@ class TreeView extends React.Component<TreeViewProps> {
         return <>
             <div className="docContainer" ref={this._tref} title="click to edit title" id={`docContainer-${this.props.parentKey}`}
                 style={{
-                    fontWeight: this.doc.searchMatch ? "bold" : undefined,
+                    fontWeight: this.doc.searchMatch !== undefined ? "bold" : undefined,
                     textDecoration: Doc.GetT(this.doc, "title", "string", true) ? "underline" : undefined,
                     outline: BoolCast(this.doc.workspaceBrush) ? "dashed 1px #06123232" : undefined,
                     pointerEvents: this.props.active() || SnappingManager.GetIsDragging() ? undefined : "none"
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 0f2f90c1d..d58d75226 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -374,7 +374,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             this._editorView.dispatch(tr.addMark(flattened[lastSel].from, flattened[lastSel].to, link));
         }
     }
-    public highlightSearchTerms = (terms: string[], alt: boolean) => {
+    public highlightSearchTerms = (terms: string[], backward: boolean) => {
         if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
 
 
@@ -391,7 +391,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             }
             else {
                 this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
-                if (alt === true) {
+                if (backward === true) {
                     if (this._searchIndex > 1) {
                         this._searchIndex += -2;
                     }
@@ -907,12 +907,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
 
         this.setupEditor(this.config, this.props.fieldKey);
 
-        this._disposers.searchAlt = reaction(() => this.rootDoc.searchMatchAlt,
-            search => search ? this.highlightSearchTerms([Doc.SearchQuery()], false) : this.unhighlightSearchTerms(),
-            { fireImmediately: true });
         this._disposers.search = reaction(() => this.rootDoc.searchMatch,
-            search => search ? this.highlightSearchTerms([Doc.SearchQuery()], true) : this.unhighlightSearchTerms(),
-            { fireImmediately: this.rootDoc.searchMatch ? true : false });
+            search => search !== undefined ? this.highlightSearchTerms([Doc.SearchQuery()], BoolCast(search)) : this.unhighlightSearchTerms(),
+            { fireImmediately: this.rootDoc.searchMatch !== undefined ? true : false });
 
         this._disposers.record = reaction(() => this._recording,
             () => {
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 965d568e6..0916e8b0c 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -152,7 +152,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
         this._mainCont.current && (this._mainCont.current.scrollTop = this.layoutDoc._scrollTop || 0);
         this._searchReactionDisposer = reaction(() => this.Document.searchMatch,
             m => {
-                if (m) (this._lastSearch = true) && this.search(Doc.SearchQuery(), true);
+                if (m !== undefined) (this._lastSearch = true) && this.search(Doc.SearchQuery(), true);
                 else !(this._lastSearch = false) && setTimeout(() => !this._lastSearch && this.search("", false, true), 200);
             }, { fireImmediately: true });
 
-- 
cgit v1.2.3-70-g09d2


From da8901bef2d4a0362354c69fe486076a67f8efc4 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 19 Aug 2020 22:39:51 -0400
Subject: cleaning lint errors

---
 src/client/views/PropertiesButtons.tsx                    |  2 +-
 src/client/views/collections/CollectionMenu.tsx           | 12 ++++++------
 src/client/views/collections/CollectionSchemaCells.tsx    | 11 ++---------
 src/client/views/collections/CollectionSchemaHeaders.tsx  |  2 +-
 src/client/views/collections/SchemaTable.tsx              |  2 +-
 src/client/views/nodes/DocumentView.tsx                   |  2 +-
 src/client/views/nodes/PresBox.tsx                        |  2 +-
 src/client/views/nodes/formattedText/FormattedTextBox.tsx | 10 ++++++----
 src/fields/Doc.ts                                         | 10 +++++-----
 9 files changed, 24 insertions(+), 29 deletions(-)

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

diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index e352db562..9e776c652 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -301,7 +301,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
             const dragData = new DragManager.DocumentDragData([this.selectedDoc]);
             const [left, top] = [e.clientX, e.clientY];
             dragData.dropAction = "alias";
-            DragManager.StartDocumentDrag([this._dragRef.current!], dragData, left, top, {
+            DragManager.StartDocumentDrag([this._dragRef.current], dragData, left, top, {
                 offsetX: dragData.offset[0],
                 offsetY: dragData.offset[1],
                 hideSource: false
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index cf053e1ca..388eda2b3 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -624,10 +624,10 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     }
 
     @computed get _url() {
-        return this.selectedDoc ? Cast(this.selectedDoc["data"], WebField, null)?.url.toString() : "hello";
+        return this.selectedDoc ? Cast(this.selectedDoc.data, WebField, null)?.url.toString() : "hello";
     }
 
-    set _url(value) { this.selectedDoc && (this.selectedDoc["data"] = value); }
+    set _url(value) { this.selectedDoc && (this.selectedDoc.data = value); }
 
     @action
     submitURL = () => {
@@ -637,7 +637,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
             const future = this.selectedDoc ? Cast(this.selectedDoc["data-future"], listSpec("string"), null) : null;
             const history = this.selectedDoc ? Cast(this.selectedDoc["data-history"], listSpec("string"), null) : [];
             const annos = this.selectedDoc ? DocListCast(this.selectedDoc["data-annotations"]) : undefined;
-            const url = this.selectedDoc ? Cast(this.selectedDoc["data"], WebField, null)?.url.toString() : null;
+            const url = this.selectedDoc ? Cast(this.selectedDoc.data, WebField, null)?.url.toString() : null;
             if (url) {
                 if (history === undefined) {
                     this.selectedDoc && (this.selectedDoc["data-history"] = new List<string>([url]));
@@ -648,7 +648,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
                 future && (future.length = 0);
                 this.selectedDoc && (this.selectedDoc["data-" + this.urlHash(url)] = new List<Doc>(annos));
             }
-            this.selectedDoc && (this.selectedDoc["data"] = new WebField(URLy));
+            this.selectedDoc && (this.selectedDoc.data = new WebField(URLy));
             this.selectedDoc && (this.selectedDoc["data-annotations"] = new List<Doc>([]));
         } catch (e) {
             console.log("WebBox URL error:" + this._url);
@@ -682,7 +682,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
         if (future?.length) {
             history?.push(this._url);
             this.selectedDoc && (this.selectedDoc["data-annotations-" + this.urlHash(this._url)] = new List<Doc>(DocListCast(this.selectedDoc["data-annotations"])));
-            this.selectedDoc && (this.selectedDoc["data"] = new WebField(new URL(this._url = future.pop()!)));
+            this.selectedDoc && (this.selectedDoc.data = new WebField(new URL(this._url = future.pop()!)));
             this.selectedDoc && (this.selectedDoc["data-annotations"] = new List<Doc>(DocListCast(this.selectedDoc["data-annotations" + "-" + this.urlHash(this._url)])));
         }
     }
@@ -695,7 +695,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
             if (future === undefined) this.selectedDoc && (this.selectedDoc["data-future"] = new List<string>([this._url]));
             else future.push(this._url);
             this.selectedDoc && (this.selectedDoc["data-annotations" + "-" + this.urlHash(this._url)] = new List<Doc>(DocListCast(this.selectedDoc["data-annotations"])));
-            this.selectedDoc && (this.selectedDoc["data"] = new WebField(new URL(this._url = history.pop()!)));
+            this.selectedDoc && (this.selectedDoc.data = new WebField(new URL(this._url = history.pop()!)));
             this.selectedDoc && (this.selectedDoc["data-annotations"] = new List<Doc>(DocListCast(this.selectedDoc["data-annotations" + "-" + this.urlHash(this._url)])));
         }
     }
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 626ddf288..ea786800c 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -778,17 +778,10 @@ export class CollectionSchemaListCell extends CollectionSchemaCell {
     @observable private _text = "select an item";
     @observable private _selectedNum = 0;
 
-    @action
-    toggleOpened(open: boolean) {
-        this._opened = open;
-    }
-
     @action
     onSetValue = (value: string) => {
-        this._text = value;
-
         // change if its a document
-        this._optionsList[this._selectedNum] = this._text;
+        this._optionsList[this._selectedNum] = this._text = value;
 
         (this.prop.Document[this.prop.fieldKey] as List<any>).splice(this._selectedNum, 1, value);
     }
@@ -854,7 +847,7 @@ export class CollectionSchemaListCell extends CollectionSchemaCell {
                     <div className="collectionSchemaView-cellContents" key={this._document[Id]} ref={reference}>
                         <div className="collectionSchemaView-dropDownWrapper">
                             <button type="button" className="collectionSchemaView-dropdownButton" style={{ right: "length", position: "relative" }}
-                                onClick={e => this.toggleOpened(!this._opened)} >
+                                onClick={action(e => this._opened = !this._opened)} >
                                 <FontAwesomeIcon icon={this._opened ? "caret-up" : "caret-down"} size="lg" />
                             </button>
                             <div className="collectionSchemaView-dropdownText"> {link ? plainText : textarea} </div>
diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx
index 73f319e9b..34a8bfa24 100644
--- a/src/client/views/collections/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/CollectionSchemaHeaders.tsx
@@ -275,7 +275,7 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
         document.removeEventListener("pointerdown", this.detectClick);
         const filters = Cast(this.props.Document._docFilters, listSpec("string"));
         if (filters?.includes(this._key)) {
-            runInAction(() => { this.closeResultsVisibility = "contents" });
+            runInAction(() => this.closeResultsVisibility = "contents");
         }
     }
 
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index 489c5e540..6ec9783e2 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -415,7 +415,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     createRow = action(() => {
         this.props.addDocument(Docs.Create.TextDocument("", { title: "", _width: 100, _height: 30 }));
         this._focusedCell = { row: this.childDocs.length, col: this._focusedCell.col };
-    })
+    });
 
     @undoBatch
     @action
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 7cf6b0f39..590befd86 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -713,7 +713,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
 
         const cm = ContextMenu.Instance;
-        if (!cm || ((e as any)?.nativeEvent as any)?.SchemaHandled) return;
+        if (!cm || (e?.nativeEvent as any)?.SchemaHandled) return;
 
         const customScripts = Cast(this.props.Document.contextMenuScripts, listSpec(ScriptField), []);
         Cast(this.props.Document.contextMenuLabels, listSpec("string"), []).forEach((label, i) =>
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index f39413e9f..d30ea03b1 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -1061,7 +1061,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 DockedFrameRenderer.PinDoc(doc, false);
                 this.gotoDocument(this.childDocs.length, this.itemIndex);
             } else {
-                this.props.addDocTab(doc as Doc, "onRight");
+                this.props.addDocTab(doc, "onRight");
             }
         }
     }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index d58d75226..6b4115e53 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -510,10 +510,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             let index = 0, foundAt;
             const ep = this.getNodeEndpoints(pm.state.doc, node);
             const regexp = find.replace("*", "");
-            if (regexp) while (ep && (foundAt = node.textContent.slice(index).search(regexp, "i")) > -1) {
-                const sel = new TextSelection(pm.state.doc.resolve(ep.from + index + foundAt + 1), pm.state.doc.resolve(ep.from + index + foundAt + find.length + 1));
-                ret.push(sel);
-                index = index + foundAt + find.length;
+            if (regexp) {
+                while (ep && (foundAt = node.textContent.slice(index).search(regexp)) > -1) {
+                    const sel = new TextSelection(pm.state.doc.resolve(ep.from + index + foundAt + 1), pm.state.doc.resolve(ep.from + index + foundAt + find.length + 1));
+                    ret.push(sel);
+                    index = index + foundAt + find.length;
+                }
             }
         } else {
             node.content.forEach((child, i) => ret = ret.concat(this.findInNode(pm, child, find)));
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 4797fb4cb..3fdeb8e71 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -206,11 +206,11 @@ export class Doc extends RefField {
 
     private [Self] = this;
     private [SelfProxy]: any;
-    public [FieldsSym] = (clear?: boolean) => { return clear ? this.___fields = this.___fieldKeys = {} : this.___fields; }
-    public [WidthSym] = () => { return NumCast(this[SelfProxy]._width); }
-    public [HeightSym] = () => { return NumCast(this[SelfProxy]._height); }
-    public [ToScriptString] = () => { return `DOC-"${this[Self][Id]}"-`; }
-    public [ToString] = () => { return `Doc(${GetEffectiveAcl(this) === AclPrivate ? "-inaccessible-" : this.title})`; }
+    public [FieldsSym] = (clear?: boolean) => clear ? this.___fields = this.___fieldKeys = {} : this.___fields;
+    public [WidthSym] = () => NumCast(this[SelfProxy]._width);
+    public [HeightSym] = () => NumCast(this[SelfProxy]._height);
+    public [ToScriptString] = () => `DOC-"${this[Self][Id]}"-`;
+    public [ToString] = () => `Doc(${GetEffectiveAcl(this) === AclPrivate ? "-inaccessible-" : this.title})`;
     public get [LayoutSym]() { return this[SelfProxy].__LAYOUT__; }
     public get [DataSym]() {
         const self = this[SelfProxy];
-- 
cgit v1.2.3-70-g09d2


From 4ed30f48bd0c87f0a5ccb484d78bf4601ab6ff74 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 22 Aug 2020 09:49:56 -0400
Subject: switched search from writiing searchMatch to matched docs to instead
 store in a run-time observableMap.  This allows simultaneous searches by
 different users.

---
 .../views/collections/CollectionSchemaCells.tsx    | 26 ++++++---------
 .../views/collections/CollectionTreeView.tsx       |  2 +-
 src/client/views/nodes/FieldView.tsx               |  3 --
 .../views/nodes/formattedText/FormattedTextBox.tsx | 39 ++++++++++------------
 src/client/views/pdf/PDFViewer.tsx                 |  4 +--
 src/client/views/search/SearchBox.tsx              | 34 ++++++++-----------
 src/fields/Doc.ts                                  | 25 ++++++++++++++
 7 files changed, 69 insertions(+), 64 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index ea786800c..4bd69041b 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -894,26 +894,22 @@ export class CollectionSchemaCheckboxCell extends CollectionSchemaCell {
 export class CollectionSchemaButtons extends CollectionSchemaCell {
     render() {
         const doc = this.props.rowProps.original;
-        const searchMatch = (backward: boolean = true) => { doc.searchMatch = undefined; setTimeout(() => doc.searchMatch = backward, 0); };
+        const searchMatch = (backward: boolean = true) => Doc.SearchMatchNext(doc, backward);
         // const reference = React.createRef<HTMLDivElement>();
         // const onItemDown = (e: React.PointerEvent) => {
         //     (!this.props.CollectionView || !this.props.CollectionView.props.isSelected() ? undefined :
         //         SetupDrag(reference, () => this._document, this.props.moveDocument, this.props.Document.schemaDoc ? "copy" : undefined)(e));
         // };
         return !BoolCast(this.props.Document._searchDoc) ? <></>
-            : StrCast(doc.type) === DocumentType.PDF ?
-                <button style={{ position: "relative", height: 30, width: 28, left: 1, }} onClick={() => searchMatch(false)}>
-                    <FontAwesomeIcon icon="arrow-down" size="sm" />
-                </button>
-                : StrCast(doc.type) === DocumentType.RTF ?
-                    <div style={{ paddingTop: 8, paddingLeft: 3, }} >
-                        <button style={{ padding: 2, left: 77 }} onClick={() => searchMatch(true)}>
-                            <FontAwesomeIcon icon="arrow-up" size="sm" />
-                        </button>
-                        <button style={{ padding: 2 }} onClick={() => searchMatch(false)} >
-                            <FontAwesomeIcon icon="arrow-down" size="sm" />
-                        </button>
-                    </div> :
-                    <></>;
+            : [DocumentType.PDF, DocumentType.RTF].includes(StrCast(doc.type) as DocumentType) ?
+                <div style={{ paddingTop: 8, paddingLeft: 3, }} >
+                    <button style={{ padding: 2, left: 77 }} onClick={() => searchMatch(true)}>
+                        <FontAwesomeIcon icon="arrow-up" size="sm" />
+                    </button>
+                    <button style={{ padding: 2 }} onClick={() => searchMatch(false)} >
+                        <FontAwesomeIcon icon="arrow-down" size="sm" />
+                    </button>
+                </div> :
+                <></>;
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 4503b0fb3..8440d3e9b 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -472,7 +472,7 @@ class TreeView extends React.Component<TreeViewProps> {
         return <>
             <div className="docContainer" ref={this._tref} title="click to edit title" id={`docContainer-${this.props.parentKey}`}
                 style={{
-                    fontWeight: this.doc.searchMatch !== undefined ? "bold" : undefined,
+                    fontWeight: Doc.IsSearchMatch(this.doc) !== undefined ? "bold" : undefined,
                     textDecoration: Doc.GetT(this.doc, "title", "string", true) ? "underline" : undefined,
                     outline: BoolCast(this.doc.dashboardBrush) ? "dashed 1px #06123232" : undefined,
                     pointerEvents: this.props.active() || SnappingManager.GetIsDragging() ? undefined : "none"
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index d95951f3a..3726f1d5f 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -58,9 +58,6 @@ export interface FieldViewProps {
 
     ChromeHeight?: () => number;
     childLayoutTemplate?: () => Opt<Doc>;
-    highlighting?: string[];
-    lines?: string[];
-    doc?: Doc;
     // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React)
     height?: number;
     width?: number;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 6b4115e53..5250a8f58 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -376,8 +376,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     }
     public highlightSearchTerms = (terms: string[], backward: boolean) => {
         if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
-
-
             const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
             const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true });
             const res = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
@@ -385,24 +383,19 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             let tr = this._editorView.state.tr;
             const flattened: TextSelection[] = [];
             res.map(r => r.map(h => flattened.push(h)));
-            if (BoolCast(Doc.GetProto(this.dataDoc).resetSearch) === true) {
-                this._searchIndex = 0;
-                Doc.GetProto(this.dataDoc).resetSearch = undefined;
-            }
-            else {
-                this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
-                if (backward === true) {
-                    if (this._searchIndex > 1) {
-                        this._searchIndex += -2;
-                    }
-                    else if (this._searchIndex === 1) {
-                        this._searchIndex = length - 1;
-                    }
-                    else if (this._searchIndex === 0 && length !== 1) {
-                        this._searchIndex = length - 2;
-                    }
-
+            console.log("Search:" + this.rootDoc.title + " " + this._searchIndex + " => " + (this._searchIndex + 1 > flattened.length - 1 ? 0 : this._searchIndex + 1));
+            this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
+            if (backward === true) {
+                if (this._searchIndex > 1) {
+                    this._searchIndex += -2;
+                }
+                else if (this._searchIndex === 1) {
+                    this._searchIndex = length - 1;
                 }
+                else if (this._searchIndex === 0 && length !== 1) {
+                    this._searchIndex = length - 2;
+                }
+
             }
 
             const lastSel = Math.min(flattened.length - 1, this._searchIndex);
@@ -909,9 +902,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
 
         this.setupEditor(this.config, this.props.fieldKey);
 
-        this._disposers.search = reaction(() => this.rootDoc.searchMatch,
-            search => search !== undefined ? this.highlightSearchTerms([Doc.SearchQuery()], BoolCast(search)) : this.unhighlightSearchTerms(),
-            { fireImmediately: this.rootDoc.searchMatch !== undefined ? true : false });
+        this._disposers.search = reaction(() => Doc.IsSearchMatch(this.rootDoc),
+            search => {
+                search ? this.highlightSearchTerms([Doc.SearchQuery()], search.searchMatch < 0) : this.unhighlightSearchTerms();
+            },
+            { fireImmediately: Doc.IsSearchMatch(this.rootDoc) ? true : false });
 
         this._disposers.record = reaction(() => this._recording,
             () => {
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 0916e8b0c..f2aa9fa3f 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -150,9 +150,9 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
         runInAction(() => this._showWaiting = this._showCover = true);
         this.props.startupLive && this.setupPdfJsViewer();
         this._mainCont.current && (this._mainCont.current.scrollTop = this.layoutDoc._scrollTop || 0);
-        this._searchReactionDisposer = reaction(() => this.Document.searchMatch,
+        this._searchReactionDisposer = reaction(() => Doc.IsSearchMatch(this.rootDoc),
             m => {
-                if (m !== undefined) (this._lastSearch = true) && this.search(Doc.SearchQuery(), true);
+                if (m) (this._lastSearch = true) && this.search(Doc.SearchQuery(), m.searchMatch > 0);
                 else !(this._lastSearch = false) && setTimeout(() => !this._lastSearch && this.search("", false, true), 200);
             }, { fireImmediately: true });
 
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index d7c065a75..c571adefe 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -84,21 +84,17 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         Object.values(this._disposers).forEach(disposer => disposer?.());
     }
 
-    @action
-    getViews = (doc: Doc) => SearchUtil.GetViewsOfDocument(doc)
-
     @action.bound
     onChange(e: React.ChangeEvent<HTMLInputElement>) {
         this.layoutDoc._searchString = e.target.value;
         this.newsearchstring = e.target.value;
         if (e.target.value === "") {
             if (this.currentSelectedCollection) {
-                this.doLoop(this.currentSelectedCollection, undefined);
+                this.setSearchDocsRecursive(this.currentSelectedCollection, undefined);
             }
             this.closeSearch(false);
 
             if (this.currentSelectedCollection !== undefined) {
-                this.currentSelectedCollection.props.Document._searchDocs = new List<Doc>([]);
                 this.currentSelectedCollection = undefined;
                 this.props.Document.selectedDoc = undefined;
             }
@@ -242,14 +238,12 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             while (docs.length > 0) {
                 newarray = [];
                 docs.forEach((d) => {
-                    if (d.data !== undefined) {
-                        newarray.push(...DocListCast(d.data));
-                    }
-                    const hlights: string[] = [];
+                    d.data && newarray.push(...DocListCast(d.data));
+                    const hlights = new Set<string>();
                     this.documentKeys(d).forEach(key =>
-                        Field.toString(d[key] as Field).toLowerCase().includes(query) && !hlights.includes(key) && hlights.push(key));
-                    if (hlights.length > 0) {
-                        found.push([d, hlights, []]);
+                        Field.toString(d[key] as Field).toLowerCase().includes(query) && hlights.add(key));
+                    if (Array.from(hlights.keys()).length > 0) {
+                        found.push([d, Array.from(hlights.keys()), []]);
                         docsforFilter.push(d);
                     }
                 });
@@ -259,7 +253,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             this.docsforfilter = docsforFilter;
             if (this.filter === true) {
                 selectedCollection.props.Document._searchDocs = new List<Doc>(docsforFilter);
-                this.doLoop(selectedCollection, docsforFilter);
+                this.setSearchDocsRecursive(selectedCollection, docsforFilter);
             }
             this._numTotalResults = found.length;
             this.realTotalResults = found.length;
@@ -285,7 +279,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
     @action
     submitSearch = async (reset?: boolean) => {
         if (this.currentSelectedCollection !== undefined) {
-            this.doLoop(this.currentSelectedCollection, undefined);
+            this.setSearchDocsRecursive(this.currentSelectedCollection, undefined);
         }
         if (reset) {
             this.layoutDoc._searchString = "";
@@ -434,7 +428,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
     closeSearch = (closesearchbar = true) => {
         this._results.forEach(result => {
             Doc.UnBrushDoc(result[0]);
-            result[0].searchMatch = undefined;
+            Doc.ClearSearchMatches();
         });
         closesearchbar && (this._searchbarOpen = false);
     }
@@ -479,9 +473,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                 const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
                 const lines = new List<string>(result[2]);
                 highlights.forEach((item) => headers.add(item));
-                result[0].lines = lines;
-                result[0].highlighting = highlights.join(", ");
-                result[0].searchMatch = true;
+                Doc.SetSearchMatch(result[0], { searchMatch: 1 });
                 if (i < this._visibleDocuments.length) {
                     this._visibleDocuments[i] = result[0];
                     Doc.BrushDoc(result[0]);
@@ -530,7 +522,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         this._searchFullDB = scope;
         this.dataDoc[this.fieldKey] = new List<Doc>([]);
         if (this.currentSelectedCollection !== undefined) {
-            this.doLoop(this.currentSelectedCollection, undefined);
+            this.setSearchDocsRecursive(this.currentSelectedCollection, undefined);
         }
         this.submitSearch();
     }
@@ -566,7 +558,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         </div>;
     }
 
-    doLoop = (collectionView: DocumentView, filter: Doc[] | undefined) => {
+    setSearchDocsRecursive = (collectionView: DocumentView, filter: Doc[] | undefined) => {
         let docs = DocListCast(collectionView.dataDoc[Doc.LayoutFieldKey(collectionView.dataDoc)]);
         let newarray: Doc[] = [];
         while (docs.length > 0) {
@@ -614,7 +606,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                                             onPointerDown={e => { e.stopPropagation(); SetupDrag(this.collectionRef, () => this.layoutDoc._searchString ? this.startDragCollection() : undefined); }}
                                             onClick={action(() => {
                                                 this.filter = !this.filter && !this._searchFullDB;
-                                                this.currentSelectedCollection && this.doLoop(this.currentSelectedCollection, this.filter ? this.docsforfilter : undefined);
+                                                this.currentSelectedCollection && this.setSearchDocsRecursive(this.currentSelectedCollection, this.filter ? this.docsforfilter : undefined);
                                             })} />
                                     </div>
                                 </Tooltip>
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index c78b01def..dc274a063 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -23,6 +23,7 @@ import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, u
 import { LinkManager } from "../client/util/LinkManager";
 import JSZip = require("jszip");
 import { saveAs } from "file-saver";
+import { result } from "lodash";
 
 export namespace Field {
     export function toKeyValueString(doc: Doc, key: string): string {
@@ -881,6 +882,7 @@ export namespace Doc {
 
     export class DocBrush {
         BrushedDoc: ObservableMap<Doc, boolean> = new ObservableMap();
+        SearchMatchDoc: ObservableMap<Doc, { searchMatch: number }> = new ObservableMap();
     }
     const brushManager = new DocBrush();
 
@@ -906,6 +908,29 @@ export namespace Doc {
     export function SetSelectedTool(tool: InkTool) { Doc.UserDoc().activeInkTool = tool; }
     export function GetSelectedTool(): InkTool { return StrCast(Doc.UserDoc().activeInkTool, InkTool.None) as InkTool; }
     export function SetUserDoc(doc: Doc) { manager._user_doc = doc; }
+
+    export function IsSearchMatch(doc: Doc) {
+        return computedFn(function IsSearchMatch(doc: Doc) {
+            return brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) :
+                brushManager.SearchMatchDoc.has(Doc.GetProto(doc)) ? brushManager.SearchMatchDoc.get(Doc.GetProto(doc)) : undefined;
+        })(doc);
+    }
+    export function SetSearchMatch(doc: Doc, results: { searchMatch: number }) {
+        if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc;
+        brushManager.SearchMatchDoc.set(doc, results);
+        return doc;
+    }
+    export function SearchMatchNext(doc: Doc, backward: boolean) {
+        if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc;
+        const result = brushManager.SearchMatchDoc.get(doc);
+        const num = Math.abs(result?.searchMatch || 0) + 1;
+        runInAction(() => result && brushManager.SearchMatchDoc.set(doc, { searchMatch: backward ? -num : num }));
+        return doc;
+    }
+    export function ClearSearchMatches() {
+        brushManager.SearchMatchDoc.clear();
+    }
+
     export function IsBrushed(doc: Doc) {
         return computedFn(function IsBrushed(doc: Doc) {
             return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetProto(doc));
-- 
cgit v1.2.3-70-g09d2


From 88b06945c8a1fcb7bc518de878a4894de70dda94 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 22 Aug 2020 14:21:41 -0400
Subject: major overhaul of search to avoid writing anything to filtered
 documents and to make the UI work properly.

---
 src/Utils.ts                                       |   2 +
 src/client/documents/Documents.ts                  |   5 +-
 src/client/util/CurrentUserUtils.ts                |   2 +-
 src/client/views/GestureOverlay.tsx                |   3 +-
 src/client/views/MainView.tsx                      |  11 +-
 src/client/views/OverlayView.tsx                   |   3 +-
 src/client/views/Palette.tsx                       |   3 +-
 src/client/views/TemplateMenu.tsx                  |   3 +-
 .../views/collections/CollectionDockingView.tsx    |   4 +-
 .../views/collections/CollectionLinearView.tsx     |   1 +
 src/client/views/collections/CollectionMenu.tsx    |  14 ++-
 .../views/collections/CollectionSchemaCells.tsx    |   6 +-
 .../views/collections/CollectionSchemaHeaders.tsx  |  26 ++---
 .../views/collections/CollectionSchemaView.scss    |   3 +
 .../views/collections/CollectionSchemaView.tsx     |  17 +--
 .../views/collections/CollectionStackingView.tsx   |   1 +
 src/client/views/collections/CollectionSubView.tsx |  26 ++---
 .../views/collections/CollectionTreeView.tsx       |   4 +-
 src/client/views/collections/CollectionView.tsx    |   3 +-
 src/client/views/collections/SchemaTable.tsx       |   3 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   1 +
 .../collectionFreeForm/PropertiesView.tsx          |   3 +-
 .../CollectionMulticolumnView.tsx                  |   1 +
 .../CollectionMultirowView.tsx                     |   1 +
 src/client/views/nodes/DocHolderBox.tsx            |   2 +
 src/client/views/nodes/DocumentView.tsx            |   2 +
 src/client/views/nodes/FieldView.tsx               |   1 +
 src/client/views/nodes/ImageBox.tsx                |   1 +
 src/client/views/nodes/LinkDocPreview.tsx          |   3 +-
 src/client/views/nodes/PDFBox.tsx                  |   2 +-
 src/client/views/nodes/VideoBox.tsx                |   1 +
 src/client/views/nodes/WebBox.tsx                  |   1 +
 .../views/nodes/formattedText/DashDocView.tsx      |   3 +-
 .../formattedText/FormattedTextBoxComment.tsx      |   3 +-
 .../views/nodes/formattedText/RichTextSchema.tsx   |   1 +
 src/client/views/pdf/PDFViewer.tsx                 |   1 +
 .../views/presentationview/PresElementBox.tsx      |   1 +
 src/client/views/search/SearchBox.tsx              | 128 ++++++++-------------
 src/fields/Doc.ts                                  |  15 +--
 src/fields/List.ts                                 |  25 ++--
 src/mobile/AudioUpload.tsx                         |   3 +-
 src/mobile/MobileInterface.tsx                     |   3 +-
 42 files changed, 173 insertions(+), 169 deletions(-)

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

diff --git a/src/Utils.ts b/src/Utils.ts
index d9a5353e8..3ff05104f 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -422,6 +422,8 @@ export function returnEmptyString() { return ""; }
 
 export function returnEmptyFilter() { return [] as string[]; }
 
+export function returnEmptyDoclist() { return [] as Doc[]; }
+
 export let emptyPath = [];
 
 export function emptyFunction() { }
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 4544e0e3e..49da4f9eb 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -72,6 +72,7 @@ export interface DocumentOptions {
     _scrollTop?: number; // scroll location for pdfs
     _noAutoscroll?: boolean;// whether collections autoscroll when this item is dragged
     _chromeStatus?: string;
+    _searchDoc?: boolean; // is this a search document (used to change UI for search results in schema view)
     _viewType?: string; // sub type of a collection
     _gridGap?: number; // gap between items in masonry view
     _xMargin?: number; // gap between left edge of document and start of masonry/stacking layouts
@@ -822,8 +823,8 @@ export namespace Docs {
 
         export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) {
             const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeViewLockExpandedView: true, treeViewDefaultExpandedView: "data", ...options, _viewType: CollectionViewType.Docking, dockingConfig: config }, id);
-            const tabs = TreeDocument(documents, { title: "Active Tabs", treeViewLockExpandedView: true, treeViewDefaultExpandedView: "data" });
-            const all = TreeDocument([], { title: "Inactive Tabs", treeViewLockExpandedView: true, treeViewDefaultExpandedView: "data" });
+            const tabs = TreeDocument(documents, { title: "On-Screen Tabs", treeViewLockExpandedView: true, treeViewDefaultExpandedView: "data" });
+            const all = TreeDocument([], { title: "Off-Screen Tabs", treeViewLockExpandedView: true, treeViewDefaultExpandedView: "data" });
             Doc.GetProto(inst).data = new List<Doc>([tabs, all]);
             return inst;
         }
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index b907a8e4c..c09a227cf 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -525,7 +525,7 @@ export class CurrentUserUtils {
     static setupSearchPanel(doc: Doc) {
         if (doc["search-panel"] === undefined) {
             doc["search-panel"] = new PrefetchProxy(Docs.Create.SearchDocument({
-                _width: 500, _height: 400, backgroundColor: "dimGray", ignoreClick: true,
+                _width: 500, _height: 400, backgroundColor: "dimGray", ignoreClick: true, _searchDoc: true,
                 childDropAction: "alias", lockedPosition: true, _viewType: CollectionViewType.Schema, _chromeStatus: "disabled", title: "sidebar search stack", system: true
             })) as any as Doc;
         }
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 2d41343b3..260cffc90 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -7,7 +7,7 @@ import { Cast, FieldValue, NumCast } from "../../fields/Types";
 import MobileInkOverlay from "../../mobile/MobileInkOverlay";
 import { GestureUtils } from "../../pen-gestures/GestureUtils";
 import { MobileInkOverlayContent } from "../../server/Message";
-import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero, returnEmptyFilter, setupMoveUpEvents } from "../../Utils";
+import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero, returnEmptyFilter, setupMoveUpEvents, returnEmptyDoclist } from "../../Utils";
 import { CognitiveServices } from "../cognitive_services/CognitiveServices";
 import { DocUtils } from "../documents/Documents";
 import { CurrentUserUtils } from "../util/CurrentUserUtils";
@@ -935,6 +935,7 @@ export default class GestureOverlay extends Touchable {
                 whenActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
                 docFilters={returnEmptyFilter}
+                searchFilterDocs={returnEmptyDoclist}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined}
             />;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index bc5483644..979f803bf 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -16,7 +16,7 @@ import { listSpec } from '../../fields/Schema';
 import { ScriptField } from '../../fields/ScriptField';
 import { BoolCast, Cast, FieldValue, StrCast } from '../../fields/Types';
 import { TraceMobx } from '../../fields/util';
-import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils';
+import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick, Utils, returnEmptyDoclist } from '../../Utils';
 import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
 import { DocServer } from '../DocServer';
 import { Docs, DocumentOptions } from '../documents/Documents';
@@ -206,7 +206,7 @@ export class MainView extends React.Component {
                 }
             });
             if (check === false) {
-                SearchBox.Instance.closeSearch();
+                SearchBox.Instance.resetSearch(true);
             }
         }
 
@@ -394,6 +394,7 @@ export class MainView extends React.Component {
             whenActiveChanged={emptyFunction}
             bringToFront={emptyFunction}
             docFilters={returnEmptyFilter}
+            searchFilterDocs={returnEmptyDoclist}
             ContainingCollectionView={undefined}
             ContainingCollectionDoc={undefined}
             renderDepth={-1}
@@ -476,6 +477,7 @@ export class MainView extends React.Component {
                     whenActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
                     docFilters={returnEmptyFilter}
+                    searchFilterDocs={returnEmptyDoclist}
                     ContainingCollectionView={undefined}
                     ContainingCollectionDoc={undefined}
                     relative={true}
@@ -510,6 +512,7 @@ export class MainView extends React.Component {
                 whenActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
                 docFilters={returnEmptyFilter}
+                searchFilterDocs={returnEmptyDoclist}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined}
                 relative={true}
@@ -703,6 +706,7 @@ export class MainView extends React.Component {
                     focus={emptyFunction}
                     whenActiveChanged={emptyFunction}
                     docFilters={returnEmptyFilter}
+                    searchFilterDocs={returnEmptyDoclist}
                     ContainingCollectionView={undefined}
                     ContainingCollectionDoc={undefined} />
             </div>;
@@ -775,6 +779,7 @@ export class MainView extends React.Component {
                 whenActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
                 docFilters={returnEmptyFilter}
+                searchFilterDocs={returnEmptyDoclist}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined}
             /></div>
@@ -808,6 +813,7 @@ export class MainView extends React.Component {
                     NativeWidth={() => 800}
                     ContentScaling={returnOne}
                     docFilters={returnEmptyFilter}
+                    searchFilterDocs={returnEmptyDoclist}
                 />
             </div>;
     }
@@ -878,6 +884,7 @@ export class MainView extends React.Component {
                             NativeWidth={() => 800}
                             ContentScaling={returnOne}
                             docFilters={returnEmptyFilter}
+                            searchFilterDocs={returnEmptyDoclist}
                         />
                     </div>;
                 </span>, ele);
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 49580cde4..001135340 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -4,7 +4,7 @@ import * as React from "react";
 import { Doc, DocListCast, Opt } from "../../fields/Doc";
 import { Id } from "../../fields/FieldSymbols";
 import { NumCast, Cast } from "../../fields/Types";
-import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero, Utils, setupMoveUpEvents, returnEmptyFilter } from "../../Utils";
+import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero, Utils, setupMoveUpEvents, returnEmptyFilter, returnEmptyDoclist } from "../../Utils";
 import { Transform } from "../util/Transform";
 import { CollectionFreeFormLinksView } from "./collections/collectionFreeForm/CollectionFreeFormLinksView";
 import { DocumentView } from "./nodes/DocumentView";
@@ -205,6 +205,7 @@ export class OverlayView extends React.Component {
                     addDocTab={returnFalse}
                     pinToPres={emptyFunction}
                     docFilters={returnEmptyFilter}
+                    searchFilterDocs={returnEmptyDoclist}
                     ContainingCollectionView={undefined}
                     ContainingCollectionDoc={undefined} />
             </div>;
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 0a4334302..92c3f09b4 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -3,7 +3,7 @@ import { observer } from "mobx-react";
 import * as React from "react";
 import { Doc } from "../../fields/Doc";
 import { NumCast } from "../../fields/Types";
-import { emptyFunction, emptyPath, returnEmptyString, returnZero, returnFalse, returnOne, returnTrue, returnEmptyFilter } from "../../Utils";
+import { emptyFunction, emptyPath, returnEmptyString, returnZero, returnFalse, returnOne, returnTrue, returnEmptyFilter, returnEmptyDoclist } from "../../Utils";
 import { Transform } from "../util/Transform";
 import { DocumentView } from "./nodes/DocumentView";
 import "./Palette.scss";
@@ -60,6 +60,7 @@ export default class Palette extends React.Component<PaletteProps> {
                             whenActiveChanged={emptyFunction}
                             bringToFront={emptyFunction}
                             docFilters={returnEmptyFilter}
+                            searchFilterDocs={returnEmptyDoclist}
                             ContainingCollectionView={undefined}
                             ContainingCollectionDoc={undefined} />
                         <div className="palette-cover" style={{ transform: `translate(${Math.max(0, this._selectedIndex) * 50.75 + 23}px, 0px)` }}></div>
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index eb20fc257..e4ba45648 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -10,7 +10,7 @@ import { Doc, DocListCast } from "../../fields/Doc";
 import { Docs, DocUtils, } from "../documents/Documents";
 import { StrCast, Cast } from "../../fields/Types";
 import { CollectionTreeView } from "./collections/CollectionTreeView";
-import { returnTrue, emptyFunction, returnFalse, returnOne, emptyPath, returnZero, returnEmptyFilter } from "../../Utils";
+import { returnTrue, emptyFunction, returnFalse, returnOne, emptyPath, returnZero, returnEmptyFilter, returnEmptyDoclist } from "../../Utils";
 import { Transform } from "../util/Transform";
 import { ScriptField, ComputedField } from "../../fields/ScriptField";
 import { Scripting } from "../util/Scripting";
@@ -133,6 +133,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                 ContainingCollectionDoc={undefined}
                 ContainingCollectionView={undefined}
                 docFilters={returnEmptyFilter}
+                searchFilterDocs={returnEmptyDoclist}
                 rootSelected={returnFalse}
                 onCheckedClick={this.scriptField}
                 onChildClick={this.scriptField}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 83321d6e0..74b1e5714 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -14,7 +14,7 @@ import { FieldId } from "../../../fields/RefField";
 import { listSpec } from '../../../fields/Schema';
 import { Cast, NumCast, StrCast } from "../../../fields/Types";
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, Utils } from "../../../Utils";
+import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, Utils, returnEmptyDoclist } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 import { Docs } from '../../documents/Documents';
 import { DocumentManager } from '../../util/DocumentManager';
@@ -938,6 +938,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
                 addDocTab={this.addDocTab}
                 pinToPres={DockedFrameRenderer.PinDoc}
                 docFilters={returnEmptyFilter}
+                searchFilterDocs={returnEmptyDoclist}
                 fitToBox={true}
             />
             <div className="miniOverlay" onPointerDown={this.miniDown} >
@@ -979,6 +980,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
                 addDocTab={this.addDocTab}
                 pinToPres={DockedFrameRenderer.PinDoc}
                 docFilters={returnEmptyFilter}
+                searchFilterDocs={returnEmptyDoclist}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined} />
             {document._viewType === CollectionViewType.Freeform && !this._document?.hideMinimap ? this.renderMiniMap() : (null)}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index e1b07077e..0fd18034f 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -166,6 +166,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                                 whenActiveChanged={emptyFunction}
                                 bringToFront={emptyFunction}
                                 docFilters={this.props.docFilters}
+                                searchFilterDocs={this.props.searchFilterDocs}
                                 ContainingCollectionView={undefined}
                                 ContainingCollectionDoc={undefined} />
                         </div>;
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 388eda2b3..5580c32f2 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -131,7 +131,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
     _contentCommand = {
         params: ["target", "source"], title: "set content",
         script: "getProto(self.target).data = copyField(self.source);",
-        immediate: undoBatch((source: Doc[]) => Doc.GetProto(this.target).data = new List<Doc>(source)), // Doc.aliasDocs(source),
+        immediate: undoBatch((source: Doc[]) => Doc.GetProto(this.target).data = new List<Doc>(source)),
         initialize: emptyFunction,
     };
     _onClickCommand = {
@@ -180,12 +180,16 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
     };
     _saveFilterCommand = {
         params: ["target"], title: "save filter",
-        script: "self.target._docFilters = copyField(self['target-docFilters']);",
-        immediate: undoBatch((source: Doc[]) => this.target._docFilters = undefined),
-        initialize: (button: Doc) => { button['target-docFilters'] = this.target._docFilters instanceof ObjectField ? ObjectField.MakeCopy(this.target._docFilters as any as ObjectField) : ""; },
+        script: `self.target._docFilters = copyField(self['target-docFilters']); 
+                 self.target._searchFilterDocs = compareLists(self['target-searchFilterDocs'],self.target._searchFilterDocs) ? undefined: copyField(self['target-searchFilterDocs']);`,
+        immediate: undoBatch((source: Doc[]) => { this.target._docFilters = undefined; this.target._searchFilterDocs = undefined; }),
+        initialize: (button: Doc) => {
+            button['target-docFilters'] = this.target._docFilters instanceof ObjectField ? ObjectField.MakeCopy(this.target._docFilters as any as ObjectField) : undefined;
+            button['target-searchFilterDocs'] = this.target._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(this.target._searchFilterDocs as any as ObjectField) : undefined;
+        },
     };
 
-    @computed get _freeform_commands() { return Doc.UserDoc().noviceMode ? [this._viewCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; }
+    @computed get _freeform_commands() { return Doc.UserDoc().noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; }
     @computed get _stacking_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._contentCommand, this._templateCommand]; }
     @computed get _masonry_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._contentCommand, this._templateCommand]; }
     @computed get _schema_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._templateCommand, this._narrativeCommand]; }
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 4bd69041b..2f1f7a90f 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -229,7 +229,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
         const fieldIsDoc = (type === "document" && typeof field === "object") || (typeof field === "object" && doc);
 
         const onItemDown = async (e: React.PointerEvent) => {
-            if (this.props.Document._searchDoc !== undefined) {
+            if (this.props.Document._searchDoc) {
                 const doc = Doc.GetProto(this.props.rowProps.original);
                 const aliasdoc = await SearchUtil.GetAliasesOfDocument(doc);
                 let targetContext = undefined;
@@ -315,7 +315,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             }
         }
         let search = false;
-        if (this.props.Document._searchDoc !== undefined) {
+        if (this.props.Document._searchDoc) {
             search = true;
         }
 
@@ -900,7 +900,7 @@ export class CollectionSchemaButtons extends CollectionSchemaCell {
         //     (!this.props.CollectionView || !this.props.CollectionView.props.isSelected() ? undefined :
         //         SetupDrag(reference, () => this._document, this.props.moveDocument, this.props.Document.schemaDoc ? "copy" : undefined)(e));
         // };
-        return !BoolCast(this.props.Document._searchDoc) ? <></>
+        return !this.props.Document._searchDoc ? <></>
             : [DocumentType.PDF, DocumentType.RTF].includes(StrCast(doc.type) as DocumentType) ?
                 <div style={{ paddingTop: 8, paddingLeft: 3, }} >
                     <button style={{ padding: 2, left: 77 }} onClick={() => searchMatch(true)}>
diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx
index 34a8bfa24..a90d78a87 100644
--- a/src/client/views/collections/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/CollectionSchemaHeaders.tsx
@@ -287,12 +287,10 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
                 const colpos = this._searchTerm.indexOf(":");
                 const temp = this._searchTerm.slice(colpos + 1, this._searchTerm.length);
                 if (temp === "") {
-                    console.log("here we are first");
                     Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, undefined);
                     this.updateFilter();
                 }
                 else {
-                    console.log("here we are first");
                     Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, undefined);
                     this.tempfilter = temp;
                     Doc.setDocFilter(this.props.Document, this._key, temp, "check");
@@ -304,8 +302,8 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
                 Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, undefined);
                 this.updateFilter();
                 let keyOptions = this._searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
-                const blockedkeys = ["system", "ACL-Public", "_scrollTop", "customTitle", "limitHeight", "proto", "x", "y", "_width", "_height", "_autoHeight", "_fontSize", "_fontFamily", "context", "zIndex", "_timeStampOnEnter", "lines", "highlighting", "searchMatch", "creationDate", "isPrototype", "text-annotations", "aliases", "text-lastModified", "text-noTemplate", "layoutKey", "baseProto", "_xMargin", "_yMargin", "layout", "layout_keyValue", "links"];
-                keyOptions = keyOptions.filter(n => !blockedkeys.includes(n));
+                const blockedkeys = ["system", "customTitle", "limitHeight", "proto", "x", "y", "zIndex", "isPrototype", "text-annotations", "aliases", "text-lastModified", "text-noTemplate", "layoutKey", "baseProto", "layout", "layout_keyValue", "links"];
+                keyOptions = keyOptions.filter(n => !blockedkeys.includes(n) && !n.startsWith("_") && !n.startsWith("ACL"));
                 if (keyOptions.length) {
                     this.onSelect(keyOptions[0]);
                 } else if (this._searchTerm !== "" && this.props.canAddNew) {
@@ -338,8 +336,8 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
         const exactFound = keyOptions.findIndex(key => key.toUpperCase() === this._searchTerm.toUpperCase()) > -1 ||
             this.props.existingKeys.findIndex(key => key.toUpperCase() === this._searchTerm.toUpperCase()) > -1;
 
-        const blockedkeys = ["proto", "x", "y", "_width", "_height", "_autoHeight", "_fontSize", "_fontFamily", "context", "zIndex", "_timeStampOnEnter", "lines", "highlighting", "searchMatch", "creationDate", "isPrototype", "text-annotations", "aliases", "text-lastModified", "text-noTemplate", "layoutKey", "baseProto", "_xMargin", "_yMargin", "layout", "layout_keyValue", "links"];
-        keyOptions = keyOptions.filter(n => !blockedkeys.includes(n));
+        const blockedkeys = ["proto", "x", "y", "zIndex", "_timeStampOnEnter", "isPrototype", "text-annotations", "aliases", "text-lastModified", "text-noTemplate", "layoutKey", "baseProto", "layout", "layout_keyValue", "links"];
+        keyOptions = keyOptions.filter(n => !blockedkeys.includes(n) && !n.startsWith("_") && !n.startsWith("ACL"));
 
         const options = keyOptions.map(key => {
             return <div key={key} className="key-option" style={{
@@ -498,11 +496,7 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
             }
         });
 
-        keyOptions.forEach(key => {
-            Doc.setDocFilter(this.props.Document, this._key, key, undefined);
-        }
-        );
-        Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, undefined);
+        Doc.setDocFilter(this.props.Document, this._key, "", "remove");
         this.props.col.setColor("rgb(241, 239, 235)");
         this.closeResultsVisibility = "none";
     }
@@ -518,13 +512,9 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
                 <div className="keys-dropdown" style={{ zIndex: 1, width: this.props.width, maxWidth: this.props.width }}>
                     <input className="keys-search" style={{ width: "100%" }}
                         ref={this._inputRef} type="text" value={this._searchTerm} placeholder="Column key" onKeyDown={this.onKeyDown}
-                        onChange={e => {
-                            this.onChange(e.target.value);
-                        }}
-                        onClick={(e) => {
-                            //this._inputRef.current!.select();
-                            e.stopPropagation();
-                        }} onFocus={this.onFocus} ></input>
+                        onChange={e => this.onChange(e.target.value)}
+                        onClick={(e) => { e.stopPropagation(); this._inputRef.current?.focus(); }}
+                        onFocus={this.onFocus} ></input>
                     <div style={{ display: this.closeResultsVisibility }}>
                         <FontAwesomeIcon onPointerDown={this.removeFilters} icon={"times-circle"} size="lg"
                             style={{ cursor: "hand", color: "grey", padding: 2, left: -20, top: -1, height: 15, position: "relative" }} />
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
index fc5dffaec..49d9a5c68 100644
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ b/src/client/views/collections/CollectionSchemaView.scss
@@ -99,6 +99,9 @@
         direction: ltr;
         overflow: visible;
     }
+    .rt-noData {
+        display: none;
+    }
 
     .rt-thead {
         width: 100%;
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 257099783..a78061da6 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -9,7 +9,7 @@ import { Resize } from "react-table";
 import "react-table/react-table.css";
 import { Doc, Opt } from "../../../fields/Doc";
 import { List } from "../../../fields/List";
-import { listSpec } from "../../../fields/Schema";
+import { listSpec, makeInterface, emptySchema } from "../../../fields/Schema";
 import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField";
 import { Cast, NumCast, BoolCast } from "../../../fields/Types";
 import { TraceMobx } from "../../../fields/util";
@@ -73,7 +73,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
     @computed get menuCoordinates() {
         let searchx = 0;
         let searchy = 0;
-        if (this.props.Document._searchDoc !== undefined) {
+        if (this.props.Document._searchDoc) {
             const el = document.getElementsByClassName("collectionSchemaView-searchContainer")[0];
             if (el !== undefined) {
                 const rect = el.getBoundingClientRect();
@@ -305,17 +305,9 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
                     this.columns = columns;
                     if (filter) {
                         Doc.setDocFilter(this.props.Document, newKey, filter, "match");
-                        if (this.props.Document.selectedDoc !== undefined) {
-                            const doc = Cast(this.props.Document.selectedDoc, Doc) as Doc;
-                            Doc.setDocFilter(doc, newKey, filter, "match");
-                        }
                     }
                     else {
                         this.props.Document._docFilters = undefined;
-                        if (this.props.Document.selectedDoc !== undefined) {
-                            const doc = Cast(this.props.Document.selectedDoc, Doc, null);
-                            doc._docFilters = undefined;
-                        }
                     }
                 }
             }
@@ -454,6 +446,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
                     PanelHeight={this.previewHeight}
                     ScreenToLocalTransform={this.getPreviewTransform}
                     docFilters={this.docFilters}
+                    searchFilterDocs={this.searchFilterDocs}
                     ContainingCollectionDoc={this.props.CollectionView?.props.Document}
                     ContainingCollectionView={this.props.CollectionView}
                     moveDocument={this.props.moveDocument}
@@ -592,7 +585,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
     }
     render() {
         let name = "collectionSchemaView-container";
-        if (this.props.Document._searchDoc !== undefined) {
+        if (this.props.Document._searchDoc) {
             name = "collectionSchemaView-searchContainer";
         }
         if (!this.props.active()) setTimeout(() => this.closeHeader(), 0);
@@ -615,7 +608,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
         return <div className={name}
             style={{
                 overflow: this.props.overflow === true ? "scroll" : undefined, backgroundColor: "white",
-                pointerEvents: !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined,
+                pointerEvents: this.props.Document._searchDoc !== undefined && !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined,
                 width: name === "collectionSchemaView-searchContainer" ? "auto" : this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative",
             }}  >
             <div className="collectionSchemaView-tableContainer"
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index a9437c11f..a50dab54d 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -217,6 +217,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
             opacity={opacity}
             focus={this.focusDocument}
             docFilters={this.docFilters}
+            searchFilterDocs={this.searchFilterDocs}
             ContainingCollectionDoc={this.props.CollectionView?.props.Document}
             ContainingCollectionView={this.props.CollectionView}
             addDocument={this.props.addDocument}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index a1dd905c2..c73159084 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -111,6 +111,9 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
             return this.props.ignoreFields?.includes("_docFilters") ? [] :
                 [...this.props.docFilters(), ...Cast(this.props.Document._docFilters, listSpec("string"), [])];
         }
+        searchFilterDocs = () => {
+            return [...this.props.searchFilterDocs(), ...DocListCast(this.props.Document._searchFilterDocs)];
+        }
         @computed get childDocs() {
             let rawdocs: (Doc | Promise<Doc>)[] = [];
             if (this.dataField instanceof Doc) { // if collection data is just a document, then promote it to a singleton list;
@@ -128,34 +131,31 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
             const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
             const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
 
-            let searchDocs = DocListCast(this.props.Document._searchDocs);
-
+            let searchDocs = this.searchFilterDocs();
 
             let docsforFilter: Doc[] = childDocs;
 
-            if (searchDocs !== undefined && searchDocs.length > 0) {
+            if (searchDocs.length > 0) {
                 docsforFilter = [];
                 const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
-                console.log(searchDocs);
                 searchDocs = DocUtils.FilterDocs(searchDocs, this.docFilters(), docRangeFilters, viewSpecScript);
                 childDocs.forEach((d) => {
+                    let notFiltered = searchDocs.includes(d) || d.z;
                     if (d.data !== undefined) {
-                        let newdocs = DocListCast(d.data);
-                        if (newdocs.length > 0) {
-                            let displaycheck = false;
+                        let subDocs = DocListCast(d.data);
+                        if (subDocs.length > 0) {
                             let newarray: Doc[] = [];
-                            while (newdocs.length > 0) {
+                            while (subDocs.length > 0 && !notFiltered) {
                                 newarray = [];
-                                newdocs.forEach((t) => {
+                                subDocs.forEach((t) => {
+                                    notFiltered = notFiltered || searchDocs.includes(t);
                                     DocListCast(t.data).forEach((newdoc) => newarray.push(newdoc));
-                                    displaycheck = displaycheck || searchDocs.includes(t);
                                 });
-                                newdocs = newarray;
+                                subDocs = newarray;
                             }
-                            displaycheck && docsforFilter.push(d);
                         }
                     }
-                    searchDocs.includes(d) && docsforFilter.push(d);
+                    notFiltered && docsforFilter.push(d);
                 });
                 return docsforFilter;
             }
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 8440d3e9b..9460095e4 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -8,7 +8,7 @@ import { PrefetchProxy } from '../../../fields/Proxy';
 import { Document, listSpec } from '../../../fields/Schema';
 import { ComputedField, ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
-import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, returnZero, simulateMouseClick, Utils, returnEmptyFilter } from '../../../Utils';
+import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, returnZero, simulateMouseClick, Utils, returnEmptyFilter, returnEmptyDoclist } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentType } from "../../documents/DocumentTypes";
 import { DocumentManager } from '../../util/DocumentManager';
@@ -359,6 +359,7 @@ class TreeView extends React.Component<TreeViewProps> {
                     focus={returnFalse}
                     ScreenToLocalTransform={this.docTransform}
                     docFilters={returnEmptyFilter}
+                    searchFilterDocs={returnEmptyDoclist}
                     ContainingCollectionDoc={this.props.containingCollection}
                     ContainingCollectionView={undefined}
                     addDocument={returnFalse}
@@ -466,6 +467,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 bringToFront={emptyFunction}
                 dontRegisterView={BoolCast(this.props.treeViewDoc.dontRegisterChildViews)}
                 docFilters={returnEmptyFilter}
+                searchFilterDocs={returnEmptyDoclist}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={this.props.containingCollection}
             />;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index ca3b67610..5230fb533 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -18,7 +18,7 @@ import { ComputedField, ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
 import { TraceMobx, GetEffectiveAcl, SharingPermissions, distributeAcls } from '../../../fields/util';
-import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils';
+import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils, returnEmptyDoclist } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { CurrentUserUtils } from '../../util/CurrentUserUtils';
@@ -537,6 +537,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                     fieldKey={`${this.props.fieldKey}-filter`}
                     CollectionView={this}
                     docFilters={returnEmptyFilter}
+                    searchFilterDocs={returnEmptyDoclist}
                     ContainingCollectionDoc={this.props.ContainingCollectionDoc}
                     ContainingCollectionView={this.props.ContainingCollectionView}
                     PanelWidth={this.facetWidth}
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index 6ec9783e2..e1c81aeab 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -12,7 +12,7 @@ import { listSpec } from "../../../fields/Schema";
 import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
 import { ComputedField } from "../../../fields/ScriptField";
 import { Cast, FieldValue, NumCast, StrCast } from "../../../fields/Types";
-import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero } from "../../../Utils";
+import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero, returnEmptyDoclist } from "../../../Utils";
 import { Docs, DocumentOptions } from "../../documents/Documents";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { CompileScript, Transformer, ts } from "../../util/Scripting";
@@ -627,6 +627,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                         PanelHeight={() => 150}
                         ScreenToLocalTransform={this.getPreviewTransform}
                         docFilters={returnEmptyFilter}
+                        searchFilterDocs={returnEmptyDoclist}
                         ContainingCollectionDoc={this.props.CollectionView?.props.Document}
                         ContainingCollectionView={this.props.CollectionView}
                         moveDocument={this.props.moveDocument}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index e66e469eb..0c0f6ca58 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -974,6 +974,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             ContainingCollectionView: this.props.CollectionView,
             ContainingCollectionDoc: this.props.Document,
             docFilters: this.docFilters,
+            searchFilterDocs: this.searchFilterDocs,
             focus: this.focusDocument,
             backgroundColor: this.getClusterColor,
             backgroundHalo: this.backgroundHalo,
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index fb138ecc0..cbce6448f 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -8,7 +8,7 @@ import { EditableView } from "../../EditableView";
 import { KeyValueBox } from "../../nodes/KeyValueBox";
 import { Cast, NumCast, StrCast } from "../../../../fields/Types";
 import { ContentFittingDocumentView } from "../../nodes/ContentFittingDocumentView";
-import { returnFalse, returnOne, emptyFunction, emptyPath, returnTrue, returnZero, returnEmptyFilter, Utils } from "../../../../Utils";
+import { returnFalse, returnOne, emptyFunction, emptyPath, returnTrue, returnZero, returnEmptyFilter, Utils, returnEmptyDoclist } from "../../../../Utils";
 import { Id } from "../../../../fields/FieldSymbols";
 import { Transform } from "../../../util/Transform";
 import { PropertiesButtons } from "../../PropertiesButtons";
@@ -284,6 +284,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     focus={returnFalse}
                     ScreenToLocalTransform={this.getTransform}
                     docFilters={returnEmptyFilter}
+                    searchFilterDocs={returnEmptyDoclist}
                     ContainingCollectionDoc={undefined}
                     ContainingCollectionView={undefined}
                     addDocument={returnFalse}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 21d283547..0afcab5a3 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -234,6 +234,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
             ScreenToLocalTransform={dxf}
             focus={this.props.focus}
             docFilters={this.docFilters}
+            searchFilterDocs={this.searchFilterDocs}
             ContainingCollectionDoc={this.props.CollectionView?.props.Document}
             ContainingCollectionView={this.props.CollectionView}
             addDocument={this.props.addDocument}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index d02088a6c..53825eece 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -234,6 +234,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
             ScreenToLocalTransform={dxf}
             focus={this.props.focus}
             docFilters={this.docFilters}
+            searchFilterDocs={this.searchFilterDocs}
             ContainingCollectionDoc={this.props.CollectionView?.props.Document}
             ContainingCollectionView={this.props.CollectionView}
             addDocument={this.props.addDocument}
diff --git a/src/client/views/nodes/DocHolderBox.tsx b/src/client/views/nodes/DocHolderBox.tsx
index 88eb48f51..b3b7cc4f3 100644
--- a/src/client/views/nodes/DocHolderBox.tsx
+++ b/src/client/views/nodes/DocHolderBox.tsx
@@ -120,6 +120,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
                     DataDoc={undefined}
                     LibraryPath={emptyPath}
                     docFilters={this.props.docFilters}
+                    searchFilterDocs={this.props.searchFilterDocs}
                     ContainingCollectionView={this as any} // bcz: hack!  need to pass a prop that can be used to select the container (ie, 'this') when the up selector in document decorations is clicked.  currently, the up selector allows only a containing collection to be selected
                     ContainingCollectionDoc={undefined}
                     fitToBox={true}
@@ -149,6 +150,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
                     DataDoc={undefined}
                     LibraryPath={emptyPath}
                     docFilters={this.props.docFilters}
+                    searchFilterDocs={this.props.searchFilterDocs}
                     ContainingCollectionView={this as any} // bcz: hack!  need to pass a prop that can be used to select the container (ie, 'this') when the up selector in document decorations is clicked.  currently, the up selector allows only a containing collection to be selected
                     ContainingCollectionDoc={undefined}
                     fitToBox={true}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 91f12f004..bf42f30fe 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -45,6 +45,7 @@ export interface DocumentViewProps {
     ContainingCollectionView: Opt<CollectionView>;
     ContainingCollectionDoc: Opt<Doc>;
     docFilters: () => string[];
+    searchFilterDocs: () => Doc[];
     FreezeDimensions?: boolean;
     NativeWidth: () => number;
     NativeHeight: () => number;
@@ -829,6 +830,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         return (<div className="documentView-contentsView" style={{ borderRadius: "inherit", width: "100%", height: "100%" }}>
             <DocumentContentsView key={1}
                 docFilters={this.props.docFilters}
+                searchFilterDocs={this.props.searchFilterDocs}
                 ContainingCollectionView={this.props.ContainingCollectionView}
                 ContainingCollectionDoc={this.props.ContainingCollectionDoc}
                 NativeWidth={this.NativeWidth}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 3726f1d5f..fceeced36 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -29,6 +29,7 @@ export interface FieldViewProps {
     dropAction: dropActionType;
     backgroundHalo?: () => boolean;
     docFilters: () => string[];
+    searchFilterDocs: () => Doc[];
     isSelected: (outsideReaction?: boolean) => boolean;
     select: (isCtrlPressed: boolean) => void;
     rootSelected: (outsideReaction?: boolean) => boolean;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 216c5f39e..dd3914df7 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -489,6 +489,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
                 ScreenToLocalTransform={this.screenToLocalTransform}
                 renderDepth={this.props.renderDepth + 1}
                 docFilters={this.props.docFilters}
+                searchFilterDocs={this.props.searchFilterDocs}
                 ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
                 {this.contentFunc}
             </CollectionFreeFormView>
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index c4481b213..f154c5f56 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -3,7 +3,7 @@ import { observer } from "mobx-react";
 import wiki from "wikijs";
 import { Doc, DocCastAsync, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
 import { Cast, FieldValue, NumCast } from "../../../fields/Types";
-import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero } from "../../../Utils";
+import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero, returnEmptyDoclist } from "../../../Utils";
 import { Docs } from "../../documents/Documents";
 import { DocumentManager } from "../../util/DocumentManager";
 import { Transform } from "../../util/Transform";
@@ -101,6 +101,7 @@ export class LinkDocPreview extends React.Component<Props> {
                 pinToPres={returnFalse}
                 dontRegisterView={true}
                 docFilters={returnEmptyFilter}
+                searchFilterDocs={returnEmptyDoclist}
                 ContainingCollectionDoc={undefined}
                 ContainingCollectionView={undefined}
                 renderDepth={0}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 255a1b2d0..890263a61 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -246,7 +246,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
             <PDFViewer {...this.props} pdf={this._pdf!} url={pdfUrl!.url.pathname} active={this.props.active} loaded={this.loaded}
                 setPdfViewer={this.setPdfViewer} ContainingCollectionView={this.props.ContainingCollectionView}
                 renderDepth={this.props.renderDepth} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth}
-                addDocTab={this.props.addDocTab} focus={this.props.focus} docFilters={this.props.docFilters}
+                addDocTab={this.props.addDocTab} focus={this.props.focus} docFilters={this.props.docFilters} searchFilterDocs={this.props.searchFilterDocs}
                 pinToPres={this.props.pinToPres} addDocument={this.addDocument}
                 Document={this.props.Document} DataDoc={this.dataDoc} ContentScaling={this.props.ContentScaling}
                 ScreenToLocalTransform={this.props.ScreenToLocalTransform} select={this.props.select}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index ee92e517c..dd76503d5 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -384,6 +384,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
                     ScreenToLocalTransform={this.props.ScreenToLocalTransform}
                     renderDepth={this.props.renderDepth + 1}
                     docFilters={this.props.docFilters}
+                    searchFilterDocs={this.props.searchFilterDocs}
                     ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
                     {this.contentFunc}
                 </CollectionFreeFormView>
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 1393e7868..7d7426e31 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -733,6 +733,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
                             ScreenToLocalTransform={this.scrollXf}
                             renderDepth={this.props.renderDepth + 1}
                             docFilters={this.props.docFilters}
+                            searchFilterDocs={this.props.searchFilterDocs}
                             ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
                         </CollectionFreeFormView>
                     </div>
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 31dd92b59..08bab8d12 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -5,7 +5,7 @@ import { Id } from "../../../../fields/FieldSymbols";
 import { ObjectField } from "../../../../fields/ObjectField";
 import { ComputedField } from "../../../../fields/ScriptField";
 import { BoolCast, Cast, NumCast, StrCast } from "../../../../fields/Types";
-import { emptyFunction, returnEmptyString, returnFalse, Utils, returnZero, returnEmptyFilter } from "../../../../Utils";
+import { emptyFunction, returnEmptyString, returnFalse, Utils, returnZero, returnEmptyFilter, returnEmptyDoclist } from "../../../../Utils";
 import { DocServer } from "../../../DocServer";
 import { Docs, DocUtils } from "../../../documents/Documents";
 import { DocumentView } from "../DocumentView";
@@ -255,6 +255,7 @@ export class DashDocView extends React.Component<IDashDocView> {
                             bringToFront={emptyFunction}
                             dontRegisterView={false}
                             docFilters={this.props.tbox?.props.docFilters || returnEmptyFilter}
+                            searchFilterDocs={this.props.tbox?.props.searchFilterDocs || returnEmptyDoclist}
                             ContainingCollectionView={this._textBox.props.ContainingCollectionView}
                             ContainingCollectionDoc={this._textBox.props.ContainingCollectionDoc}
                             ContentScaling={this.contentScaling}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index 6f3984f39..1e1bcd42c 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -4,7 +4,7 @@ import { EditorView } from "prosemirror-view";
 import * as ReactDOM from 'react-dom';
 import { Doc, DocCastAsync, Opt } from "../../../../fields/Doc";
 import { Cast, FieldValue, NumCast, StrCast } from "../../../../fields/Types";
-import { emptyFunction, returnEmptyString, returnFalse, Utils, emptyPath, returnZero, returnOne, returnEmptyFilter } from "../../../../Utils";
+import { emptyFunction, returnEmptyString, returnFalse, Utils, emptyPath, returnZero, returnOne, returnEmptyFilter, returnEmptyDoclist } from "../../../../Utils";
 import { DocServer } from "../../../DocServer";
 import { DocumentManager } from "../../../util/DocumentManager";
 import { schema } from "./schema_rts";
@@ -302,6 +302,7 @@ export class FormattedTextBoxComment {
                                             pinToPres={returnFalse}
                                             dontRegisterView={true}
                                             docFilters={returnEmptyFilter}
+                                            searchFilterDocs={returnEmptyDoclist}
                                             ContainingCollectionDoc={undefined}
                                             ContainingCollectionView={undefined}
                                             renderDepth={0}
diff --git a/src/client/views/nodes/formattedText/RichTextSchema.tsx b/src/client/views/nodes/formattedText/RichTextSchema.tsx
index a85dacc7e..b76e520b7 100644
--- a/src/client/views/nodes/formattedText/RichTextSchema.tsx
+++ b/src/client/views/nodes/formattedText/RichTextSchema.tsx
@@ -155,6 +155,7 @@ export class DashDocView {
                     bringToFront={emptyFunction}
                     dontRegisterView={false}
                     docFilters={this._textBox.props.docFilters}
+                    searchFilterDocs={this._textBox.props.searchFilterDocs}
                     ContainingCollectionView={this._textBox.props.ContainingCollectionView}
                     ContainingCollectionDoc={this._textBox.props.ContainingCollectionDoc}
                     ContentScaling={this.contentScaling}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index f2aa9fa3f..67d435194 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -56,6 +56,7 @@ interface IViewerProps {
     Document: Doc;
     DataDoc?: Doc;
     docFilters: () => string[];
+    searchFilterDocs: () => Doc[];
     ContainingCollectionView: Opt<CollectionView>;
     PanelWidth: () => number;
     PanelHeight: () => number;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index a25a8ee33..dfcf575f1 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -102,6 +102,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                     bringToFront={returnFalse}
                     opacity={returnOne}
                     docFilters={this.props.docFilters}
+                    searchFilterDocs={this.props.searchFilterDocs}
                     ContainingCollectionView={undefined}
                     ContainingCollectionDoc={undefined}
                     ContentScaling={returnOne}
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index c571adefe..9c9900bfb 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -1,6 +1,6 @@
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { Tooltip } from '@material-ui/core';
-import { action, computed, IReactionDisposer, observable, runInAction } from 'mobx';
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, DocListCast, Field, Opt } from '../../../fields/Doc';
@@ -17,8 +17,8 @@ import { SetupDrag } from '../../util/DragManager';
 import { SearchUtil } from '../../util/SearchUtil';
 import { SelectionManager } from '../../util/SelectionManager';
 import { Transform } from '../../util/Transform';
-import { ColumnType } from "../collections/CollectionSchemaView";
-import { CollectionView, CollectionViewType } from '../collections/CollectionView';
+import { CollectionSchemaView, ColumnType } from "../collections/CollectionSchemaView";
+import { CollectionViewType } from '../collections/CollectionView';
 import { ViewBoxBaseComponent } from "../DocComponent";
 import { DocumentView } from '../nodes/DocumentView';
 import { FieldView, FieldViewProps } from '../nodes/FieldView';
@@ -46,11 +46,11 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
     private _disposers: { [name: string]: IReactionDisposer } = {};
     private _blockedTypes = [DocumentType.PRESELEMENT, DocumentType.KVP, DocumentType.DOCHOLDER, DocumentType.SEARCH, DocumentType.SEARCHITEM, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
 
-    private currentSelectedCollection: DocumentView | undefined = undefined;
-    private docsforfilter: Doc[] = [];
+    private docsforfilter: Doc[] | undefined = [];
     private realTotalResults: number = 0;
     private collectionRef = React.createRef<HTMLSpanElement>();
 
+    @observable _currentSelectedCollection: DocumentView | undefined = undefined;
     @observable _icons: string[] = this._allIcons;
     @observable _results: [Doc, string[], string[]][] = [];
     @observable _visibleElements: JSX.Element[] = [];
@@ -64,9 +64,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
     @observable open = false;
     @observable children = 0;
     @observable newsearchstring = "";
-    @observable headercount: number = 0;
-    @observable headerscale: number = 0;
-    @observable filter = false;
+    @computed get filter() { return this._results?.length && (this._currentSelectedCollection?.props.Document._searchFilterDocs || this._currentSelectedCollection?.props.Document._docFilters); }
 
     constructor(props: any) {
         super(props);
@@ -78,6 +76,8 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             this._inputRef.current.focus();
             this._searchbarOpen = true;
         }
+        this._disposers.filters = reaction(() => this.props.Document._docFilters,
+            (filters: any) => this.setSearchFilter(this._currentSelectedCollection, this.filter ? undefined : this.docsforfilter));
     });
 
     componentWillUnmount() {
@@ -89,14 +89,12 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         this.layoutDoc._searchString = e.target.value;
         this.newsearchstring = e.target.value;
         if (e.target.value === "") {
-            if (this.currentSelectedCollection) {
-                this.setSearchDocsRecursive(this.currentSelectedCollection, undefined);
-            }
-            this.closeSearch(false);
+            this.docsforfilter = undefined;
+            this.setSearchFilter(this._currentSelectedCollection, undefined);
+            this.resetSearch(false);
 
-            if (this.currentSelectedCollection !== undefined) {
-                this.currentSelectedCollection = undefined;
-                this.props.Document.selectedDoc = undefined;
+            if (this._currentSelectedCollection !== undefined) {
+                this._currentSelectedCollection = undefined;
             }
             this.open = false;
             this._results = [];
@@ -226,10 +224,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         query = query.toLowerCase();
 
         if (selectedCollection !== undefined) {
-            this.currentSelectedCollection = selectedCollection;
-            if (this.filter === true) {
-                this.props.Document.selectedDoc = selectedCollection.props.Document;
-            }
+            this._currentSelectedCollection = selectedCollection;
             let docs = DocListCast(selectedCollection.dataDoc[Doc.LayoutFieldKey(selectedCollection.dataDoc)]);
             const found: [Doc, string[], string[]][] = [];
             const docsforFilter: Doc[] = [];
@@ -251,10 +246,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             }
             this._results = found;
             this.docsforfilter = docsforFilter;
-            if (this.filter === true) {
-                selectedCollection.props.Document._searchDocs = new List<Doc>(docsforFilter);
-                this.setSearchDocsRecursive(selectedCollection, docsforFilter);
-            }
+            this.setSearchFilter(selectedCollection, this.filter && found.length ? docsforFilter : undefined);
             this._numTotalResults = found.length;
             this.realTotalResults = found.length;
         }
@@ -277,23 +269,17 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
     }
 
     @action
-    submitSearch = async (reset?: boolean) => {
-        if (this.currentSelectedCollection !== undefined) {
-            this.setSearchDocsRecursive(this.currentSelectedCollection, undefined);
-        }
-        if (reset) {
-            this.layoutDoc._searchString = "";
-        }
+    submitSearch = async () => {
+        this.resetSearch(false);
+
         //this.props.Document._docFilters = new List();
         this._noResults = "";
 
         this.dataDoc[this.fieldKey] = new List<Doc>([]);
-        this.headercount = 0;
         this.children = 0;
         let query = StrCast(this.layoutDoc._searchString);
         Doc.SetSearchQuery(query);
-        this._searchFullDB ? query = this.getFinalQuery(query) : console.log("local");
-        this.closeSearch(false);
+        this._searchFullDB && (query = this.getFinalQuery(query));
         this._results = [];
         this._resultsSet.clear();
         this._visibleElements = [];
@@ -425,12 +411,14 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
     }
 
     @action.bound
-    closeSearch = (closesearchbar = true) => {
+    resetSearch = (close: boolean) => {
         this._results.forEach(result => {
             Doc.UnBrushDoc(result[0]);
             Doc.ClearSearchMatches();
         });
-        closesearchbar && (this._searchbarOpen = false);
+        if (close) {
+            this._searchbarOpen = false;
+        }
     }
 
     @action.bound
@@ -482,7 +470,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                 }
             }
         }
-        this.headerscale = headers.size;
         const oldSchemaHeaders = Cast(this.props.Document._schemaHeaders, listSpec("string"), []);
         if (oldSchemaHeaders?.length && typeof oldSchemaHeaders[0] !== "object") {
             const newSchemaHeaders = oldSchemaHeaders.map(i => typeof i === "string" ? new SchemaHeaderField(i, "#f1efeb") : i);
@@ -491,7 +478,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                     newSchemaHeaders.push(new SchemaHeaderField(header, "#f1efeb"));
                 }
             });
-            this.headercount = newSchemaHeaders.length;
             this.props.Document._schemaHeaders = new List<SchemaHeaderField>(newSchemaHeaders);
         } else if (this.props.Document._schemaHeaders === undefined) {
             this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb")]);
@@ -518,12 +504,10 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
 
     @action
     changeSearchScope = (scope: string) => {
-        scope && (this.filter = false);
+        this.docsforfilter = undefined;
+        this.setSearchFilter(this._currentSelectedCollection, undefined);
         this._searchFullDB = scope;
         this.dataDoc[this.fieldKey] = new List<Doc>([]);
-        if (this.currentSelectedCollection !== undefined) {
-            this.setSearchDocsRecursive(this.currentSelectedCollection, undefined);
-        }
         this.submitSearch();
     }
 
@@ -558,28 +542,14 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         </div>;
     }
 
-    setSearchDocsRecursive = (collectionView: DocumentView, filter: Doc[] | undefined) => {
-        let docs = DocListCast(collectionView.dataDoc[Doc.LayoutFieldKey(collectionView.dataDoc)]);
-        let newarray: Doc[] = [];
-        while (docs.length > 0) {
-            newarray = [];
-            docs.forEach(d => {
-                const subDocs = DocListCast(d.data);
-                if (subDocs.length) {
-                    d._searchDocs = filter ? new List<Doc>(filter) : undefined;
-                    DocListCast(d.data).forEach(newdoc => newarray.push(newdoc));
-                }
-            });
-            docs = newarray;
+    setSearchFilter = (collectionView: DocumentView | undefined, docsForFilter: Doc[] | undefined) => {
+        if (collectionView) {
+            const docFilters = Cast(this.props.Document._docFilters, listSpec("string"), null);
+            collectionView.props.Document._searchFilterDocs = docsForFilter?.length ? new List<Doc>(docsForFilter) : undefined;
+            collectionView.props.Document._docFilters = docsForFilter?.length && docFilters?.length ? new List<string>(docFilters) : undefined;
         }
-        collectionView.props.Document._searchDocs = filter ? new List<Doc>(filter) : undefined;
-        this.props.Document.selectedDoc = filter ? collectionView.props.Document : undefined;
     }
-
     render() {
-        this.props.Document._chromeStatus === "disabled";
-        this.props.Document._searchDoc = true;
-        const rows = this.children;
         return (
             <div style={{ pointerEvents: "all" }} className="searchBox-container">
                 <div style={{ position: "absolute", left: 15, height: 32, alignItems: "center", display: "flex" }}>{`${Doc.CurrentUserEmail}/${Cast(Doc.UserDoc().activeDashboard, Doc, null)?.title}`}</div>
@@ -604,34 +574,34 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                                         <FontAwesomeIcon icon={"filter"} size="lg"
                                             style={{ cursor: "hand", padding: 1, backgroundColor: this.filter ? "white" : "lightgray", color: this.filter ? "black" : "white" }}
                                             onPointerDown={e => { e.stopPropagation(); SetupDrag(this.collectionRef, () => this.layoutDoc._searchString ? this.startDragCollection() : undefined); }}
-                                            onClick={action(() => {
-                                                this.filter = !this.filter && !this._searchFullDB;
-                                                this.currentSelectedCollection && this.setSearchDocsRecursive(this.currentSelectedCollection, this.filter ? this.docsforfilter : undefined);
-                                            })} />
+                                            onClick={action(() => this.setSearchFilter(this._currentSelectedCollection, this.filter ? undefined : this.docsforfilter))} />
                                     </div>
                                 </Tooltip>
                             </div>
                             {this.scopeButtons}
                         </div>
-
                     </div >
                 </div >
-                {!this._searchbarOpen ? (null) : <div style={{ zIndex: 20000, color: "black" }}>
-                    <div style={{ display: "flex", justifyContent: "center", }}>
-                        <div style={{ display: this.open ? "flex" : "none", overflow: "auto", }}>
-                            <CollectionView {...this.props}
-                                Document={this.props.Document}
-                                moveDocument={returnFalse}
-                                removeDocument={returnFalse}
-                                PanelHeight={this.open ? this.returnHeight : returnZero}
-                                PanelWidth={this.open ? this.returnLength : returnZero}
-                                overflow={length > window.innerWidth || rows > 6 ? true : false}
-                                focus={this.selectElement}
-                                ScreenToLocalTransform={Transform.Identity}
-                            />
+                {!this._searchbarOpen ? (null) :
+                    <div style={{ zIndex: 20000, color: "black" }} ref={(r) => r?.focus()}>
+                        <div style={{ display: "flex", justifyContent: "center", }}>
+                            <div style={{ display: this.open ? "flex" : "none", overflow: "auto", }}>
+                                <CollectionSchemaView {...this.props}
+                                    CollectionView={undefined}
+                                    annotationsKey={""}
+                                    addDocument={returnFalse}
+                                    Document={this.props.Document}
+                                    moveDocument={returnFalse}
+                                    removeDocument={returnFalse}
+                                    PanelHeight={this.open ? this.returnHeight : returnZero}
+                                    PanelWidth={this.open ? this.returnLength : returnZero}
+                                    overflow={length > window.innerWidth || this.children > 6 ? true : false}
+                                    focus={this.selectElement}
+                                    ScreenToLocalTransform={Transform.Identity}
+                                />
+                            </div>
                         </div>
                     </div>
-                </div>
                 }
             </div >
         );
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index dc274a063..272b70293 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1024,10 +1024,10 @@ export namespace Doc {
         const fieldVal = doc[key];
         if (Cast(fieldVal, listSpec("string"), []).length) {
             const vals = Cast(fieldVal, listSpec("string"), []);
-            return vals.some(v => v === value);
+            return vals.some(v => v.includes(value));  // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
         }
         const fieldStr = Field.toString(fieldVal as Field);
-        return fieldStr === value;
+        return fieldStr.includes(value); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
     }
 
     export function deiconifyView(doc: any) {
@@ -1056,18 +1056,14 @@ export namespace Doc {
         }
     }
 
-    export function aliasDocs(field: any) {
-        return new List<Doc>(field.map((d: any) => Doc.MakeAlias(d)));
-    }
-
     // filters document in a container collection:
     // all documents with the specified value for the specified key are included/excluded 
     // based on the modifiers :"check", "x", undefined
-    export function setDocFilter(container: Doc, key: string, value: any, modifiers?: "match" | "check" | "x" | undefined) {
+    export function setDocFilter(container: Doc, key: string, value: any, modifiers?: "remove" | "match" | "check" | "x" | undefined) {
         const docFilters = Cast(container._docFilters, listSpec("string"), []);
         runInAction(() => {
             for (let i = 0; i < docFilters.length; i += 3) {
-                if (docFilters[i] === key && (docFilters[i + 1] === value || modifiers === "match")) {
+                if (docFilters[i] === key && (docFilters[i + 1] === value || modifiers === "match" || modifiers === "remove")) {
                     if (docFilters[i + 2] === modifiers && modifiers && docFilters[i + 1] === value) return;
                     docFilters.splice(i, 3);
                     container._docFilters = new List<string>(docFilters);
@@ -1077,7 +1073,7 @@ export namespace Doc {
             if (typeof modifiers === "string") {
                 if (!docFilters.length && modifiers === "match" && value === undefined) {
                     container._docFilters = undefined;
-                } else {
+                } else if (modifiers !== "remove") {
                     docFilters.push(key);
                     docFilters.push(value);
                     docFilters.push(modifiers);
@@ -1274,7 +1270,6 @@ Scripting.addGlobal(function getDocTemplate(doc?: any) { return Doc.getDocTempla
 Scripting.addGlobal(function getAlias(doc: any) { return Doc.MakeAlias(doc); });
 Scripting.addGlobal(function getCopy(doc: any, copyProto: any) { return doc.isTemplateDoc ? Doc.ApplyTemplate(doc) : Doc.MakeCopy(doc, copyProto); });
 Scripting.addGlobal(function copyField(field: any) { return field instanceof ObjectField ? ObjectField.MakeCopy(field) : field; });
-Scripting.addGlobal(function aliasDocs(field: any) { return Doc.aliasDocs(field); });
 Scripting.addGlobal(function docList(field: any) { return DocListCast(field); });
 Scripting.addGlobal(function setInPlace(doc: any, field: any, value: any) { return Doc.SetInPlace(doc, field, value, false); });
 Scripting.addGlobal(function sameDocs(doc1: any, doc2: any) { return Doc.AreProtosEqual(doc1, doc2); });
diff --git a/src/fields/List.ts b/src/fields/List.ts
index a9da75abb..1c2b89b01 100644
--- a/src/fields/List.ts
+++ b/src/fields/List.ts
@@ -1,14 +1,16 @@
-import { Deserializable, autoObject, afterDocDeserialize } from "../client/util/SerializationHelper";
+import { action, observable, runInAction } from "mobx";
+import { alias, list, serializable } from "serializr";
+import { DocServer } from "../client/DocServer";
+import { Scripting } from "../client/util/Scripting";
+import { afterDocDeserialize, autoObject, Deserializable } from "../client/util/SerializationHelper";
 import { Field } from "./Doc";
-import { setter, getter, deleteProperty, updateFunction } from "./util";
-import { serializable, alias, list } from "serializr";
-import { observable, action, runInAction } from "mobx";
+import { Copy, OnUpdate, Parent, Self, SelfProxy, ToScriptString, ToString, Update } from "./FieldSymbols";
 import { ObjectField } from "./ObjectField";
-import { RefField } from "./RefField";
 import { ProxyField } from "./Proxy";
-import { Self, Update, Parent, OnUpdate, SelfProxy, ToScriptString, ToString, Copy, Id } from "./FieldSymbols";
-import { Scripting } from "../client/util/Scripting";
-import { DocServer } from "../client/DocServer";
+import { RefField } from "./RefField";
+import { listSpec } from "./Schema";
+import { Cast } from "./Types";
+import { deleteProperty, getter, setter, updateFunction } from "./util";
 
 const listHandlers: any = {
     /// Mutator methods
@@ -328,4 +330,9 @@ class ListImpl<T extends Field> extends ObjectField {
 export type List<T extends Field> = ListImpl<T> & (T | (T extends RefField ? Promise<T> : never))[];
 export const List: { new <T extends Field>(fields?: T[]): List<T> } = ListImpl as any;
 
-Scripting.addGlobal("List", List);
\ No newline at end of file
+Scripting.addGlobal("List", List);
+Scripting.addGlobal(function compareLists(l1: any, l2: any) {
+    const L1 = Cast(l1, listSpec("string"), []);
+    const L2 = Cast(l2, listSpec("string"), []);
+    return L1 && L2 && L1.length === L2.length && L2.reduce((p, v) => p && L1.includes(v), true);
+}, "compare two lists");
\ No newline at end of file
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index 8ae504f1b..738de09c6 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -3,7 +3,7 @@ import "./ImageUpload.scss";
 import React = require('react');
 import { observer } from 'mobx-react';
 import { observable, action, computed } from 'mobx';
-import { Utils, emptyPath, returnFalse, emptyFunction, returnOne, returnZero, returnTrue, returnEmptyFilter } from '../Utils';
+import { Utils, emptyPath, returnFalse, emptyFunction, returnOne, returnZero, returnTrue, returnEmptyFilter, returnEmptyDoclist } from '../Utils';
 import { Doc, Opt } from '../fields/Doc';
 import { Cast, FieldValue } from '../fields/Types';
 import { listSpec } from '../fields/Schema';
@@ -88,6 +88,7 @@ export class AudioUpload extends React.Component {
                         rootSelected={returnTrue}
                         removeDocument={undefined}
                         docFilters={returnEmptyFilter}
+                        searchFilterDocs={returnEmptyDoclist}
                         onClick={undefined}
                         ScreenToLocalTransform={Transform.Identity}
                         ContentScaling={returnOne}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 41b997285..05a695147 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -14,7 +14,7 @@ import { action, computed, observable, reaction, trace, runInAction } from 'mobx
 import { observer } from 'mobx-react';
 import { Doc, DocListCast } from '../fields/Doc';
 import { CurrentUserUtils } from '../client/util/CurrentUserUtils';
-import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, returnZero, returnEmptyFilter } from '../Utils';
+import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, returnZero, returnEmptyFilter, returnEmptyDoclist } from '../Utils';
 import { Docs, DocumentOptions } from '../client/documents/Documents';
 import { Scripting } from '../client/util/Scripting';
 import { DocumentView } from '../client/views/nodes/DocumentView';
@@ -220,6 +220,7 @@ export class MobileInterface extends React.Component {
                     whenActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
                     docFilters={returnEmptyFilter}
+                    searchFilterDocs={returnEmptyDoclist}
                     ContainingCollectionView={undefined}
                     ContainingCollectionDoc={undefined}
                 />
-- 
cgit v1.2.3-70-g09d2


From ff5994377a80ec76c0138c5966f43a5bbce6e8b3 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 22 Aug 2020 19:44:02 -0400
Subject: more search cleanup.  searches over dashboards, not collections now. 
 fixed drag-off filters to still work with collections.

---
 src/Utils.ts                                       |   2 +-
 src/client/documents/Documents.ts                  |   1 +
 .../views/collections/CollectionDockingView.tsx    |  27 ++--
 src/client/views/collections/CollectionMenu.tsx    |   6 +-
 .../views/collections/CollectionSchemaCells.tsx    |  12 +-
 src/client/views/collections/CollectionSubView.tsx |   1 +
 src/client/views/collections/SchemaTable.tsx       | 153 ++++++---------------
 src/client/views/nodes/KeyValuePair.tsx            |   5 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |   2 +-
 src/client/views/search/SearchBox.tsx              | 135 +++++-------------
 src/fields/Doc.ts                                  |   6 +-
 src/fields/List.ts                                 |   2 +-
 12 files changed, 114 insertions(+), 238 deletions(-)

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

diff --git a/src/Utils.ts b/src/Utils.ts
index 3ff05104f..5b5a06839 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -422,7 +422,7 @@ export function returnEmptyString() { return ""; }
 
 export function returnEmptyFilter() { return [] as string[]; }
 
-export function returnEmptyDoclist() { return [] as Doc[]; }
+export function returnEmptyDoclist() { return [] as any[]; }
 
 export let emptyPath = [];
 
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 49da4f9eb..36712ab3e 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -873,6 +873,7 @@ export namespace DocUtils {
         }
 
         const filteredDocs = docFilters.length ? childDocs.filter(d => {
+            if (d.z) return true;
             for (const facetKey of Object.keys(filterFacets)) {
                 const facet = filterFacets[facetKey];
                 const satisfiesFacet = Object.keys(facet).some(value => {
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 58c40b1d4..6277fbb14 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -30,14 +30,14 @@ import { DocumentView } from "../nodes/DocumentView";
 import { PresBox } from '../nodes/PresBox';
 import "./CollectionDockingView.scss";
 import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
-import { SubCollectionViewProps } from "./CollectionSubView";
+import { SubCollectionViewProps, CollectionSubView } from "./CollectionSubView";
 import { CollectionViewType } from './CollectionView';
 import { DockingViewButtonSelector } from './ParentDocumentSelector';
 import React = require("react");
 const _global = (window /* browser */ || global /* node */) as any;
 
 @observer
-export class CollectionDockingView extends React.Component<SubCollectionViewProps> {
+export class CollectionDockingView extends CollectionSubView(doc => doc) {
     @observable public static Instances: CollectionDockingView[] = [];
     @computed public static get Instance() { return CollectionDockingView.Instances[0]; }
     public static makeDocumentConfig(document: Doc, width?: number, libraryPath?: Doc[]) {
@@ -73,20 +73,13 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
         DragManager.StartWindowDrag = this.StartOtherDrag;
     }
     public StartOtherDrag = (e: any, dragDocs: Doc[]) => {
-        let config: any;
-        if (dragDocs.length === 1) {
-            config = CollectionDockingView.makeDocumentConfig(dragDocs[0]);
-        } else {
-            config = {
+        const config = dragDocs.length === 1 ? CollectionDockingView.makeDocumentConfig(dragDocs[0]) :
+            {
                 type: 'row',
                 content: dragDocs.map((doc, i) => CollectionDockingView.makeDocumentConfig(doc))
             };
-        }
-        const div = document.createElement("div");
-        const dragSource = this._goldenLayout.createDragSource(div, config);
-        dragSource._dragListener.on("dragStop", () => {
-            dragSource.destroy();
-        });
+        const dragSource = this._goldenLayout.createDragSource(document.createElement("div"), config);
+        dragSource._dragListener.on("dragStop", () => dragSource.destroy());
         dragSource._dragListener.onMouseDown(e);
     }
 
@@ -939,8 +932,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
                 backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
                 addDocTab={this.addDocTab}
                 pinToPres={DockedFrameRenderer.PinDoc}
-                docFilters={returnEmptyFilter}
-                searchFilterDocs={returnEmptyDoclist}
+                docFilters={CollectionDockingView.Instance.docFilters}
+                searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
                 fitToBox={true}
             />
             <div className="miniOverlay" onPointerDown={this.miniDown} >
@@ -981,8 +974,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
                 backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
                 addDocTab={this.addDocTab}
                 pinToPres={DockedFrameRenderer.PinDoc}
-                docFilters={returnEmptyFilter}
-                searchFilterDocs={returnEmptyDoclist}
+                docFilters={CollectionDockingView.Instance.docFilters}
+                searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined} />
             {document._viewType === CollectionViewType.Freeform && !this._document?.hideMinimap ? this.renderMiniMap() : (null)}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 5580c32f2..00415dab1 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -180,12 +180,12 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
     };
     _saveFilterCommand = {
         params: ["target"], title: "save filter",
-        script: `self.target._docFilters = copyField(self['target-docFilters']); 
+        script: `self.target._docFilters = compareLists(self['target-docFilters'],self.target._docFilters) ? undefined : copyField(self['target-docFilters']); 
                  self.target._searchFilterDocs = compareLists(self['target-searchFilterDocs'],self.target._searchFilterDocs) ? undefined: copyField(self['target-searchFilterDocs']);`,
         immediate: undoBatch((source: Doc[]) => { this.target._docFilters = undefined; this.target._searchFilterDocs = undefined; }),
         initialize: (button: Doc) => {
-            button['target-docFilters'] = this.target._docFilters instanceof ObjectField ? ObjectField.MakeCopy(this.target._docFilters as any as ObjectField) : undefined;
-            button['target-searchFilterDocs'] = this.target._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(this.target._searchFilterDocs as any as ObjectField) : undefined;
+            button['target-docFilters'] = Cast(Doc.UserDoc()["search-panel"], Doc, null)._docFilters instanceof ObjectField ? ObjectField.MakeCopy(Cast(Doc.UserDoc()["search-panel"], Doc, null)._docFilters as any as ObjectField) : undefined;
+            button['target-searchFilterDocs'] = Cast(Doc.UserDoc()["search-panel"], Doc, null)._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(Cast(Doc.UserDoc()["search-panel"], Doc, null)._searchFilterDocs as any as ObjectField) : undefined;
         },
     };
 
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 2f1f7a90f..e37644f2f 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -3,7 +3,7 @@ import { action, observable, trace, computed, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { CellInfo } from "react-table";
 import "react-table/react-table.css";
-import { emptyFunction, returnFalse, returnZero, returnOne, returnEmptyFilter, Utils, emptyPath } from "../../../Utils";
+import { emptyFunction, returnFalse, returnZero, returnOne, returnEmptyFilter, Utils, emptyPath, returnEmptyDoclist } from "../../../Utils";
 import { Doc, DocListCast, Field, Opt } from "../../../fields/Doc";
 import { Id } from "../../../fields/FieldSymbols";
 import { KeyCodes } from "../../util/KeyCodes";
@@ -199,6 +199,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             rootSelected: returnFalse,
             fieldKey: this.props.rowProps.column.id as string,
             docFilters: returnEmptyFilter,
+            searchFilterDocs: returnEmptyDoclist,
             ContainingCollectionView: this.props.CollectionView,
             ContainingCollectionDoc: this.props.CollectionView && this.props.CollectionView.props.Document,
             isSelected: returnFalse,
@@ -511,7 +512,8 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell {
         addDocTab: this.props.addDocTab,
         pinToPres: this.props.pinToPres,
         ContentScaling: returnOne,
-        docFilters: returnEmptyFilter
+        docFilters: returnEmptyFilter,
+        searchFilterDocs: returnEmptyDoclist,
     };
     @observable private _field = this.prop.Document[this.prop.fieldKey];
     @observable private _doc = FieldValue(Cast(this._field, Doc));
@@ -691,7 +693,8 @@ export class CollectionSchemaImageCell extends CollectionSchemaCell {
             addDocTab: this.props.addDocTab,
             pinToPres: this.props.pinToPres,
             ContentScaling: returnOne,
-            docFilters: returnEmptyFilter
+            docFilters: returnEmptyFilter,
+            searchFilterDocs: returnEmptyDoclist,
         };
 
         let image = true;
@@ -770,7 +773,8 @@ export class CollectionSchemaListCell extends CollectionSchemaCell {
         addDocTab: this.props.addDocTab,
         pinToPres: this.props.pinToPres,
         ContentScaling: returnOne,
-        docFilters: returnEmptyFilter
+        docFilters: returnEmptyFilter,
+        searchFilterDocs: returnEmptyDoclist,
     };
     @observable private _field = this.prop.Document[this.prop.fieldKey];
     @observable private _optionsList = this._field as List<any>;
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index c73159084..71e891045 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -136,6 +136,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
             let docsforFilter: Doc[] = childDocs;
 
             if (searchDocs.length > 0) {
+                searchDocs = [...searchDocs, ...docs.filter(d => d.z)];
                 docsforFilter = [];
                 const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
                 searchDocs = DocUtils.FilterDocs(searchDocs, this.docFilters(), docRangeFilters, viewSpecScript);
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index e1c81aeab..7de0b14ac 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -14,7 +14,6 @@ import { ComputedField } from "../../../fields/ScriptField";
 import { Cast, FieldValue, NumCast, StrCast } from "../../../fields/Types";
 import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero, returnEmptyDoclist } from "../../../Utils";
 import { Docs, DocumentOptions } from "../../documents/Documents";
-import { DocumentType } from "../../documents/DocumentTypes";
 import { CompileScript, Transformer, ts } from "../../util/Scripting";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
@@ -22,11 +21,12 @@ import { COLLECTION_BORDER_WIDTH } from '../../views/globalCssVariables.scss';
 import { ContextMenu } from "../ContextMenu";
 import '../DocumentDecorations.scss';
 import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
-import { CellProps, CollectionSchemaButtons, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDateCell, CollectionSchemaDocCell, CollectionSchemaImageCell, CollectionSchemaListCell, CollectionSchemaNumberCell, CollectionSchemaStringCell } from "./CollectionSchemaCells";
+import { CellProps, CollectionSchemaButtons, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDateCell, CollectionSchemaDocCell, CollectionSchemaImageCell, CollectionSchemaListCell, CollectionSchemaNumberCell, CollectionSchemaStringCell, CollectionSchemaBooleanCell } from "./CollectionSchemaCells";
 import { CollectionSchemaAddColumnHeader, KeysDropdown } from "./CollectionSchemaHeaders";
 import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC";
 import "./CollectionSchemaView.scss";
 import { CollectionView } from "./CollectionView";
+import { DocumentType } from "../../documents/DocumentTypes";
 
 
 enum ColumnType {
@@ -91,7 +91,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
 
     @observable _cellIsEditing: boolean = false;
     @observable _focusedCell: { row: number, col: number } = { row: 0, col: 0 };
-    @observable _openCollections: Array<string> = [];
+    @observable _openCollections: Set<number> = new Set;
 
     @observable _showDoc: Doc | undefined;
     @observable _showDataDoc: any = "";
@@ -136,16 +136,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
 
     @action
     changeSorting = (col: any) => {
-        if (col.desc === undefined) {
-            // no sorting
-            this.props.changeColumnSort(col, true);
-        } else if (col.desc === true) {
-            // descending sort
-            this.props.changeColumnSort(col, false);
-        } else if (col.desc === false) {
-            // ascending sort
-            this.props.changeColumnSort(col, undefined);
-        }
+        this.props.changeColumnSort(col, col.desc === true ? false : col.desc === false ? undefined : true);
     }
 
     @action
@@ -153,7 +144,6 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
 
     @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); }
     @computed get tableColumns(): Column<Doc>[] {
-
         const possibleKeys = this.props.documentKeys.filter(key => this.props.columns.findIndex(existingKey => existingKey.heading.toUpperCase() === key.toUpperCase()) === -1);
         const columns: Column<Doc>[] = [];
         const tableIsFocused = this.props.isFocused(this.props.Document, false);
@@ -161,27 +151,16 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
         const focusedCol = this._focusedCell.col;
         const isEditable = !this.props.headerIsEditing;
 
-        //if (this.childDocs.reduce((found, doc) => found || doc.type === DocumentType.COL, false)) {
-        columns.push(
-            {
-                expander: true,
-                Header: "",
-                width: 60,
-                Expander: (rowInfo) => {
-                    if (rowInfo.original.type === "collection") {
-                        return rowInfo.isExpanded ?
-                            <div className="collectionSchemaView-expander" onClick={() => this.onCloseCollection(rowInfo.original)}><FontAwesomeIcon icon={"caret-down"} size="lg" /></div> :
-                            <div className="collectionSchemaView-expander" onClick={() => this.onExpandCollection(rowInfo.original)}><FontAwesomeIcon icon={"caret-right"} size="lg" /></div>;
-                    } else {
-                        return null;
-                    }
-                }
+        columns.push({
+            expander: true, Header: "", width: 60,
+            Expander: (rowInfo) => {
+                return rowInfo.original.type !== DocumentType.COL ? (null) :
+                    <div className="collectionSchemaView-expander" onClick={action(() => (this._openCollections[rowInfo.isExpanded ? "delete" : "add"])(rowInfo.viewIndex))}>
+                        <FontAwesomeIcon icon={rowInfo.isExpanded ? "caret-down" : "caret-right"} size="lg" />
+                    </div>;
             }
-        );
-        // }
-        this.props.active;
-
-        const cols = this.props.columns.map(col => {
+        });
+        columns.push(...this.props.columns.map(col => {
             const icon: IconProp = this.getColumnType(col) === ColumnType.Number ? "hashtag" : this.getColumnType(col) === ColumnType.String ? "font" :
                 this.getColumnType(col) === ColumnType.Boolean ? "check-square" : this.getColumnType(col) === ColumnType.Doc ? "file" :
                     this.getColumnType(col) === ColumnType.Image ? "image" : this.getColumnType(col) === ColumnType.List ? "list-ul" :
@@ -209,25 +188,13 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                 width={"100%"}
             />;
 
-
-
             const sortIcon = col.desc === undefined ? "caret-right" : col.desc === true ? "caret-down" : "caret-up";
-
-            const header =
-                <div //className="collectionSchemaView-header"
-                    //onClick={e => this.props.openHeader(col, menuContent, e.clientX, e.clientY)}
-                    className="collectionSchemaView-menuOptions-wrapper"
-                    style={{
-                        background: col.color, padding: "2px",
-                        display: "flex", cursor: "default", height: "100%",
-                    }}>
-                    {/* <FontAwesomeIcon onClick={e => this.props.openHeader(col, e.clientX, e.clientY)} icon={icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} /> */}
-                    {keysDropdown}
-                    <div onClick={e => this.changeSorting(col)}
-                        style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit", cursor: "hand" }}>
-                        <FontAwesomeIcon icon={sortIcon} size="lg" />
-                    </div>
-                </div>;
+            const header = <div className="collectionSchemaView-menuOptions-wrapper" style={{ background: col.color, padding: "2px", display: "flex", cursor: "default", height: "100%", }}>
+                {keysDropdown}
+                <div onClick={e => this.changeSorting(col)} style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit", cursor: "hand" }}>
+                    <FontAwesomeIcon icon={sortIcon} size="lg" />
+                </div>
+            </div>;
 
             return {
                 Header: <MovableColumn columnRenderer={header} columnValue={col} allColumns={this.props.columns} reorderColumns={this.props.reorderColumns} ScreenToLocalTransform={this.props.ScreenToLocalTransform} />,
@@ -260,21 +227,20 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                         showDoc: this.showDoc,
                     };
 
-                    const colType = this.getColumnType(col);
-                    if (colType === ColumnType.Number) return <CollectionSchemaNumberCell {...props} />;
-                    if (colType === ColumnType.String) return <CollectionSchemaStringCell {...props} />;
-                    if (colType === ColumnType.Boolean) return <CollectionSchemaCheckboxCell {...props} />;
-                    if (colType === ColumnType.Doc) return <CollectionSchemaDocCell {...props} />;
-                    if (colType === ColumnType.Image) return <CollectionSchemaImageCell {...props} />;
-                    if (colType === ColumnType.List) return <CollectionSchemaListCell {...props} />;
-                    if (colType === ColumnType.Date) return <CollectionSchemaDateCell {...props} />;
-                    return <CollectionSchemaCell {...props} />;
+                    switch (this.getColumnType(col)) {
+                        case ColumnType.Number: return <CollectionSchemaNumberCell {...props} />;
+                        case ColumnType.String: return <CollectionSchemaStringCell {...props} />;
+                        case ColumnType.Boolean: return <CollectionSchemaCheckboxCell {...props} />;
+                        case ColumnType.Doc: return <CollectionSchemaDocCell {...props} />;
+                        case ColumnType.Image: return <CollectionSchemaImageCell {...props} />;
+                        case ColumnType.List: return <CollectionSchemaListCell {...props} />;
+                        case ColumnType.Date: return <CollectionSchemaDateCell {...props} />;
+                        default: return <CollectionSchemaCell {...props} />;
+                    }
                 },
                 minWidth: 200,
             };
-        });
-        columns.push(...cols);
-
+        }));
         columns.push({
             Header: <CollectionSchemaAddColumnHeader createColumn={this.createColumn} />,
             accessor: (doc: Doc) => 0,
@@ -283,8 +249,8 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                 const rowIndex = rowProps.index;
                 const columnIndex = this.props.columns.map(c => c.heading).indexOf(rowProps.column.id!);
                 const isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused;
-                const props: CellProps = {
-                    row: rowIndex,
+                return <CollectionSchemaButtons  {...{
+                    row: rowProps.index,
                     col: columnIndex,
                     rowProps: rowProps,
                     isFocused: isFocused,
@@ -303,9 +269,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                     setComputed: this.setComputed,
                     getField: this.getField,
                     showDoc: this.showDoc,
-                };
-
-                return <CollectionSchemaButtons {...props} />;
+                }} />;
             },
             width: 28,
             resizable: false
@@ -316,12 +280,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
 
     constructor(props: SchemaTableProps) {
         super(props);
-        // convert old schema columns (list of strings) into new schema columns (list of schema header fields)
-        const oldSchemaHeaders = Cast(this.props.Document._schemaHeaders, listSpec("string"), []);
-        if (oldSchemaHeaders?.length && typeof oldSchemaHeaders[0] !== "object") {
-            const newSchemaHeaders = oldSchemaHeaders.map(i => typeof i === "string" ? new SchemaHeaderField(i, "#f1efeb") : i);
-            this.props.Document._schemaHeaders = new List<SchemaHeaderField>(newSchemaHeaders);
-        } else if (this.props.Document._schemaHeaders === undefined) {
+        if (this.props.Document._schemaHeaders === undefined) {
             this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb"), new SchemaHeaderField("author", "#f1efeb"), new SchemaHeaderField("*lastModified", "#f1efeb", ColumnType.Date),
             new SchemaHeaderField("text", "#f1efeb", ColumnType.String), new SchemaHeaderField("type", "#f1efeb"), new SchemaHeaderField("context", "#f1efeb", ColumnType.Doc)]);
         }
@@ -362,19 +321,10 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
         const isFocused = this._focusedCell.row === row && this._focusedCell.col === col && this.props.isFocused(this.props.Document, true);
         // TODO: editing border doesn't work :(
         return {
-            style: {
-                border: !this.props.headerIsEditing && isFocused ? "2px solid rgb(255, 160, 160)" : "1px solid #f1efeb"
-            }
+            style: { border: !this.props.headerIsEditing && isFocused ? "2px solid rgb(255, 160, 160)" : "1px solid #f1efeb" }
         };
     }
 
-    @action
-    onCloseCollection = (collection: Doc): void => {
-        const index = this._openCollections.findIndex(col => col === collection[Id]);
-        if (index > -1) this._openCollections.splice(index, 1);
-    }
-
-    @action onExpandCollection = (collection: Doc) => this._openCollections.push(collection[Id]);
     @action setCellIsEditing = (isEditing: boolean) => this._cellIsEditing = isEditing;
 
     @action
@@ -431,21 +381,13 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
 
     @action
     getColumnType = (column: SchemaHeaderField): ColumnType => {
-        // added functionality to convert old column type stuff to new column type stuff -syip
         if (column.type && column.type !== 0) {
             return column.type;
         }
         if (columnTypes.get(column.heading)) {
-            column.type = columnTypes.get(column.heading)!;
-            return columnTypes.get(column.heading)!;
-        }
-        const typesDoc = FieldValue(Cast(this.props.Document.schemaColumnTypes, Doc));
-        if (!typesDoc) {
-            column.type = ColumnType.Any;
-            return ColumnType.Any;
+            return column.type = columnTypes.get(column.heading)!;
         }
-        column.type = NumCast(typesDoc[column.heading]);
-        return NumCast(typesDoc[column.heading]);
+        return column.type = ColumnType.Any;
     }
 
     @undoBatch
@@ -474,11 +416,9 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     @computed
     get reactTable() {
         const children = this.childDocs;
-        const hasCollectionChild = children.reduce((found, doc) => found || doc.type === "collection", false);
-        const expandedRowsList = this._openCollections.map(col => children.findIndex(doc => doc[Id] === col).toString());
-        const expanded = {};
-        //@ts-ignore
-        expandedRowsList.forEach(row => expanded[row] = true);
+        const hasCollectionChild = children.reduce((found, doc) => found || doc.type === DocumentType.COL, false);
+        const expanded: { [name: string]: any } = {};
+        Array.from(this._openCollections.keys()).map(col => expanded[col.toString()] = true);
         const rerender = [...this.textWrappedRows]; // TODO: get component to rerender on text wrap change without needign to console.log :((((
 
         return <ReactTable
@@ -496,17 +436,14 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
             expanded={expanded}
             resized={this.resized}
             onResizedChange={this.props.onResizedChange}
-            SubComponent={!hasCollectionChild ? undefined : row => (row.original.type !== "collection") ? (null) :
+            SubComponent={!hasCollectionChild ? undefined : row => (row.original.type !== DocumentType.COL) ? (null) :
                 <div className="reactTable-sub"><SchemaTable {...this.props} Document={row.original} dataDoc={undefined} childDocs={undefined} /></div>}
 
         />;
     }
 
     onContextMenu = (e: React.MouseEvent): void => {
-        if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
-            // ContextMenu.Instance.addItem({ description: "Make DB", event: this.makeDB, icon: "table" });
-            ContextMenu.Instance.addItem({ description: "Toggle text wrapping", event: this.toggleTextwrap, icon: "table" });
-        }
+        ContextMenu.Instance.addItem({ description: "Toggle text wrapping", event: this.toggleTextwrap, icon: "table" });
     }
 
     getField = (row: number, col?: number) => {
@@ -588,9 +525,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     }
 
     onOpenClick = () => {
-        if (this._showDoc) {
-            this.props.addDocTab(this._showDoc, "onRight");
-        }
+        this._showDoc && this.props.addDocTab(this._showDoc, "onRight");
     }
 
     getPreviewTransform = (): Transform => {
@@ -606,7 +541,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
             {StrCast(this.props.Document._chromeStatus) !== "disabled" ? <div className="collectionSchemaView-addRow" onClick={() => this.createRow()}>+ new</div>
                 : undefined}
             {!this._showDoc ? (null) :
-                <div className="collectionSchemaView-documentPreview" //onClick={() => { this.onOpenClick(); }}
+                <div className="collectionSchemaView-documentPreview"
                     style={{
                         position: "absolute", width: 150, height: 150,
                         background: "dimGray", display: "block", top: 0, left: 0,
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 4568a6b16..6dd85b7f5 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -1,7 +1,7 @@
 import { action, observable } from 'mobx';
 import { observer } from "mobx-react";
 import { Doc, Field, Opt } from '../../../fields/Doc';
-import { emptyFunction, returnFalse, returnOne, returnZero, returnEmptyFilter } from '../../../Utils';
+import { emptyFunction, returnFalse, returnOne, returnZero, returnEmptyFilter, returnEmptyDoclist } from '../../../Utils';
 import { Docs } from '../../documents/Documents';
 import { Transform } from '../../util/Transform';
 import { undoBatch } from '../../util/UndoManager';
@@ -56,7 +56,8 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             Document: this.props.doc,
             DataDoc: this.props.doc,
             LibraryPath: [],
-            docFilters:returnEmptyFilter,
+            docFilters: returnEmptyFilter,
+            searchFilterDocs: returnEmptyDoclist,
             ContainingCollectionView: undefined,
             ContainingCollectionDoc: undefined,
             fieldKey: this.props.keyName,
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 5250a8f58..ba0ac6293 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -906,7 +906,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             search => {
                 search ? this.highlightSearchTerms([Doc.SearchQuery()], search.searchMatch < 0) : this.unhighlightSearchTerms();
             },
-            { fireImmediately: Doc.IsSearchMatch(this.rootDoc) ? true : false });
+            { fireImmediately: Doc.IsSearchMatchUnmemoized(this.rootDoc) ? true : false });
 
         this._disposers.record = reaction(() => this._recording,
             () => {
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 9c9900bfb..e93fc86b5 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -5,7 +5,7 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, DocListCast, Field, Opt } from '../../../fields/Doc';
 import { documentSchema } from "../../../fields/documentSchemas";
-import { Id } from '../../../fields/FieldSymbols';
+import { Id, Copy } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { createSchema, listSpec, makeInterface } from '../../../fields/Schema';
 import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
@@ -15,12 +15,11 @@ import { Docs } from '../../documents/Documents';
 import { DocumentType } from "../../documents/DocumentTypes";
 import { SetupDrag } from '../../util/DragManager';
 import { SearchUtil } from '../../util/SearchUtil';
-import { SelectionManager } from '../../util/SelectionManager';
 import { Transform } from '../../util/Transform';
+import { CollectionDockingView } from "../collections/CollectionDockingView";
 import { CollectionSchemaView, ColumnType } from "../collections/CollectionSchemaView";
 import { CollectionViewType } from '../collections/CollectionView';
 import { ViewBoxBaseComponent } from "../DocComponent";
-import { DocumentView } from '../nodes/DocumentView';
 import { FieldView, FieldViewProps } from '../nodes/FieldView';
 import "./SearchBox.scss";
 
@@ -48,9 +47,8 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
 
     private docsforfilter: Doc[] | undefined = [];
     private realTotalResults: number = 0;
-    private collectionRef = React.createRef<HTMLSpanElement>();
+    private collectionRef = React.createRef<HTMLDivElement>();
 
-    @observable _currentSelectedCollection: DocumentView | undefined = undefined;
     @observable _icons: string[] = this._allIcons;
     @observable _results: [Doc, string[], string[]][] = [];
     @observable _visibleElements: JSX.Element[] = [];
@@ -64,7 +62,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
     @observable open = false;
     @observable children = 0;
     @observable newsearchstring = "";
-    @computed get filter() { return this._results?.length && (this._currentSelectedCollection?.props.Document._searchFilterDocs || this._currentSelectedCollection?.props.Document._docFilters); }
+    @computed get filter() { return this._results?.length && (this.currentSelectedCollection?.props.Document._searchFilterDocs || this.currentSelectedCollection?.props.Document._docFilters); }
 
     constructor(props: any) {
         super(props);
@@ -77,25 +75,24 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             this._searchbarOpen = true;
         }
         this._disposers.filters = reaction(() => this.props.Document._docFilters,
-            (filters: any) => this.setSearchFilter(this._currentSelectedCollection, this.filter ? undefined : this.docsforfilter));
+            (filters: any) => this.setSearchFilter(this.currentSelectedCollection, !this.filter ? undefined : this.docsforfilter));
     });
 
     componentWillUnmount() {
         Object.values(this._disposers).forEach(disposer => disposer?.());
     }
 
+    @computed get currentSelectedCollection() { return CollectionDockingView.Instance; }
+
     @action.bound
     onChange(e: React.ChangeEvent<HTMLInputElement>) {
         this.layoutDoc._searchString = e.target.value;
         this.newsearchstring = e.target.value;
         if (e.target.value === "") {
             this.docsforfilter = undefined;
-            this.setSearchFilter(this._currentSelectedCollection, undefined);
+            this.setSearchFilter(this.currentSelectedCollection, undefined);
             this.resetSearch(false);
 
-            if (this._currentSelectedCollection !== undefined) {
-                this._currentSelectedCollection = undefined;
-            }
             this.open = false;
             this._results = [];
             this._resultsSet.clear();
@@ -149,9 +146,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                 const mod = "_t:";
                 const newWords: string[] = [];
                 const oldWords = values[0].split(" ");
-                oldWords.forEach((word, i) => {
-                    i === 0 ? newWords.push(key + mod + "\"" + word + "\"") : newWords.push("AND " + key + mod + "\"" + word + "\"");
-                });
+                oldWords.forEach((word, i) => i === 0 ? newWords.push(key + mod + "\"" + word + "\"") : newWords.push("AND " + key + mod + "\"" + word + "\""));
                 query = `(${query}) AND (${newWords.join(" ")})`;
             }
             else {
@@ -159,22 +154,12 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                     const mod = "_t:";
                     const newWords: string[] = [];
                     const oldWords = values[i].split(" ");
-                    oldWords.forEach((word, i) => {
-                        i === 0 ? newWords.push(key + mod + "\"" + word + "\"") : newWords.push("AND " + key + mod + "\"" + word + "\"");
-                    });
+                    oldWords.forEach((word, i) => i === 0 ? newWords.push(key + mod + "\"" + word + "\"") : newWords.push("AND " + key + mod + "\"" + word + "\""));
                     const v = "(" + newWords.join(" ") + ")";
                     if (i === 0) {
-                        query = `(${query}) AND (${v}`;
-                        if (values.length === 1) {
-                            query = query + ")";
-                        }
-                    }
-                    else if (i === values.length - 1) {
-                        query = query + " OR " + v + ")";
-                    }
-                    else {
-                        query = query + " OR " + v;
+                        query = `(${query}) AND (${v}` + (values.length === 1 ? ")" : "");
                     }
+                    else query = query + " OR " + v + (i === values.length - 1 ? ")" : "");
                 }
             }
         }
@@ -194,40 +179,15 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         return finalDocs;
     }
 
-    //TODO: basically all of this
-    //gets all of the collections of all the docviews that are selected
-    //if a collection is the only thing selected, search only in that collection (not its container)
-    getCurCollections(): Doc[] {
-        const selectedDocs: DocumentView[] = SelectionManager.SelectedDocuments();
-        const collections: Doc[] = [];
-        selectedDocs.forEach(async element => {
-            const layout: string = StrCast(element.props.Document.layout);
-            //checks if selected view (element) is a collection. if it is, adds to list to search through
-            if (layout.indexOf("Collection") > -1) {
-                //makes sure collections aren't added more than once
-                if (!collections.includes(element.props.Document)) {
-                    collections.push(element.props.Document);
-                }
-            }
-            //makes sure collections aren't added more than once
-            if (element.props.ContainingCollectionDoc && !collections.includes(element.props.ContainingCollectionDoc)) {
-                collections.push(element.props.ContainingCollectionDoc);
-            }
-        });
-
-        return collections;
-    }
-
-
+    @action
     searchCollection(query: string) {
-        const selectedCollection = SelectionManager.SelectedDocuments()[0];
+        const selectedCollection = this.currentSelectedCollection;//SelectionManager.SelectedDocuments()[0];
         query = query.toLowerCase();
 
         if (selectedCollection !== undefined) {
-            this._currentSelectedCollection = selectedCollection;
+            // this._currentSelectedCollection = selectedCollection;
             let docs = DocListCast(selectedCollection.dataDoc[Doc.LayoutFieldKey(selectedCollection.dataDoc)]);
             const found: [Doc, string[], string[]][] = [];
-            const docsforFilter: Doc[] = [];
             let newarray: Doc[] = [];
 
             while (docs.length > 0) {
@@ -239,14 +199,13 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                         Field.toString(d[key] as Field).toLowerCase().includes(query) && hlights.add(key));
                     if (Array.from(hlights.keys()).length > 0) {
                         found.push([d, Array.from(hlights.keys()), []]);
-                        docsforFilter.push(d);
                     }
                 });
                 docs = newarray;
             }
             this._results = found;
-            this.docsforfilter = docsforFilter;
-            this.setSearchFilter(selectedCollection, this.filter && found.length ? docsforFilter : undefined);
+            this.docsforfilter = this._results.map(r => r[0]);
+            this.setSearchFilter(selectedCollection, this.filter && found.length ? this.docsforfilter : undefined);
             this._numTotalResults = found.length;
             this.realTotalResults = found.length;
         }
@@ -285,11 +244,11 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         this._visibleElements = [];
         this._visibleDocuments = [];
 
-        if (query !== "" || this._searchFullDB === "My Stuff") {
+        if (query || this._searchFullDB === "My Stuff") {
             this._endIndex = 12;
             this._maxSearchIndex = 0;
             this._numTotalResults = -1;
-            this._searchFullDB ? await this.getResults(query) : this.searchCollection(query);
+            this._searchFullDB ? await this.searchDatabase(query) : this.searchCollection(query);
             runInAction(() => {
                 this._searchbarOpen = true;
                 this.resultsScrolled();
@@ -307,8 +266,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         const includeDeleted = this._deletedDocsStatus ? "" : " NOT deleted_b:true";
         const typeExpr = this._onlyAliases ? "NOT {!join from=id to=proto_i}type_t:*" : `(type_t:* OR {!join from=id to=proto_i}type_t:*) ${this._blockedTypes.map(type => `NOT ({!join from=id to=proto_i}type_t:${type}) AND NOT type_t:${type}`).join(" AND ")}`;
         // fq: type_t:collection OR {!join from=id to=proto_i}type_t:collection   q:text_t:hello
-        const query = [baseExpr, authorExpr, includeDeleted, typeExpr].filter(q => q).join(" AND ").replace(/AND $/, "");
-        return query;
+        return [baseExpr, authorExpr, includeDeleted, typeExpr].filter(q => q).join(" AND ").replace(/AND $/, "");
     }
 
     @computed get primarySort() {
@@ -324,7 +282,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         return headers.reduce((p: Opt<string>, header: SchemaHeaderField) => p || (header.desc !== undefined && suffixMap(header.type) ? (header.heading + suffixMap(header.type) + (header.desc ? " desc" : " asc")) : undefined), undefined);
     }
 
-    getResults = async (query: string) => {
+    searchDatabase = async (query: string) => {
         this._lockPromise && (await this._lockPromise);
         this._lockPromise = new Promise(async res => {
             while (this._results.length <= this._endIndex && (this._numTotalResults === -1 || this._maxSearchIndex < this._numTotalResults)) {
@@ -368,6 +326,10 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             }
 
             this.resultsScrolled();
+
+            const selectedCollection = this.currentSelectedCollection;//SelectionManager.SelectedDocuments()[0];
+            this.docsforfilter = this._results.map(r => r[0]);
+            this.setSearchFilter(selectedCollection, this.filter ? this.docsforfilter : undefined);
             res();
         });
         return this._lockPromise;
@@ -400,7 +362,8 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                 y += 300;
             }
         }
-        return Docs.Create.SchemaDocument(Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []), DocListCast(this.dataDoc[this.fieldKey]), { _autoHeight: true, _viewType: CollectionViewType.Schema, title: StrCast(this.layoutDoc._searchString) });
+        const headers = Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []).map(h => { const v = h[Copy](); v.color = "#f1efeb"; return v; });
+        return Docs.Create.SchemaDocument(headers, DocListCast(this.dataDoc[this.fieldKey]), { _autoHeight: true, _viewType: CollectionViewType.Schema, title: StrCast(this.layoutDoc._searchString) });
     }
 
     @action.bound
@@ -416,9 +379,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             Doc.UnBrushDoc(result[0]);
             Doc.ClearSearchMatches();
         });
-        if (close) {
-            this._searchbarOpen = false;
-        }
+        close && (this._searchbarOpen = false);
     }
 
     @action.bound
@@ -470,16 +431,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                 }
             }
         }
-        const oldSchemaHeaders = Cast(this.props.Document._schemaHeaders, listSpec("string"), []);
-        if (oldSchemaHeaders?.length && typeof oldSchemaHeaders[0] !== "object") {
-            const newSchemaHeaders = oldSchemaHeaders.map(i => typeof i === "string" ? new SchemaHeaderField(i, "#f1efeb") : i);
-            headers.forEach(header => {
-                if (oldSchemaHeaders.includes(header) === false) {
-                    newSchemaHeaders.push(new SchemaHeaderField(header, "#f1efeb"));
-                }
-            });
-            this.props.Document._schemaHeaders = new List<SchemaHeaderField>(newSchemaHeaders);
-        } else if (this.props.Document._schemaHeaders === undefined) {
+        if (this.props.Document._schemaHeaders === undefined) {
             this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb")]);
         }
         if (this._maxSearchIndex >= this._numTotalResults) {
@@ -488,44 +440,29 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         }
     }
 
-    findCommonElements(arr2: string[]) {
-        const arr1 = ["layout", "data"];
-        return arr1.some(item => arr2.includes(item));
-    }
-
     getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight
     panelHeight = () => this.props.PanelHeight();
-
-    selectElement = (doc: Doc) => {
-        //this.gotoDocument(this.childDocs.indexOf(doc), NumCasst(this.layoutDoc._itemIndex));
-    }
+    selectElement = (doc: Doc) => { /* this.gotoDocument(this.childDocs.indexOf(doc), NumCasst(this.layoutDoc._itemIndex)); */ }
     returnHeight = () => 31 + 31 * 6;
     returnLength = () => Math.min(window.innerWidth, 51 + 205 * Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []).length);
 
     @action
     changeSearchScope = (scope: string) => {
         this.docsforfilter = undefined;
-        this.setSearchFilter(this._currentSelectedCollection, undefined);
+        this.setSearchFilter(this.currentSelectedCollection, undefined);
         this._searchFullDB = scope;
         this.dataDoc[this.fieldKey] = new List<Doc>([]);
         this.submitSearch();
     }
 
     @computed get scopeButtons() {
-        return <div style={{
-            height: 25,
-            paddingLeft: "4px",
-            paddingRight: "4px",
-            border: "1px solid gray",
-            borderRadius: "0.3em",
-            borderBottom: !this.open ? "1px solid" : "none",
-        }}>
+        return <div style={{ height: 25, paddingLeft: "4px", paddingRight: "4px", border: "1px solid gray", borderRadius: "0.3em", borderBottom: !this.open ? "1px solid" : "none", }}>
             <form className="beta" style={{ justifyContent: "space-evenly", display: "flex" }}>
                 <div style={{ display: "contents" }}>
                     <div className="radio" style={{ margin: 0 }}>
                         <label style={{ fontSize: 12, marginTop: 6 }} >
                             <input type="radio" style={{ marginLeft: -16, marginTop: -1 }} checked={!this._searchFullDB} onChange={() => this.changeSearchScope("")} />
-                            Collection
+                            Dashboard
                         </label>
                     </div>
                     <div className="radio" style={{ margin: 0 }}>
@@ -542,7 +479,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         </div>;
     }
 
-    setSearchFilter = (collectionView: DocumentView | undefined, docsForFilter: Doc[] | undefined) => {
+    setSearchFilter = (collectionView: { props: { Document: Doc } }, docsForFilter: Doc[] | undefined) => {
         if (collectionView) {
             const docFilters = Cast(this.props.Document._docFilters, listSpec("string"), null);
             collectionView.props.Document._searchFilterDocs = docsForFilter?.length ? new List<Doc>(docsForFilter) : undefined;
@@ -561,7 +498,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                         <div style={{ display: "flex", alignItems: "center" }}>
                             <div style={{ position: "absolute", left: 10 }}>
                                 <Tooltip title={<div className="dash-tooltip" >drag search results as collection</div>}>
-                                    <div><FontAwesomeIcon onPointerDown={SetupDrag(this.collectionRef, () => StrCast(this.layoutDoc._searchString) ? this.startDragCollection() : undefined)} icon={"search"} size="lg"
+                                    <div ref={this.collectionRef}><FontAwesomeIcon onPointerDown={SetupDrag(this.collectionRef, () => StrCast(this.layoutDoc._searchString) ? this.startDragCollection() : undefined)} icon={"search"} size="lg"
                                         style={{ cursor: "hand", color: "black", padding: 1, position: "relative" }} /></div>
                                 </Tooltip>
                             </div>
@@ -574,7 +511,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                                         <FontAwesomeIcon icon={"filter"} size="lg"
                                             style={{ cursor: "hand", padding: 1, backgroundColor: this.filter ? "white" : "lightgray", color: this.filter ? "black" : "white" }}
                                             onPointerDown={e => { e.stopPropagation(); SetupDrag(this.collectionRef, () => this.layoutDoc._searchString ? this.startDragCollection() : undefined); }}
-                                            onClick={action(() => this.setSearchFilter(this._currentSelectedCollection, this.filter ? undefined : this.docsforfilter))} />
+                                            onClick={action(() => this.setSearchFilter(this.currentSelectedCollection, this.filter ? undefined : this.docsforfilter))} />
                                     </div>
                                 </Tooltip>
                             </div>
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index af2ea73d5..c2b491454 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -915,6 +915,10 @@ export namespace Doc {
                 brushManager.SearchMatchDoc.has(Doc.GetProto(doc)) ? brushManager.SearchMatchDoc.get(Doc.GetProto(doc)) : undefined;
         })(doc);
     }
+    export function IsSearchMatchUnmemoized(doc: Doc) {
+        return brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) :
+            brushManager.SearchMatchDoc.has(Doc.GetProto(doc)) ? brushManager.SearchMatchDoc.get(Doc.GetProto(doc)) : undefined;
+    }
     export function SetSearchMatch(doc: Doc, results: { searchMatch: number }) {
         if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc;
         brushManager.SearchMatchDoc.set(doc, results);
@@ -1276,7 +1280,7 @@ Scripting.addGlobal(function copyDragFactory(dragFactory: Doc) {
         Doc.SetInPlace(ndoc, "title", ndoc.title + " " + NumCast(dragFactory["dragFactory-count"]).toString(), true);
     }
     return ndoc;
-})
+});
 Scripting.addGlobal(function copyField(field: any) { return field instanceof ObjectField ? ObjectField.MakeCopy(field) : field; });
 Scripting.addGlobal(function docList(field: any) { return DocListCast(field); });
 Scripting.addGlobal(function setInPlace(doc: any, field: any, value: any) { return Doc.SetInPlace(doc, field, value, false); });
diff --git a/src/fields/List.ts b/src/fields/List.ts
index 1c2b89b01..3601f282b 100644
--- a/src/fields/List.ts
+++ b/src/fields/List.ts
@@ -334,5 +334,5 @@ Scripting.addGlobal("List", List);
 Scripting.addGlobal(function compareLists(l1: any, l2: any) {
     const L1 = Cast(l1, listSpec("string"), []);
     const L2 = Cast(l2, listSpec("string"), []);
-    return L1 && L2 && L1.length === L2.length && L2.reduce((p, v) => p && L1.includes(v), true);
+    return !L1 && !L2 ? true : L1 && L2 && L1.length === L2.length && L2.reduce((p, v) => p && L1.includes(v), true);
 }, "compare two lists");
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 505ad0d2e2a37795f1877b2319a8ba3a1ce65d28 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 24 Aug 2020 11:21:20 -0400
Subject: cleaned up all library() calls to add icons.  fixed import styles. 
 fixed keyboard events for presentation views to trigger when no input box is
 the target.

---
 src/client/DocServer.ts                            |   2 +-
 src/client/apis/GoogleAuthenticationManager.tsx    |   8 +-
 .../apis/google_docs/GooglePhotosClientUtils.ts    |   2 +-
 src/client/util/CurrentUserUtils.ts                |   2 +-
 src/client/util/GroupManager.tsx                   |  43 +++----
 src/client/util/GroupMemberView.tsx                |  22 ++--
 .../util/Import & Export/DirectoryImportBox.tsx    |   9 +-
 .../util/Import & Export/ImportMetadataEntry.tsx   |   8 +-
 src/client/util/SettingsManager.tsx                |  30 +++--
 src/client/util/SharingManager.tsx                 |  53 ++++----
 src/client/views/AntimodeMenu.tsx                  |   2 +-
 src/client/views/ContextMenu.tsx                   |   5 -
 src/client/views/ContextMenuItem.tsx               |   7 +-
 src/client/views/DictationOverlay.tsx              |   2 +-
 src/client/views/DocumentButtonBar.tsx             |  32 ++---
 src/client/views/DocumentDecorations.tsx           |  43 ++-----
 src/client/views/EditableView.tsx                  |  10 +-
 src/client/views/GestureOverlay.tsx                |   2 +-
 src/client/views/GlobalKeyHandler.ts               |  14 +--
 src/client/views/InkingStroke.tsx                  |  17 +--
 src/client/views/MainView.tsx                      |  49 ++++----
 src/client/views/MainViewModal.tsx                 |   2 +-
 src/client/views/PropertiesButtons.tsx             |  45 +++----
 src/client/views/ScriptingRepl.tsx                 |  17 +--
 .../views/collections/CollectionDockingView.tsx    |   2 +-
 src/client/views/collections/CollectionMenu.tsx    |   8 +-
 .../views/collections/CollectionSchemaCells.tsx    |  58 ++++-----
 .../CollectionSchemaMovableTableHOC.tsx            |   6 +-
 .../views/collections/CollectionSchemaView.tsx     |  15 +--
 .../CollectionStackingViewFieldColumn.tsx          |  14 +--
 src/client/views/collections/CollectionView.tsx    |   7 +-
 .../views/collections/ParentDocumentSelector.tsx   |  24 ++--
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  22 ++--
 .../collectionFreeForm/FormatShapePane.tsx         |   4 +-
 .../collectionFreeForm/MarqueeOptionsMenu.tsx      |   9 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |  11 +-
 .../collectionFreeForm/PropertiesView.tsx          |  52 ++++----
 src/client/views/linking/LinkEditor.tsx            |   5 -
 src/client/views/linking/LinkMenu.tsx              |  16 +--
 src/client/views/linking/LinkMenuItem.tsx          |  26 ++--
 src/client/views/nodes/DocumentView.tsx            |   2 +-
 src/client/views/nodes/FaceRectangles.tsx          |   2 +-
 src/client/views/nodes/ImageBox.tsx                |  15 +--
 src/client/views/nodes/PresBox.tsx                 |  33 +++--
 src/client/views/nodes/RadialMenuItem.tsx          |   8 +-
 src/client/views/nodes/ScreenshotBox.tsx           |   6 +-
 src/client/views/nodes/SliderBox.tsx               |   5 -
 src/client/views/nodes/WebBox.tsx                  |   4 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  13 +-
 .../formattedText/ProsemirrorExampleTransfer.ts    |   2 +-
 .../views/nodes/formattedText/RichTextMenu.tsx     |  19 ++-
 .../views/nodes/formattedText/RichTextRules.ts     |   2 +-
 src/client/views/pdf/Annotation.tsx                |   4 +-
 src/client/views/pdf/PDFMenu.tsx                   |  14 +--
 src/client/views/pdf/PDFViewer.tsx                 |  18 +--
 src/client/views/search/IconBar.tsx                |  25 +---
 src/client/views/search/IconButton.tsx             | 140 ++++++---------------
 src/client/views/webcam/DashWebRTCVideo.tsx        |  24 ++--
 src/mobile/AudioUpload.tsx                         |   4 +-
 src/mobile/ImageUpload.tsx                         |  20 +--
 src/mobile/MobileInterface.tsx                     |  43 +++----
 61 files changed, 423 insertions(+), 685 deletions(-)

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

diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index dde75497c..9da5b8632 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -5,7 +5,7 @@ import { Utils, emptyFunction } from '../Utils';
 import { SerializationHelper } from './util/SerializationHelper';
 import { RefField } from '../fields/RefField';
 import { Id, HandleUpdate, Parent } from '../fields/FieldSymbols';
-import GestureOverlay from './views/GestureOverlay';
+import { GestureOverlay } from './views/GestureOverlay';
 import MobileInkOverlay from '../mobile/MobileInkOverlay';
 import { runInAction } from 'mobx';
 import { ObjectField } from '../fields/ObjectField';
diff --git a/src/client/apis/GoogleAuthenticationManager.tsx b/src/client/apis/GoogleAuthenticationManager.tsx
index 117d1fa1e..cda108058 100644
--- a/src/client/apis/GoogleAuthenticationManager.tsx
+++ b/src/client/apis/GoogleAuthenticationManager.tsx
@@ -1,17 +1,17 @@
-import { observable, action, reaction, runInAction, IReactionDisposer } from "mobx";
+import { action, IReactionDisposer, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import * as React from "react";
-import MainViewModal from "../views/MainViewModal";
 import { Opt } from "../../fields/Doc";
 import { Networking } from "../Network";
-import "./GoogleAuthenticationManager.scss";
 import { Scripting } from "../util/Scripting";
+import { MainViewModal } from "../views/MainViewModal";
+import "./GoogleAuthenticationManager.scss";
 
 const AuthenticationUrl = "https://accounts.google.com/o/oauth2/v2/auth";
 const prompt = "Paste authorization code here...";
 
 @observer
-export default class GoogleAuthenticationManager extends React.Component<{}> {
+export class GoogleAuthenticationManager extends React.Component<{}> {
     public static Instance: GoogleAuthenticationManager;
     private authenticationLink: Opt<string> = undefined;
     @observable private openState = false;
diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts
index 92eaf2e73..899e65a16 100644
--- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts
+++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts
@@ -11,7 +11,7 @@ import { Utils } from "../../../Utils";
 import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents";
 import { Networking } from "../../Network";
 import { FormattedTextBox } from "../../views/nodes/formattedText/FormattedTextBox";
-import GoogleAuthenticationManager from "../GoogleAuthenticationManager";
+import { GoogleAuthenticationManager } from "../GoogleAuthenticationManager";
 import Photos = require('googlephotos');
 
 export namespace GooglePhotos {
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 3ee0c7003..be584c3cf 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -908,7 +908,7 @@ export class CurrentUserUtils {
     // Import sidebar is where shared documents are contained
     static setupImportSidebar(doc: Doc) {
         if (doc["sidebar-import-documents"] === undefined) {
-            doc["sidebar-import-documents"] = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Imported Documents", forceActive: true, _showTitle: "title", childDropAction: "alias", _yMargin: 30, lockedPosition: true, _chromeStatus: "disabled", system: true, _height: 500 }));
+            doc["sidebar-import-documents"] = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Imported Documents", forceActive: true, _showTitle: "title", childDropAction: "alias", _autoHeight: true, _yMargin: 30, lockedPosition: true, _chromeStatus: "disabled", system: true }));
         }
         if (doc["sidebar-import"] === undefined) {
             const uploads = Cast(doc["sidebar-import-documents"], Doc, null);
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index d03989675..612ca7be7 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -1,24 +1,19 @@
-import * as React from "react";
-import { observable, action, runInAction, computed } from "mobx";
-import { SelectionManager } from "./SelectionManager";
-import MainViewModal from "../views/MainViewModal";
-import { observer } from "mobx-react";
-import { Doc, DocListCast, Opt, DocListCastAsync } from "../../fields/Doc";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import * as fa from '@fortawesome/free-solid-svg-icons';
-import { library } from "@fortawesome/fontawesome-svg-core";
-import SharingManager, { User } from "./SharingManager";
-import { Utils } from "../../Utils";
-import * as RequestPromise from "request-promise";
+import { action, computed, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import * as React from "react";
 import Select from 'react-select';
-import "./GroupManager.scss";
-import { StrCast, Cast } from "../../fields/Types";
-import GroupMemberView from "./GroupMemberView";
+import * as RequestPromise from "request-promise";
+import { Doc, DocListCast, DocListCastAsync, Opt } from "../../fields/Doc";
+import { Cast, StrCast } from "../../fields/Types";
 import { setGroups } from "../../fields/util";
+import { Utils } from "../../Utils";
 import { DocServer } from "../DocServer";
+import { MainViewModal } from "../views/MainViewModal";
 import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox";
-
-library.add(fa.faPlus, fa.faTimes, fa.faInfoCircle, fa.faCaretUp, fa.faCaretRight, fa.faCaretDown);
+import "./GroupManager.scss";
+import { GroupMemberView } from "./GroupMemberView";
+import { SharingManager, User } from "./SharingManager";
 
 /**
  * Interface for options for the react-select component
@@ -29,7 +24,7 @@ export interface UserOptions {
 }
 
 @observer
-export default class GroupManager extends React.Component<{}> {
+export class GroupManager extends React.Component<{}> {
 
     static Instance: GroupManager;
     @observable isOpen: boolean = false; // whether the GroupManager is to be displayed or not.
@@ -314,7 +309,7 @@ export default class GroupManager extends React.Component<{}> {
                     <div className={"close-button"} onClick={action(() => {
                         this.createGroupModalOpen = false; TaskCompletionBox.taskCompleted = false;
                     })}>
-                        <FontAwesomeIcon icon={fa.faTimes} color={"black"} size={"lg"} />
+                        <FontAwesomeIcon icon={"times"} color={"black"} size={"lg"} />
                     </div>
                 </div>
                 <input
@@ -398,19 +393,19 @@ export default class GroupManager extends React.Component<{}> {
                 <div className="group-heading">
                     <p><b>Manage Groups</b></p>
                     <button onClick={action(() => this.createGroupModalOpen = true)}>
-                        <FontAwesomeIcon icon={fa.faPlus} size={"sm"} /> Create Group
+                        <FontAwesomeIcon icon={"plus-hexagon"} size={"sm"} /> Create Group
                     </button>
                     <div className={"close-button"} onClick={this.close}>
-                        <FontAwesomeIcon icon={fa.faTimes} color={"black"} size={"lg"} />
+                        <FontAwesomeIcon icon={"times"} color={"black"} size={"lg"} />
                     </div>
                 </div>
                 <div className="main-container">
                     <div
                         className="sort-groups"
                         onClick={action(() => this.groupSort = this.groupSort === "ascending" ? "descending" : this.groupSort === "descending" ? "none" : "ascending")}>
-                        Name {this.groupSort === "ascending" ? <FontAwesomeIcon icon={fa.faCaretUp} size={"xs"} />
-                            : this.groupSort === "descending" ? <FontAwesomeIcon icon={fa.faCaretDown} size={"xs"} />
-                                : <FontAwesomeIcon icon={fa.faCaretRight} size={"xs"} />
+                        Name {this.groupSort === "ascending" ? <FontAwesomeIcon icon={"caret-up"} size={"xs"} />
+                            : this.groupSort === "descending" ? <FontAwesomeIcon icon={"caret-down"} size={"xs"} />
+                                : <FontAwesomeIcon icon={"caret-right"} size={"xs"} />
                         }
                     </div>
                     <div className="group-body">
@@ -421,7 +416,7 @@ export default class GroupManager extends React.Component<{}> {
                             >
                                 <div className="group-name" >{group.groupName}</div>
                                 <div className="group-info" onClick={action(() => this.currentGroup = group)}>
-                                    <FontAwesomeIcon icon={fa.faInfoCircle} color={"#e8e8e8"} size={"sm"} style={{ backgroundColor: "#1e89d7", borderRadius: "100%", border: "1px solid #1e89d7" }} />
+                                    <FontAwesomeIcon icon={"info-circle"} color={"#e8e8e8"} size={"sm"} style={{ backgroundColor: "#1e89d7", borderRadius: "100%", border: "1px solid #1e89d7" }} />
                                 </div>
                             </div>
                         )}
diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx
index 531ef988a..4ead01e9f 100644
--- a/src/client/util/GroupMemberView.tsx
+++ b/src/client/util/GroupMemberView.tsx
@@ -1,25 +1,21 @@
-import * as React from "react";
-import MainViewModal from "../views/MainViewModal";
-import { observer } from "mobx-react";
-import GroupManager, { UserOptions } from "./GroupManager";
-import { library } from "@fortawesome/fontawesome-svg-core";
-import { StrCast } from "../../fields/Types";
-import { action, observable } from "mobx";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import * as fa from '@fortawesome/free-solid-svg-icons';
+import { action, observable } from "mobx";
+import { observer } from "mobx-react";
+import * as React from "react";
 import Select from "react-select";
 import { Doc } from "../../fields/Doc";
+import { StrCast } from "../../fields/Types";
+import { MainViewModal } from "../views/MainViewModal";
+import { GroupManager, UserOptions } from "./GroupManager";
 import "./GroupMemberView.scss";
 
-library.add(fa.faTimes, fa.faTrashAlt);
-
 interface GroupMemberViewProps {
     group: Doc;
     onCloseButtonClick: () => void;
 }
 
 @observer
-export default class GroupMemberView extends React.Component<GroupMemberViewProps> {
+export class GroupMemberView extends React.Component<GroupMemberViewProps> {
 
     @observable private memberSort: "ascending" | "descending" | "none" = "none";
 
@@ -43,7 +39,7 @@ export default class GroupMemberView extends React.Component<GroupMemberViewProp
                     >
                     </input>
                     <div className={"memberView-closeButton"} onClick={action(this.props.onCloseButtonClick)}>
-                        <FontAwesomeIcon icon={fa.faTimes} color={"black"} size={"lg"} />
+                        <FontAwesomeIcon icon={"times"} color={"black"} size={"lg"} />
                     </div>
                     {GroupManager.Instance.hasEditAccess(this.props.group) ?
                         <div className="group-buttons">
@@ -88,7 +84,7 @@ export default class GroupMemberView extends React.Component<GroupMemberViewProp
                             </div>
                             {hasEditAccess ?
                                 <div className={"remove-button"} onClick={() => GroupManager.Instance.removeMemberFromGroup(this.props.group, member)}>
-                                    <FontAwesomeIcon icon={fa.faTrashAlt} size={"sm"} />
+                                    <FontAwesomeIcon icon={"trash-alt"} size={"sm"} />
                                 </div>
                                 : null}
                         </div>
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx
index 77f13e9f4..d04270afa 100644
--- a/src/client/util/Import & Export/DirectoryImportBox.tsx	
+++ b/src/client/util/Import & Export/DirectoryImportBox.tsx	
@@ -1,5 +1,3 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faCloudUploadAlt, faPlus, faTag } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { BatchedArray } from "array-batcher";
 import "fs";
@@ -47,7 +45,6 @@ export class DirectoryImportBox extends React.Component<FieldViewProps> {
 
     constructor(props: FieldViewProps) {
         super(props);
-        library.add(faTag, faPlus);
         const doc = this.props.Document;
         this.editingMetadata = this.editingMetadata || false;
         this.persistent = this.persistent || false;
@@ -301,7 +298,7 @@ export class DirectoryImportBox extends React.Component<FieldViewProps> {
                                 opacity: uploading ? 0 : 1,
                                 transition: "0.4s opacity ease"
                             }}>
-                                <FontAwesomeIcon icon={faCloudUploadAlt} color="#FFFFFF" size={"2x"} />
+                                <FontAwesomeIcon icon={"cloud-upload-alt"} color="#FFFFFF" size={"2x"} />
                             </div>
                             <img
                                 style={{
@@ -366,7 +363,7 @@ export class DirectoryImportBox extends React.Component<FieldViewProps> {
                                 opacity: uploading ? 0 : 1,
                                 transition: "0.4s opacity ease"
                             }}
-                            icon={isEditing ? faCloudUploadAlt : faTag}
+                            icon={isEditing ? "cloud-upload-alt" : "tag"}
                             color="#FFFFFF"
                             size={"1x"}
                         />
@@ -399,7 +396,7 @@ export class DirectoryImportBox extends React.Component<FieldViewProps> {
                                         marginLeft: 6.4,
                                         marginTop: 5.2
                                     }}
-                                    icon={faPlus}
+                                    icon={"plus"}
                                     size={"1x"}
                                 />
                             </div>
diff --git a/src/client/util/Import & Export/ImportMetadataEntry.tsx b/src/client/util/Import & Export/ImportMetadataEntry.tsx
index dcb94e2e0..1870213b9 100644
--- a/src/client/util/Import & Export/ImportMetadataEntry.tsx	
+++ b/src/client/util/Import & Export/ImportMetadataEntry.tsx	
@@ -4,7 +4,6 @@ import { EditableView } from "../../views/EditableView";
 import { action, computed } from "mobx";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { faPlus } from "@fortawesome/free-solid-svg-icons";
-import { library } from '@fortawesome/fontawesome-svg-core';
 import { Doc } from "../../../fields/Doc";
 import { StrCast, BoolCast } from "../../../fields/Types";
 
@@ -24,11 +23,6 @@ export default class ImportMetadataEntry extends React.Component<KeyValueProps>
     private valueRef = React.createRef<EditableView>();
     private checkRef = React.createRef<HTMLInputElement>();
 
-    constructor(props: KeyValueProps) {
-        super(props);
-        library.add(faPlus);
-    }
-
     @computed
     public get valid() {
         return (this.key.length > 0 && this.key !== keyPlaceholder) && (this.value.length > 0 && this.value !== valuePlaceholder);
@@ -132,7 +126,7 @@ export default class ImportMetadataEntry extends React.Component<KeyValueProps>
                 </div>
                 <div onClick={() => this.props.remove(this)} title={"Delete Entry"}>
                     <FontAwesomeIcon
-                        icon={faPlus}
+                        icon={"plus"}
                         color={"red"}
                         size={"1x"}
                         style={{
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index bc5e1e9d3..e9befc465 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -1,27 +1,25 @@
-import { observable, runInAction, action, computed } from "mobx";
-import * as React from "react";
-import MainViewModal from "../views/MainViewModal";
-import { observer } from "mobx-react";
-import * as fa from '@fortawesome/free-solid-svg-icons';
-import { SelectionManager } from "./SelectionManager";
-import "./SettingsManager.scss";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { Networking } from "../Network";
-import { CurrentUserUtils } from "./CurrentUserUtils";
-import { Utils, addStyleSheet, addStyleSheetRule, removeStyleSheetRule } from "../../Utils";
+import { action, computed, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import * as React from "react";
+import { ColorState, SketchPicker } from "react-color";
 import { Doc } from "../../fields/Doc";
-import GroupManager from "./GroupManager";
-import GoogleAuthenticationManager from "../apis/GoogleAuthenticationManager";
+import { BoolCast, StrCast } from "../../fields/Types";
+import { addStyleSheet, addStyleSheetRule, Utils } from "../../Utils";
+import { GoogleAuthenticationManager } from "../apis/GoogleAuthenticationManager";
 import { DocServer } from "../DocServer";
-import { BoolCast, StrCast, NumCast } from "../../fields/Types";
+import { Networking } from "../Network";
+import { MainViewModal } from "../views/MainViewModal";
+import { CurrentUserUtils } from "./CurrentUserUtils";
+import { GroupManager } from "./GroupManager";
+import "./SettingsManager.scss";
 import { undoBatch } from "./UndoManager";
-import { ColorState, SketchPicker } from "react-color";
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
 
 @observer
-export default class SettingsManager extends React.Component<{}> {
+export class SettingsManager extends React.Component<{}> {
     public static Instance: SettingsManager;
     static _settingsStyle = addStyleSheet();
     @observable private isOpen = false;
@@ -166,7 +164,7 @@ export default class SettingsManager extends React.Component<{}> {
                     {CurrentUserUtils.GuestDashboard ? "Exit" : "Log Out"}
                 </button>
                 <div className="close-button" onClick={this.close}>
-                    <FontAwesomeIcon icon={fa.faTimes} color="black" size={"lg"} />
+                    <FontAwesomeIcon icon={"times"} color="black" size={"lg"} />
                 </div>
             </div>
             <div className="settings-content">
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index b9918e900..a73cb63d0 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -1,29 +1,24 @@
-import { observable, runInAction, action } from "mobx";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
 import * as React from "react";
-import MainViewModal from "../views/MainViewModal";
-import { Doc, Opt, AclAdmin, AclPrivate, DocListCast, DataSym } from "../../fields/Doc";
-import { DocServer } from "../DocServer";
-import { Cast, StrCast } from "../../fields/Types";
+import Select from "react-select";
 import * as RequestPromise from "request-promise";
+import { AclAdmin, AclPrivate, DataSym, Doc, DocListCast, Opt } from "../../fields/Doc";
+import { List } from "../../fields/List";
+import { Cast, StrCast } from "../../fields/Types";
+import { distributeAcls, GetEffectiveAcl, SharingPermissions } from "../../fields/util";
 import { Utils } from "../../Utils";
-import "./SharingManager.scss";
-import { observer } from "mobx-react";
-import * as fa from '@fortawesome/free-solid-svg-icons';
-import { DocumentView } from "../views/nodes/DocumentView";
-import { SelectionManager } from "./SelectionManager";
-import { DocumentManager } from "./DocumentManager";
+import { DocServer } from "../DocServer";
 import { CollectionView } from "../views/collections/CollectionView";
 import { DictationOverlay } from "../views/DictationOverlay";
-import GroupManager, { UserOptions } from "./GroupManager";
-import GroupMemberView from "./GroupMemberView";
-import Select from "react-select";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { List } from "../../fields/List";
-import { distributeAcls, SharingPermissions, GetEffectiveAcl } from "../../fields/util";
+import { MainViewModal } from "../views/MainViewModal";
+import { DocumentView } from "../views/nodes/DocumentView";
 import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox";
-import { library } from "@fortawesome/fontawesome-svg-core";
-
-library.add(fa.faInfoCircle, fa.faCaretUp, fa.faCaretRight, fa.faCaretDown);
+import { DocumentManager } from "./DocumentManager";
+import { GroupManager, UserOptions } from "./GroupManager";
+import { GroupMemberView } from "./GroupMemberView";
+import "./SharingManager.scss";
 
 export interface User {
     email: string;
@@ -58,7 +53,7 @@ interface ValidatedUser {
 
 
 @observer
-export default class SharingManager extends React.Component<{}> {
+export class SharingManager extends React.Component<{}> {
     public static Instance: SharingManager;
     @observable private isOpen = false; // whether the SharingManager modal is open or not
     @observable private users: ValidatedUser[] = []; // the list of users with notificationDocs
@@ -486,7 +481,7 @@ export default class SharingManager extends React.Component<{}> {
                 >
                     <div className={"padding"}>{group.groupName}</div>
                     <div className="group-info" onClick={action(() => GroupManager.Instance.currentGroup = group)}>
-                        <FontAwesomeIcon icon={fa.faInfoCircle} color={"#e8e8e8"} size={"sm"} style={{ backgroundColor: "#1e89d7", borderRadius: "100%", border: "1px solid #1e89d7" }} />
+                        <FontAwesomeIcon icon={"info-circle"} color={"#e8e8e8"} size={"sm"} style={{ backgroundColor: "#1e89d7", borderRadius: "100%", border: "1px solid #1e89d7" }} />
                     </div>
                     <div className="edit-actions">
                         <select
@@ -522,7 +517,7 @@ export default class SharingManager extends React.Component<{}> {
                             style={{ backgroundColor: this.copied ? "lawngreen" : "gainsboro" }}
                             onClick={this.copy}
                         >
-                            <FontAwesomeIcon icon={fa.faCopy} />
+                            <FontAwesomeIcon icon={"copy"} />
                         </div>
                     </div>
                 }
@@ -584,9 +579,9 @@ export default class SharingManager extends React.Component<{}> {
                             <div
                                 className="user-sort"
                                 onClick={action(() => this.individualSort = this.individualSort === "ascending" ? "descending" : this.individualSort === "descending" ? "none" : "ascending")}>
-                                Individuals {this.individualSort === "ascending" ? <FontAwesomeIcon icon={fa.faCaretUp} size={"xs"} />
-                                    : this.individualSort === "descending" ? <FontAwesomeIcon icon={fa.faCaretDown} size={"xs"} />
-                                        : <FontAwesomeIcon icon={fa.faCaretRight} size={"xs"} />}
+                                Individuals {this.individualSort === "ascending" ? <FontAwesomeIcon icon={"caret-up"} size={"xs"} />
+                                    : this.individualSort === "descending" ? <FontAwesomeIcon icon={"caret-down"} size={"xs"} />
+                                        : <FontAwesomeIcon icon={"caret-right"} size={"xs"} />}
                             </div>
                             <div className={"users-list"} style={{ display: "block" }}>{/*200*/}
                                 {userListContents}
@@ -596,9 +591,9 @@ export default class SharingManager extends React.Component<{}> {
                             <div
                                 className="user-sort"
                                 onClick={action(() => this.groupSort = this.groupSort === "ascending" ? "descending" : this.groupSort === "descending" ? "none" : "ascending")}>
-                                Groups {this.groupSort === "ascending" ? <FontAwesomeIcon icon={fa.faCaretUp} size={"xs"} />
-                                    : this.groupSort === "descending" ? <FontAwesomeIcon icon={fa.faCaretDown} size={"xs"} />
-                                        : <FontAwesomeIcon icon={fa.faCaretRight} size={"xs"} />}
+                                Groups {this.groupSort === "ascending" ? <FontAwesomeIcon icon={"caret-up"} size={"xs"} />
+                                    : this.groupSort === "descending" ? <FontAwesomeIcon icon={"caret-down"} size={"xs"} />
+                                        : <FontAwesomeIcon icon={"caret-right"} size={"xs"} />}
 
                             </div>
                             <div className={"groups-list"} style={{ display: !displayGroupList ? "flex" : "block" }}>{/*200*/}
diff --git a/src/client/views/AntimodeMenu.tsx b/src/client/views/AntimodeMenu.tsx
index ccc54058d..32fb24b32 100644
--- a/src/client/views/AntimodeMenu.tsx
+++ b/src/client/views/AntimodeMenu.tsx
@@ -8,7 +8,7 @@ export interface AntimodeMenuProps {
  * This is an abstract class that serves as the base for a PDF-style or Marquee-style
  * menu. To use this class, look at PDFMenu.tsx or MarqueeOptionsMenu.tsx for an example.
  */
-export default abstract class AntimodeMenu<T extends AntimodeMenuProps> extends React.Component<T, {}> {
+export abstract class AntimodeMenu<T extends AntimodeMenuProps> extends React.Component<T, {}> {
     protected _offsetY: number = 0;
     protected _offsetX: number = 0;
     protected _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index 07f7b8e6d..cb34b8873 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -3,14 +3,9 @@ import { ContextMenuItem, ContextMenuProps, OriginalMenuProps } from "./ContextM
 import { observable, action, computed, runInAction, IReactionDisposer, reaction } from "mobx";
 import { observer } from "mobx-react";
 import "./ContextMenu.scss";
-import { library } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faSearch, faCircle } from '@fortawesome/free-solid-svg-icons';
 import Measure from "react-measure";
 
-library.add(faSearch);
-library.add(faCircle);
-
 @observer
 export class ContextMenu extends React.Component {
     static Instance: ContextMenu;
diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index 7e233ec04..22bfbe217 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -1,13 +1,10 @@
 import React = require("react");
 import { observable, action } from "mobx";
 import { observer } from "mobx-react";
-import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faAngleRight } from '@fortawesome/free-solid-svg-icons';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { UndoManager } from "../util/UndoManager";
 
-library.add(faAngleRight);
-
 export interface OriginalMenuProps {
     description: string;
     event: (stuff?: any) => void;
@@ -115,7 +112,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
                     <div className="contextMenu-description" onMouseEnter={this.onPointerEnter}
                         style={{ alignItems: "center" }} >
                         {this.props.description}
-                        <FontAwesomeIcon icon={faAngleRight} size="lg" style={{ position: "absolute", right: "10px" }} />
+                        <FontAwesomeIcon icon={"angle-right"} size="lg" style={{ position: "absolute", right: "10px" }} />
                     </div>
                     {submenu}
                 </div>
diff --git a/src/client/views/DictationOverlay.tsx b/src/client/views/DictationOverlay.tsx
index 9ed14509f..f4f96da8a 100644
--- a/src/client/views/DictationOverlay.tsx
+++ b/src/client/views/DictationOverlay.tsx
@@ -4,7 +4,7 @@ import "normalize.css";
 import * as React from 'react';
 import { DictationManager } from '../util/DictationManager';
 import "./Main.scss";
-import MainViewModal from './MainViewModal';
+import { MainViewModal } from './MainViewModal';
 
 @observer
 export class DictationOverlay extends React.Component {
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 17ed211dd..659adebbc 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -1,48 +1,34 @@
-import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faArrowAltCircleDown, faArrowAltCircleRight, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faPhotoVideo, faShare, faStopCircle, faSyncAlt, faTag, faTimes } from '@fortawesome/free-solid-svg-icons';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { Tooltip } from '@material-ui/core';
 import { action, computed, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, DocListCast } from "../../fields/Doc";
+import { Doc } from "../../fields/Doc";
 import { RichTextField } from '../../fields/RichTextField';
 import { Cast, NumCast } from "../../fields/Types";
 import { emptyFunction, setupMoveUpEvents } from "../../Utils";
-import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
+import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
 import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils';
-import { Docs, DocUtils } from '../documents/Documents';
+import { Docs } from '../documents/Documents';
+import { CurrentUserUtils } from '../util/CurrentUserUtils';
 import { DragManager } from '../util/DragManager';
+import { SelectionManager } from '../util/SelectionManager';
+import { SharingManager } from '../util/SharingManager';
 import { CollectionDockingView, DockedFrameRenderer } from './collections/CollectionDockingView';
 import { ParentDocSelector } from './collections/ParentDocumentSelector';
 import './collections/ParentDocumentSelector.scss';
 import './DocumentButtonBar.scss';
 import { MetadataEntryMenu } from './MetadataEntryMenu';
+import { DocumentLinksButton } from './nodes/DocumentLinksButton';
 import { DocumentView } from './nodes/DocumentView';
 import { GoogleRef } from "./nodes/formattedText/FormattedTextBox";
 import { TemplateMenu } from "./TemplateMenu";
 import { Template, Templates } from "./Templates";
 import React = require("react");
-import { DocumentLinksButton } from './nodes/DocumentLinksButton';
-import { Tooltip } from '@material-ui/core';
-import SharingManager from '../util/SharingManager';
-import { CurrentUserUtils } from '../util/CurrentUserUtils';
-import { SelectionManager } from '../util/SelectionManager';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
 
-library.add(faLink);
-library.add(faTag);
-library.add(faTimes);
-library.add(faArrowAltCircleDown);
-library.add(faArrowAltCircleUp);
-library.add(faArrowAltCircleRight);
-library.add(faStopCircle);
-library.add(faCheckCircle);
-library.add(faCloudUploadAlt);
-library.add(faSyncAlt);
-library.add(faShare);
-library.add(faPhotoVideo);
-
 const cloud: IconProp = "cloud-upload-alt";
 const fetch: IconProp = "sync-alt";
 
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 8e44bcf8f..7b665ccd3 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,5 +1,4 @@
-import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faAngleDoubleLeft, faAngleDoubleRight, faAngleLeft, faAngleRight, faArrowAltCircleDown, faArrowAltCircleUp, faCaretUp, faCheckCircle, faCloudUploadAlt, faExternalLinkAlt, faFilePdf, faFilm, faImage, faLink, faObjectGroup, faPause, faShare, faStickyNote, faStopCircle, faSyncAlt, faTag, faTextHeight, faTimes } from '@fortawesome/free-solid-svg-icons';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { Tooltip } from '@material-ui/core';
 import { action, computed, observable, reaction, runInAction } from "mobx";
@@ -19,35 +18,13 @@ import { SelectionManager } from "../util/SelectionManager";
 import { SnappingManager } from '../util/SnappingManager';
 import { undoBatch, UndoManager } from "../util/UndoManager";
 import { CollectionDockingView } from './collections/CollectionDockingView';
-import FormatShapePane from './collections/collectionFreeForm/FormatShapePane';
+import { FormatShapePane } from './collections/collectionFreeForm/FormatShapePane';
 import { DocumentButtonBar } from './DocumentButtonBar';
 import './DocumentDecorations.scss';
 import { DocumentView } from "./nodes/DocumentView";
 import React = require("react");
 import e = require('express');
 
-library.add(faCaretUp);
-library.add(faObjectGroup);
-library.add(faStickyNote);
-library.add(faFilePdf);
-library.add(faFilm, faTextHeight);
-library.add(faLink);
-library.add(faTag);
-library.add(faTimes);
-library.add(faArrowAltCircleDown);
-library.add(faArrowAltCircleUp);
-library.add(faStopCircle);
-library.add(faCheckCircle);
-library.add(faCloudUploadAlt);
-library.add(faSyncAlt);
-library.add(faShare);
-library.add(faAngleDoubleLeft);
-library.add(faAngleDoubleRight);
-library.add(faAngleLeft);
-library.add(faAngleRight);
-library.add(faPause);
-library.add(faExternalLinkAlt);
-
 @observer
 export class DocumentDecorations extends React.Component<{}, { value: string }> {
     static Instance: DocumentDecorations;
@@ -587,12 +564,12 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         }
     }
     public static DocumentIcon(layout: string) {
-        const button = layout.indexOf("PDFBox") !== -1 ? faFilePdf :
-            layout.indexOf("ImageBox") !== -1 ? faImage :
-                layout.indexOf("Formatted") !== -1 ? faStickyNote :
-                    layout.indexOf("Video") !== -1 ? faFilm :
-                        layout.indexOf("Collection") !== -1 ? faObjectGroup :
-                            faCaretUp;
+        const button = layout.indexOf("PDFBox") !== -1 ? "file-pdf" :
+            layout.indexOf("ImageBox") !== -1 ? "image" :
+                layout.indexOf("Formatted") !== -1 ? "sticky-note" :
+                    layout.indexOf("Video") !== -1 ? "film" :
+                        layout.indexOf("Collection") !== -1 ? "object-group" :
+                            "caret-up";
         return <FontAwesomeIcon icon={button} className="documentView-minimizedIcon" />;
     }
     render() {
@@ -615,7 +592,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                     <Tooltip title={<><div className="dash-tooltip">Close</div></>} placement="top">
                         <div className="documentDecorations-closeButton" onClick={this.onCloseClick}>
                             {/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/}
-                            <FontAwesomeIcon className="documentdecorations-times" icon={faTimes} size="lg" />
+                            <FontAwesomeIcon className="documentdecorations-times" icon={"times"} size="lg" />
                         </div></Tooltip>) : (null);
 
         const titleArea = this._edtingTitle ?
@@ -705,7 +682,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                         <Tooltip title={<><div className="dash-tooltip">tap to select containing document</div></>} placement="top">
                             <div id="documentDecorations-levelSelector" className="documentDecorations-selector"
                                 onPointerDown={this.onSelectorUp} onContextMenu={e => e.preventDefault()}>
-                                <FontAwesomeIcon className="documentdecorations-times" icon={faArrowAltCircleUp} size="lg" />
+                                <FontAwesomeIcon className="documentdecorations-times" icon={"arrow-alt-circle-up"} size="lg" />
                             </div></Tooltip>}
                     <div id={`documentDecorations-${useRotation ? "rotation" : "borderRadius"}`}
                         onPointerDown={useRotation ? this.onRotateDown : this.onRadiusDown} onContextMenu={(e) => e.preventDefault()}>{useRotation && "⟲"}</div>
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index a4b059482..d0e6ed463 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -4,11 +4,8 @@ import { observer } from 'mobx-react';
 import * as Autosuggest from 'react-autosuggest';
 import { ObjectField } from '../../fields/ObjectField';
 import { SchemaHeaderField } from '../../fields/SchemaHeaderField';
-import "./EditableView.scss";
 import { DragManager } from '../util/DragManager';
-import { ComputedField } from '../../fields/ScriptField';
-import { FieldValue } from '../../fields/Types';
-import { PresBox } from './nodes/PresBox';
+import "./EditableView.scss";
 
 export interface EditableProps {
     /**
@@ -172,6 +169,7 @@ export class EditableView extends React.Component<EditableProps> {
                     onPointerDown: this.stopPropagation,
                     onClick: this.stopPropagation,
                     onPointerUp: this.stopPropagation,
+                    onKeyPress: this.stopPropagation,
                     value: this.props.autosuggestProps.value,
                     onChange: this.props.autosuggestProps.onChange
                 }}
@@ -180,6 +178,10 @@ export class EditableView extends React.Component<EditableProps> {
                 defaultValue={this.props.GetValue()}
                 onKeyDown={this.onKeyDown}
                 autoFocus={true}
+                onKeyPress={e => {
+                    e.stopPropagation();
+                    (e.nativeEvent as any).Aaaa = 3;
+                }}
                 onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true)}
                 onPointerDown={this.stopPropagation} onClick={this.stopPropagation} onPointerUp={this.stopPropagation}
                 style={{ display: this.props.display, fontSize: this.props.fontSize, minWidth: 20 }}
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 260cffc90..63711a3cb 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -26,7 +26,7 @@ import * as fitCurve from 'fit-curve';
 import { CollectionFreeFormViewChrome } from "./collections/CollectionMenu";
 
 @observer
-export default class GestureOverlay extends Touchable {
+export class GestureOverlay extends Touchable {
     static Instance: GestureOverlay;
 
     @observable public InkShape: string = "";
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 9e7f525b7..b29a04ea7 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -6,22 +6,22 @@ import { InkTool } from "../../fields/InkField";
 import { List } from "../../fields/List";
 import { ScriptField } from "../../fields/ScriptField";
 import { Cast, PromiseValue } from "../../fields/Types";
-import GoogleAuthenticationManager from "../apis/GoogleAuthenticationManager";
+import { GoogleAuthenticationManager } from "../apis/GoogleAuthenticationManager";
 import { DocServer } from "../DocServer";
 import { DocumentType } from "../documents/DocumentTypes";
 import { DictationManager } from "../util/DictationManager";
 import { DragManager } from "../util/DragManager";
 import { SelectionManager } from "../util/SelectionManager";
-import SharingManager from "../util/SharingManager";
+import { SharingManager } from "../util/SharingManager";
 import { undoBatch, UndoManager } from "../util/UndoManager";
 import { CollectionDockingView } from "./collections/CollectionDockingView";
 import { DocumentDecorations } from "./DocumentDecorations";
 import { MainView } from "./MainView";
 import { DocumentView } from "./nodes/DocumentView";
 import { DocumentLinksButton } from "./nodes/DocumentLinksButton";
-import PDFMenu from "./pdf/PDFMenu";
+import { PDFMenu } from "./pdf/PDFMenu";
 import { ContextMenu } from "./ContextMenu";
-import GroupManager from "../util/GroupManager";
+import { GroupManager } from "../util/GroupManager";
 import { CollectionFreeFormViewChrome } from "./collections/CollectionMenu";
 
 const modifiers = ["control", "meta", "shift", "alt"];
@@ -31,7 +31,7 @@ type KeyControlInfo = {
     stopPropagation: boolean
 };
 
-export default class KeyManager {
+export class KeyManager {
     public static Instance: KeyManager = new KeyManager();
     private router = new Map<string, KeyHandler>();
 
@@ -121,9 +121,7 @@ export default class KeyManager {
                 }
 
                 const selected = SelectionManager.SelectedDocuments().slice();
-                UndoManager.RunInBatch(() => {
-                    selected.map(dv => dv.props.removeDocument?.(dv.props.Document));
-                }, "delete");
+                UndoManager.RunInBatch(() => selected.map(dv => dv.props.removeDocument?.(dv.props.Document)), "delete");
                 SelectionManager.DeselectAll();
                 break;
             case "arrowleft":
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 3376fcd97..b972d4e41 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -1,27 +1,22 @@
-import { library } from "@fortawesome/fontawesome-svg-core";
-import { faPaintBrush } from "@fortawesome/free-solid-svg-icons";
+import { action } from "mobx";
 import { observer } from "mobx-react";
+import { Doc } from "../../fields/Doc";
 import { documentSchema } from "../../fields/documentSchemas";
 import { InkData, InkField, InkTool } from "../../fields/InkField";
 import { makeInterface } from "../../fields/Schema";
 import { Cast, StrCast } from "../../fields/Types";
 import { TraceMobx } from "../../fields/util";
+import { setupMoveUpEvents } from "../../Utils";
 import { CognitiveServices } from "../cognitive_services/CognitiveServices";
 import { InteractionUtils } from "../util/InteractionUtils";
+import { Scripting } from "../util/Scripting";
+import { UndoManager } from "../util/UndoManager";
+import { FormatShapePane } from "./collections/collectionFreeForm/FormatShapePane";
 import { ContextMenu } from "./ContextMenu";
 import { ViewBoxBaseComponent } from "./DocComponent";
 import "./InkingStroke.scss";
 import { FieldView, FieldViewProps } from "./nodes/FieldView";
 import React = require("react");
-import { Scripting } from "../util/Scripting";
-import { Doc } from "../../fields/Doc";
-import FormatShapePane from "./collections/collectionFreeForm/FormatShapePane";
-import { action } from "mobx";
-import { setupMoveUpEvents } from "../../Utils";
-import { undoBatch, UndoManager } from "../util/UndoManager";
-
-
-library.add(faPaintBrush);
 
 type InkDocument = makeInterface<[typeof documentSchema]>;
 const InkDocument = makeInterface(documentSchema);
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 3b10c0e6b..9d6bffa60 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -8,45 +8,49 @@ import "normalize.css";
 import * as React from 'react';
 import * as ReactDOM from 'react-dom';
 import Measure from 'react-measure';
+import * as rp from 'request-promise';
 import { Doc, DocListCast, Field, Opt } from '../../fields/Doc';
 import { Id } from '../../fields/FieldSymbols';
 import { List } from '../../fields/List';
+import { PrefetchProxy } from '../../fields/Proxy';
 import { listSpec } from '../../fields/Schema';
 import { ScriptField } from '../../fields/ScriptField';
-import { BoolCast, Cast, FieldValue, StrCast, NumCast } from '../../fields/Types';
+import { BoolCast, Cast, FieldValue, NumCast, StrCast } from '../../fields/Types';
 import { TraceMobx } from '../../fields/util';
-import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick, Utils, returnEmptyDoclist } from '../../Utils';
-import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
+import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils';
+import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
 import { DocServer } from '../DocServer';
 import { Docs, DocumentOptions } from '../documents/Documents';
 import { DocumentType } from '../documents/DocumentTypes';
+import { Networking } from '../Network';
 import { CurrentUserUtils } from '../util/CurrentUserUtils';
 import { DocumentManager } from '../util/DocumentManager';
-import GroupManager from '../util/GroupManager';
+import { GroupManager } from '../util/GroupManager';
 import { HistoryUtil } from '../util/History';
 import { Hypothesis } from '../util/HypothesisUtils';
+import { LinkManager } from '../util/LinkManager';
 import { Scripting } from '../util/Scripting';
+import { SearchUtil } from '../util/SearchUtil';
 import { SelectionManager } from '../util/SelectionManager';
-import SettingsManager from '../util/SettingsManager';
-import SharingManager from '../util/SharingManager';
+import { SettingsManager } from '../util/SettingsManager';
+import { SharingManager } from '../util/SharingManager';
 import { SnappingManager } from '../util/SnappingManager';
 import { Transform } from '../util/Transform';
 import { TimelineMenu } from './animationtimeline/TimelineMenu';
 import { CollectionDockingView } from './collections/CollectionDockingView';
-import FormatShapePane from "./collections/collectionFreeForm/FormatShapePane";
-import MarqueeOptionsMenu from './collections/collectionFreeForm/MarqueeOptionsMenu';
+import { FormatShapePane } from "./collections/collectionFreeForm/FormatShapePane";
+import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOptionsMenu';
 import { PropertiesView } from './collections/collectionFreeForm/PropertiesView';
 import { CollectionLinearView } from './collections/CollectionLinearView';
-import CollectionMenu from './collections/CollectionMenu';
+import { CollectionMenu } from './collections/CollectionMenu';
 import { CollectionView, CollectionViewType } from './collections/CollectionView';
 import { ContextMenu } from './ContextMenu';
 import { DictationOverlay } from './DictationOverlay';
 import { DocumentDecorations } from './DocumentDecorations';
-import GestureOverlay from './GestureOverlay';
+import { GestureOverlay } from './GestureOverlay';
 import { ANTIMODEMENU_HEIGHT, SEARCH_PANEL_HEIGHT } from './globalCssVariables.scss';
-import KeyManager from './GlobalKeyHandler';
+import { KeyManager } from './GlobalKeyHandler';
 import { LinkMenu } from './linking/LinkMenu';
-import "./MainView.scss";
 import { AudioBox } from './nodes/AudioBox';
 import { DocumentLinksButton } from './nodes/DocumentLinksButton';
 import { DocumentView } from './nodes/DocumentView';
@@ -57,14 +61,10 @@ import { RadialMenu } from './nodes/RadialMenu';
 import { TaskCompletionBox } from './nodes/TaskCompletedBox';
 import { WebBox } from './nodes/WebBox';
 import { OverlayView } from './OverlayView';
-import PDFMenu from './pdf/PDFMenu';
+import { PDFMenu } from './pdf/PDFMenu';
 import { PreviewCursor } from './PreviewCursor';
 import { SearchBox } from './search/SearchBox';
-import { SearchUtil } from '../util/SearchUtil';
-import { Networking } from '../Network';
-import * as rp from 'request-promise';
-import { LinkManager } from '../util/LinkManager';
-import { PrefetchProxy } from '../../fields/Proxy';
+import "./MainView.scss";
 
 @observer
 export class MainView extends React.Component {
@@ -168,13 +168,13 @@ export class MainView extends React.Component {
 
         library.add(fa.faEdit, fa.faTrash, fa.faTrashAlt, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faCalendar,
             fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock,
-            fa.faLock, fa.faLaptopCode, fa.faMale, fa.faCopy, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone, fa.faKeyboard,
-            fa.faQuestion, fa.faTasks, fa.faPalette, fa.faAngleRight, fa.faBell, fa.faCamera, fa.faExpand, fa.faCaretDown, fa.faCaretLeft, fa.faCaretRight,
+            fa.faLock, fa.faLaptopCode, fa.faMale, fa.faCopy, fa.faHandPointLeft, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone, fa.faKeyboard,
+            fa.faQuestion, fa.faTasks, fa.faPalette, fa.faAngleLeft, fa.faAngleRight, fa.faBell, fa.faCamera, fa.faExpand, fa.faCaretDown, fa.faCaretLeft, fa.faCaretRight,
             fa.faCaretSquareDown, fa.faCaretSquareRight, fa.faArrowsAltH, fa.faPlus, fa.faMinus, fa.faTerminal, fa.faToggleOn, fa.faFile, fa.faLocationArrow,
-            fa.faSearch, fa.faFileDownload, fa.faStop, fa.faCalculator, fa.faWindowMaximize, fa.faAddressCard, fa.faQuestionCircle, fa.faArrowLeft,
+            fa.faSearch, fa.faFileDownload, fa.faFileUpload, fa.faStop, fa.faCalculator, fa.faWindowMaximize, fa.faAddressCard, fa.faQuestionCircle, fa.faArrowLeft,
             fa.faArrowRight, fa.faArrowDown, fa.faArrowUp, fa.faBolt, fa.faBullseye, fa.faCaretUp, fa.faCat, fa.faCheck, fa.faChevronRight, fa.faClipboard,
             fa.faClone, fa.faCloudUploadAlt, fa.faCommentAlt, fa.faCompressArrowsAlt, fa.faCut, fa.faEllipsisV, fa.faEraser, fa.faExclamation, fa.faFileAlt,
-            fa.faFileAudio, fa.faFilePdf, fa.faFilm, fa.faFilter, fa.faFont, fa.faGlobeAsia, fa.faHighlighter, fa.faLongArrowAltRight, fa.faMousePointer,
+            fa.faFileAudio, fa.faFilePdf, fa.faFilm, fa.faFilter, fa.faFont, fa.faGlobeAmericas, fa.faGlobeAsia, fa.faHighlighter, fa.faLongArrowAltRight, fa.faMousePointer,
             fa.faMusic, fa.faObjectGroup, fa.faPause, fa.faPen, fa.faPenNib, fa.faPhone, fa.faPlay, fa.faPortrait, fa.faRedoAlt, fa.faStamp, fa.faStickyNote,
             fa.faTimesCircle, fa.faThumbtack, fa.faTree, fa.faTv, fa.faUndoAlt, fa.faVideo, fa.faAsterisk, fa.faBrain, fa.faImage, fa.faPaintBrush, fa.faTimes,
             fa.faEye, fa.faArrowsAlt, fa.faQuoteLeft, fa.faSortAmountDown, fa.faAlignLeft, fa.faAlignCenter, fa.faAlignRight, fa.faHeading, fa.faRulerCombined,
@@ -183,7 +183,10 @@ export class MainView extends React.Component {
             fa.faDesktop, fa.faTrashRestore, fa.faUsers, fa.faWrench, fa.faCog, fa.faMap, fa.faBellSlash, fa.faExpandAlt, fa.faArchive, fa.faBezierCurve, fa.faCircle,
             fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, faBuffer, fa.faExpand, fa.faUndo, fa.faSlidersH, fa.faAngleDoubleLeft, fa.faAngleUp,
             fa.faAngleDown, fa.faPlayCircle, fa.faClock, fa.faRocket, fa.faExchangeAlt, faBuffer, fa.faHashtag, fa.faAlignJustify, fa.faCheckSquare, fa.faListUl,
-            fa.faWindowMinimize, fa.faWindowRestore, fa.faTextWidth, fa.faClosedCaptioning);
+            fa.faWindowMinimize, fa.faWindowRestore, fa.faTextWidth, fa.faTextHeight, fa.faClosedCaptioning, fa.faInfoCircle, fa.faTag, fa.faSyncAlt, fa.faPhotoVideo,
+            fa.faArrowAltCircleDown, fa.faArrowAltCircleUp, fa.faArrowAltCircleLeft, fa.faArrowAltCircleRight, fa.faStopCircle, fa.faCheckCircle, fa.faGripVertical,
+            fa.faSortUp, fa.faSortDown, fa.faTable, fa.faTh, fa.faThList, fa.faProjectDiagram, fa.faSignature, fa.faColumns, fa.faChevronCircleUp, fa.faUpload,
+            fa.faBraille, fa.faChalkboard, fa.faPencilAlt, fa.faEyeSlash, fa.faSmile, fa.faIndent, fa.faOutdent, fa.faChartBar, fa.faBan, fa.faPhoneSlash);
         this.initEventListeners();
         this.initAuthenticationRouters();
     }
diff --git a/src/client/views/MainViewModal.tsx b/src/client/views/MainViewModal.tsx
index 19387f619..34e0ff126 100644
--- a/src/client/views/MainViewModal.tsx
+++ b/src/client/views/MainViewModal.tsx
@@ -14,7 +14,7 @@ export interface MainViewOverlayProps {
 }
 
 @observer
-export default class MainViewModal extends React.Component<MainViewOverlayProps> {
+export class MainViewModal extends React.Component<MainViewOverlayProps> {
 
     render() {
         const p = this.props;
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 9839222ec..4abb2cb7a 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -1,52 +1,39 @@
-import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faArrowAltCircleDown, faArrowAltCircleRight, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faPhotoVideo, faShare, faStopCircle, faSyncAlt, faTag, faTimes } from '@fortawesome/free-solid-svg-icons';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { Tooltip } from '@material-ui/core';
 import { action, computed, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, DataSym, AclEdit, AclAdmin } from "../../fields/Doc";
+import { AclAdmin, AclEdit, DataSym, Doc } from "../../fields/Doc";
+import { InkField } from '../../fields/InkField';
 import { RichTextField } from '../../fields/RichTextField';
-import { Cast, NumCast, BoolCast } from "../../fields/Types";
-import { emptyFunction, setupMoveUpEvents, Utils } from "../../Utils";
-import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
+import { Cast, NumCast } from "../../fields/Types";
+import { ImageField } from '../../fields/URLField';
+import { GetEffectiveAcl } from '../../fields/util';
+import { emptyFunction, setupMoveUpEvents } from "../../Utils";
+import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
 import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils';
+import { GooglePhotos } from '../apis/google_docs/GooglePhotosClientUtils';
 import { Docs, DocUtils } from '../documents/Documents';
+import { DocumentType } from '../documents/DocumentTypes';
 import { DragManager } from '../util/DragManager';
+import { SelectionManager } from '../util/SelectionManager';
+import { SharingManager } from '../util/SharingManager';
+import { undoBatch } from '../util/UndoManager';
 import { CollectionDockingView, DockedFrameRenderer } from './collections/CollectionDockingView';
 import { ParentDocSelector } from './collections/ParentDocumentSelector';
 import './collections/ParentDocumentSelector.scss';
-import './PropertiesButtons.scss';
 import { MetadataEntryMenu } from './MetadataEntryMenu';
 import { DocumentView } from './nodes/DocumentView';
 import { GoogleRef } from "./nodes/formattedText/FormattedTextBox";
+import { PresBox } from './nodes/PresBox';
+import './PropertiesButtons.scss';
 import { TemplateMenu } from "./TemplateMenu";
 import { Template, Templates } from "./Templates";
 import React = require("react");
-import { Tooltip } from '@material-ui/core';
-import { SelectionManager } from '../util/SelectionManager';
-import SharingManager from '../util/SharingManager';
-import { GooglePhotos } from '../apis/google_docs/GooglePhotosClientUtils';
-import { ImageField } from '../../fields/URLField';
-import { undoBatch, UndoManager } from '../util/UndoManager';
-import { DocumentType } from '../documents/DocumentTypes';
-import { InkField } from '../../fields/InkField';
-import { PresBox } from './nodes/PresBox';
-import { GetEffectiveAcl } from '../../fields/util';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
 
-library.add(faLink);
-library.add(faTag);
-library.add(faTimes);
-library.add(faArrowAltCircleDown);
-library.add(faArrowAltCircleUp);
-library.add(faArrowAltCircleRight);
-library.add(faStopCircle);
-library.add(faCheckCircle);
-library.add(faCloudUploadAlt);
-library.add(faSyncAlt);
-library.add(faShare);
-library.add(faPhotoVideo);
 
 const cloud: IconProp = "cloud-upload-alt";
 const fetch: IconProp = "sync-alt";
diff --git a/src/client/views/ScriptingRepl.tsx b/src/client/views/ScriptingRepl.tsx
index db087fb23..c598b2861 100644
--- a/src/client/views/ScriptingRepl.tsx
+++ b/src/client/views/ScriptingRepl.tsx
@@ -1,17 +1,12 @@
-import * as React from 'react';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, observable } from 'mobx';
 import { observer } from 'mobx-react';
-import { observable, action } from 'mobx';
-import './ScriptingRepl.scss';
-import { Scripting, CompileScript, ts, Transformer } from '../util/Scripting';
+import * as React from 'react';
 import { DocumentManager } from '../util/DocumentManager';
-import { OverlayView } from './OverlayView';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faCaretDown, faCaretRight } from '@fortawesome/free-solid-svg-icons';
+import { CompileScript, Scripting, Transformer, ts } from '../util/Scripting';
 import { DocumentIconContainer } from './nodes/DocumentIcon';
-
-library.add(faCaretDown);
-library.add(faCaretRight);
+import { OverlayView } from './OverlayView';
+import './ScriptingRepl.scss';
 
 @observer
 export class ScriptingObjectDisplay extends React.Component<{ scrollToBottom: () => void, value: { [key: string]: any }, name?: string }> {
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index f1959460c..cc2220f62 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -791,7 +791,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
         observer.observe(this.props.glContainer._element[0]);
         this.props.glContainer.layoutManager.on("activeContentItemChanged", this.onActiveContentItemChanged);
         this.props.glContainer.tab?.isActive && this.onActiveContentItemChanged();
-        this._tabReaction = reaction(() => ({ views: SelectionManager.SelectedDocuments(), color: color() }), () => updateTabColor(), { fireImmediately: true });
+        this._tabReaction = reaction(() => ({ views: SelectionManager.SelectedDocuments(), color: color() }), updateTabColor, { fireImmediately: true });
     }
 
     componentWillUnmount() {
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 00415dab1..d086c8b1f 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -22,18 +22,18 @@ import { DragManager } from "../../util/DragManager";
 import { Scripting } from "../../util/Scripting";
 import { SelectionManager } from "../../util/SelectionManager";
 import { undoBatch } from "../../util/UndoManager";
-import AntimodeMenu, { AntimodeMenuProps } from "../AntimodeMenu";
+import { AntimodeMenu, AntimodeMenuProps } from "../AntimodeMenu";
 import { EditableView } from "../EditableView";
-import GestureOverlay from "../GestureOverlay";
+import { GestureOverlay } from "../GestureOverlay";
 import { ActiveFillColor, ActiveInkColor, SetActiveArrowEnd, SetActiveArrowStart, SetActiveBezierApprox, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth } from "../InkingStroke";
 import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
 import { DocumentView } from "../nodes/DocumentView";
-import RichTextMenu from "../nodes/formattedText/RichTextMenu";
+import { RichTextMenu } from "../nodes/formattedText/RichTextMenu";
 import "./CollectionMenu.scss";
 import { CollectionViewType, COLLECTION_BORDER_WIDTH } from "./CollectionView";
 
 @observer
-export default class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> {
+export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> {
     static Instance: CollectionMenu;
 
     @observable SelectedCollection: DocumentView | undefined;
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index e37644f2f..ac789ab48 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -1,45 +1,41 @@
 import React = require("react");
-import { action, observable, trace, computed, runInAction } from "mobx";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
+import DatePicker from "react-datepicker";
+import "react-datepicker/dist/react-datepicker.css";
 import { CellInfo } from "react-table";
 import "react-table/react-table.css";
-import { emptyFunction, returnFalse, returnZero, returnOne, returnEmptyFilter, Utils, emptyPath, returnEmptyDoclist } from "../../../Utils";
+import { DateField } from "../../../fields/DateField";
 import { Doc, DocListCast, Field, Opt } from "../../../fields/Doc";
 import { Id } from "../../../fields/FieldSymbols";
+import { List } from "../../../fields/List";
+import { RichTextField } from "../../../fields/RichTextField";
+import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
+import { ComputedField } from "../../../fields/ScriptField";
+import { BoolCast, Cast, DateCast, FieldValue, NumCast, StrCast } from "../../../fields/Types";
+import { ImageField } from "../../../fields/URLField";
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnZero, Utils } from "../../../Utils";
+import { Docs } from "../../documents/Documents";
+import { DocumentType } from "../../documents/DocumentTypes";
+import { DocumentManager } from "../../util/DocumentManager";
+import { DragManager, SetupDrag } from "../../util/DragManager";
 import { KeyCodes } from "../../util/KeyCodes";
-import { SetupDrag, DragManager } from "../../util/DragManager";
 import { CompileScript } from "../../util/Scripting";
+import { SearchUtil } from "../../util/SearchUtil";
+import { SnappingManager } from "../../util/SnappingManager";
 import { Transform } from "../../util/Transform";
-import { MAX_ROW_HEIGHT, COLLECTION_BORDER_WIDTH } from '../globalCssVariables.scss';
+import { undoBatch } from "../../util/UndoManager";
 import '../DocumentDecorations.scss';
 import { EditableView } from "../EditableView";
-import { FieldView, FieldViewProps } from "../nodes/FieldView";
-import "./CollectionSchemaView.scss";
-import { CollectionView, Flyout } from "./CollectionView";
-import { NumCast, StrCast, BoolCast, FieldValue, Cast, DateCast } from "../../../fields/Types";
-import { Docs } from "../../documents/Documents";
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faExpand } from '@fortawesome/free-solid-svg-icons';
-import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
-import { undoBatch } from "../../util/UndoManager";
-import { SnappingManager } from "../../util/SnappingManager";
-import { ComputedField } from "../../../fields/ScriptField";
-import { ImageField } from "../../../fields/URLField";
-import { List } from "../../../fields/List";
-import { OverlayView } from "../OverlayView";
+import { COLLECTION_BORDER_WIDTH, MAX_ROW_HEIGHT } from '../globalCssVariables.scss';
 import { DocumentIconContainer } from "../nodes/DocumentIcon";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import { DateField } from "../../../fields/DateField";
-import { RichTextField } from "../../../fields/RichTextField";
-import { DocumentManager } from "../../util/DocumentManager";
-import { SearchUtil } from "../../util/SearchUtil";
-import { DocumentType } from "../../documents/DocumentTypes";
+import { FieldViewProps } from "../nodes/FieldView";
+import { OverlayView } from "../OverlayView";
+import "./CollectionSchemaView.scss";
+import { CollectionView } from "./CollectionView";
 const path = require('path');
 
-library.add(faExpand);
-
 export interface CellProps {
     row: number;
     col: number;
@@ -287,12 +283,6 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
         if (this.props.isFocused && this.props.isEditable) className += " focused";
         if (this.props.isFocused && !this.props.isEditable) className += " inactive";
 
-
-        // let docExpander = (
-        //     <div className="collectionSchemaView-cellContents-docExpander" onPointerDown={this.expandDoc} >
-        //         <FontAwesomeIcon icon="expand" size="sm" />
-        //     </div>
-        // );   
         const positions = [];
         let cfield = props.Document[props.fieldKey];
         this.type = props.fieldKey;
diff --git a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
index 4754adc90..a3475b481 100644
--- a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
+++ b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
@@ -1,6 +1,5 @@
 import React = require("react");
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faGripVertical, faTrash } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { action } from "mobx";
 import { ReactTableDefaults, RowInfo, TableCellRenderer } from "react-table";
 import { Doc } from "../../../fields/Doc";
@@ -13,9 +12,6 @@ import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
 import { ContextMenu } from "../ContextMenu";
 import "./CollectionSchemaView.scss";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-
-library.add(faGripVertical, faTrash);
 
 export interface MovableColumnProps {
     columnRenderer: TableCellRenderer;
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index a78061da6..10c33fc4d 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -1,6 +1,4 @@
 import React = require("react");
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faCog, faPlus, faSortDown, faSortUp, faTable } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, observable, untracked } from "mobx";
 import { observer } from "mobx-react";
@@ -9,26 +7,23 @@ import { Resize } from "react-table";
 import "react-table/react-table.css";
 import { Doc, Opt } from "../../../fields/Doc";
 import { List } from "../../../fields/List";
-import { listSpec, makeInterface, emptySchema } from "../../../fields/Schema";
+import { listSpec } from "../../../fields/Schema";
 import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField";
-import { Cast, NumCast, BoolCast } from "../../../fields/Types";
+import { Cast, NumCast } from "../../../fields/Types";
 import { TraceMobx } from "../../../fields/util";
 import { emptyFunction, returnFalse, returnOne, returnZero, setupMoveUpEvents } from "../../../Utils";
+import { SelectionManager } from "../../util/SelectionManager";
 import { SnappingManager } from "../../util/SnappingManager";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
 import { COLLECTION_BORDER_WIDTH } from '../../views/globalCssVariables.scss';
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
 import '../DocumentDecorations.scss';
 import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
 import "./CollectionSchemaView.scss";
 import { CollectionSubView } from "./CollectionSubView";
 import { SchemaTable } from "./SchemaTable";
-import { SelectionManager } from "../../util/SelectionManager";
-import { ContextMenu } from "../ContextMenu";
-import { ContextMenuProps } from "../ContextMenuItem";
-
-library.add(faCog, faPlus, faSortUp, faSortDown);
-library.add(faTable);
 // bcz: need to add drag and drop of rows and columns.  This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657
 
 export enum ColumnType {
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 0a206a6c6..12b7d742b 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -1,35 +1,31 @@
 import React = require("react");
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faPalette } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, observable, runInAction, computed } from "mobx";
+import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
 import { Doc, DocListCast } from "../../../fields/Doc";
 import { RichTextField } from "../../../fields/RichTextField";
+import { listSpec } from "../../../fields/Schema";
 import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField";
 import { ScriptField } from "../../../fields/ScriptField";
-import { NumCast, StrCast, Cast } from "../../../fields/Types";
+import { Cast, NumCast, StrCast } from "../../../fields/Types";
 import { ImageField } from "../../../fields/URLField";
 import { TraceMobx } from "../../../fields/util";
+import { emptyFunction, setupMoveUpEvents } from "../../../Utils";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { DragManager } from "../../util/DragManager";
+import { SnappingManager } from "../../util/SnappingManager";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
 import { ContextMenu } from "../ContextMenu";
 import { ContextMenuProps } from "../ContextMenuItem";
 import { EditableView } from "../EditableView";
 import { CollectionStackingView } from "./CollectionStackingView";
-import { setupMoveUpEvents, emptyFunction } from "../../../Utils";
 import "./CollectionStackingView.scss";
-import { listSpec } from "../../../fields/Schema";
-import { SnappingManager } from "../../util/SnappingManager";
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
 
-library.add(faPalette);
-
 interface CSVFieldColumnProps {
     cols: () => number;
     headings: () => object[];
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 4fdf1411d..97336798b 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,6 +1,3 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faEdit, faEye } from '@fortawesome/free-regular-svg-icons';
-import { faColumns, faCopy, faEllipsisV, faFingerprint, faGlobeAmericas, faImage, faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { action, computed, observable } from 'mobx';
 import { observer } from "mobx-react";
@@ -53,8 +50,6 @@ export const Flyout = higflyout.default;
 export const COLLECTION_BORDER_WIDTH = 2;
 const path = require('path');
 
-library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faGlobeAmericas, faEllipsisV, faImage, faEye as any, faCopy);
-
 export enum CollectionViewType {
     Invalid = "invalid",
     Freeform = "freeform",
@@ -528,7 +523,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
             <div className="collectionTimeView-addFacet" style={{ width: `${this.facetWidth()}px` }} onPointerDown={e => e.stopPropagation()}>
                 <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}>
                     <div className="collectionTimeView-button">
-                        <FontAwesomeIcon icon={faEdit} size={"lg"} />
+                        <FontAwesomeIcon icon={"edit"} size={"lg"} />
                         <span className="collectionTimeView-span">Facet Filters</span>
                     </div>
                 </Flyout>
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index 149d4927b..a6de32145 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -1,27 +1,21 @@
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { Tooltip } from "@material-ui/core";
+import { computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
+import { observer } from "mobx-react";
 import * as React from "react";
-import './ParentDocumentSelector.scss';
 import { Doc } from "../../../fields/Doc";
-import { observer } from "mobx-react";
-import { observable, action, runInAction, trace, computed, reaction, IReactionDisposer } from "mobx";
 import { Id } from "../../../fields/FieldSymbols";
+import { NumCast } from "../../../fields/Types";
 import { SearchUtil } from "../../util/SearchUtil";
-import { CollectionDockingView } from "./CollectionDockingView";
-import { NumCast, StrCast } from "../../../fields/Types";
-import { CollectionViewType } from "./CollectionView";
 import { DocumentButtonBar } from "../DocumentButtonBar";
-import { DocumentManager } from "../../util/DocumentManager";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faCog, faChevronCircleUp } from "@fortawesome/free-solid-svg-icons";
-import { library } from "@fortawesome/fontawesome-svg-core";
 import { DocumentView } from "../nodes/DocumentView";
-import { SelectionManager } from "../../util/SelectionManager";
-import { Tooltip } from "@material-ui/core";
+import { CollectionDockingView } from "./CollectionDockingView";
+import { CollectionViewType } from "./CollectionView";
+import './ParentDocumentSelector.scss';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
 
-library.add(faCog);
-
 type SelectorProps = {
     Document: Doc,
     Stack?: any,
@@ -93,7 +87,7 @@ export class ParentDocSelector extends React.Component<SelectorProps> {
         return <div title="Show Contexts" onPointerDown={e => e.stopPropagation()} className="parentDocumentSelector-linkFlyout">
             <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}>
                 <span className="parentDocumentSelector-button" >
-                    <FontAwesomeIcon icon={faChevronCircleUp} size={"lg"} />
+                    <FontAwesomeIcon icon={"chevron-circle-up"} size={"lg"} />
                 </span>
             </Flyout>
         </div>;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 02ff3e78c..d64b49c4d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,7 +1,4 @@
-import { library } from "@fortawesome/fontawesome-svg-core";
-import { faEye } from "@fortawesome/free-regular-svg-icons";
-import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons";
-import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, trace } from "mobx";
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { computedFn } from "mobx-utils";
 import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../../fields/Doc";
@@ -15,7 +12,7 @@ import { ScriptField } from "../../../../fields/ScriptField";
 import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types";
 import { TraceMobx } from "../../../../fields/util";
 import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
-import { aggregateBounds, intersectRect, returnFalse, returnOne, returnZero, Utils, setupMoveUpEvents } from "../../../../Utils";
+import { aggregateBounds, intersectRect, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from "../../../../Utils";
 import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
 import { DocServer } from "../../../DocServer";
 import { Docs, DocUtils } from "../../../documents/Documents";
@@ -24,10 +21,12 @@ import { DocumentManager } from "../../../util/DocumentManager";
 import { DragManager, dropActionType } from "../../../util/DragManager";
 import { HistoryUtil } from "../../../util/History";
 import { InteractionUtils } from "../../../util/InteractionUtils";
+import { LinkManager } from "../../../util/LinkManager";
+import { SearchUtil } from "../../../util/SearchUtil";
 import { SelectionManager } from "../../../util/SelectionManager";
 import { SnappingManager } from "../../../util/SnappingManager";
 import { Transform } from "../../../util/Transform";
-import { undoBatch, UndoManager } from "../../../util/UndoManager";
+import { undoBatch } from "../../../util/UndoManager";
 import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss";
 import { Timeline } from "../../animationtimeline/Timeline";
 import { ContextMenu } from "../../ContextMenu";
@@ -37,20 +36,16 @@ import { DocumentLinksButton } from "../../nodes/DocumentLinksButton";
 import { DocumentViewProps } from "../../nodes/DocumentView";
 import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
 import { pageSchema } from "../../nodes/ImageBox";
+import { PresBox } from "../../nodes/PresBox";
 import { CollectionDockingView } from "../CollectionDockingView";
 import { CollectionSubView } from "../CollectionSubView";
 import { CollectionViewType } from "../CollectionView";
 import { computePivotLayout, computerPassLayout, computerStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from "./CollectionFreeFormLayoutEngines";
 import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors";
 import "./CollectionFreeFormView.scss";
-import MarqueeOptionsMenu from "./MarqueeOptionsMenu";
+import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu";
 import { MarqueeView } from "./MarqueeView";
 import React = require("react");
-import { PresBox } from "../../nodes/PresBox";
-import { SearchUtil } from "../../../util/SearchUtil";
-import { LinkManager } from "../../../util/LinkManager";
-
-library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload);
 
 export const panZoomSchema = createSchema({
     _panX: "number",
@@ -608,7 +603,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
     pan = (e: PointerEvent | React.Touch | { clientX: number, clientY: number }): void => {
         // bcz: theres should be a better way of doing these than referencing these static instances directly
         MarqueeOptionsMenu.Instance?.fadeOut(true);// I think it makes sense for the marquee menu to go away when panned. -syip2
-        // PDFMenu.Instance.fadeOut(true); (commented out for mobile)
 
         const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
         this.setPan((this.Document._panX || 0) - dx, (this.Document._panY || 0) - dy, undefined, true);
@@ -1261,7 +1255,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         const options = ContextMenu.Instance.findByDescription("Options...");
         const optionItems = options && "subitems" in options ? options.subitems : [];
         !this.props.isAnnotationOverlay && !Doc.UserDoc().noviceMode &&
-            optionItems.push({ description: (this.showTimeline ? "Close" : "Open") + " Animation Timeline", event: action(() => this.showTimeline = !this.showTimeline), icon: faEye });
+            optionItems.push({ description: (this.showTimeline ? "Close" : "Open") + " Animation Timeline", event: action(() => this.showTimeline = !this.showTimeline), icon: "eye" });
         this.props.ContainingCollectionView &&
             optionItems.push({ description: "Undo Collection", event: this.promoteCollection, icon: "table" });
         optionItems.push({ description: this.layoutDoc._lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: this.layoutDoc._lockedTransform ? "unlock" : "lock" });
diff --git a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
index a7f44bbbf..1d3604d7f 100644
--- a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
+++ b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
@@ -9,13 +9,13 @@ import { InkField } from "../../../../fields/InkField";
 import { BoolCast, Cast, NumCast } from "../../../../fields/Types";
 import { DocumentType } from "../../../documents/DocumentTypes";
 import { SelectionManager } from "../../../util/SelectionManager";
-import AntimodeMenu, { AntimodeMenuProps } from "../../AntimodeMenu";
+import { AntimodeMenu, AntimodeMenuProps } from "../../AntimodeMenu";
 import "./FormatShapePane.scss";
 import { undoBatch } from "../../../util/UndoManager";
 import { ColorState, SketchPicker } from 'react-color';
 
 @observer
-export default class FormatShapePane extends AntimodeMenu<AntimodeMenuProps> {
+export class FormatShapePane extends AntimodeMenu<AntimodeMenuProps> {
     static Instance: FormatShapePane;
 
     private _lastFill = "#D0021B";
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
index 5e292a833..46298ec6f 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
@@ -1,13 +1,12 @@
 import React = require("react");
-import AntimodeMenu, { AntimodeMenuProps } from "../../AntimodeMenu";
-import { observer } from "mobx-react";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { unimplementedFunction } from "../../../../Utils";
-import { undoBatch } from "../../../util/UndoManager";
 import { Tooltip } from "@material-ui/core";
+import { observer } from "mobx-react";
+import { unimplementedFunction } from "../../../../Utils";
+import { AntimodeMenu, AntimodeMenuProps } from "../../AntimodeMenu";
 
 @observer
-export default class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> {
+export class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> {
     static Instance: MarqueeOptionsMenu;
 
     public createCollection: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction;
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 7e02673f4..d161f49f7 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,29 +1,28 @@
 import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, Opt, DocListCast, DataSym, AclEdit, AclAddonly, AclAdmin } from "../../../../fields/Doc";
-import { GetEffectiveAcl } from "../../../../fields/util";
+import { AclAddonly, AclAdmin, AclEdit, DataSym, Doc, DocListCast, Opt } from "../../../../fields/Doc";
 import { InkData, InkField, InkTool } from "../../../../fields/InkField";
 import { List } from "../../../../fields/List";
 import { RichTextField } from "../../../../fields/RichTextField";
 import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
 import { Cast, FieldValue, NumCast, StrCast } from "../../../../fields/Types";
+import { GetEffectiveAcl } from "../../../../fields/util";
 import { Utils } from "../../../../Utils";
 import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
 import { Docs, DocumentOptions, DocUtils } from "../../../documents/Documents";
+import { DocumentManager } from "../../../util/DocumentManager";
 import { SelectionManager } from "../../../util/SelectionManager";
 import { Transform } from "../../../util/Transform";
 import { undoBatch, UndoManager } from "../../../util/UndoManager";
 import { ContextMenu } from "../../ContextMenu";
 import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
 import { PreviewCursor } from "../../PreviewCursor";
+import { CollectionDockingView } from "../CollectionDockingView";
 import { SubCollectionViewProps } from "../CollectionSubView";
 import { CollectionView } from "../CollectionView";
-import MarqueeOptionsMenu from "./MarqueeOptionsMenu";
+import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu";
 import "./MarqueeView.scss";
 import React = require("react");
-import { ContextMenuItem } from "../../ContextMenuItem";
-import { CollectionDockingView } from "../CollectionDockingView";
-import { DocumentManager } from "../../../util/DocumentManager";
 
 interface MarqueeViewProps {
     getContainerTransform: () => Transform;
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index e128f6aab..1bfc6bdce 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -1,40 +1,35 @@
 import React = require("react");
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { Checkbox, Tooltip } from "@material-ui/core";
+import { action, computed, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
-import "./PropertiesView.scss";
-import { observable, action, computed, runInAction } from "mobx";
-import { Doc, Field, WidthSym, HeightSym, AclSym, AclPrivate, AclReadonly, AclAddonly, AclEdit, AclAdmin, Opt, DocCastAsync, DataSym } from "../../../../fields/Doc";
+import { ColorState, SketchPicker } from "react-color";
+import { AclAddonly, AclAdmin, AclEdit, AclPrivate, AclReadonly, AclSym, DataSym, Doc, Field, HeightSym, WidthSym } from "../../../../fields/Doc";
+import { Id } from "../../../../fields/FieldSymbols";
+import { InkField } from "../../../../fields/InkField";
 import { ComputedField } from "../../../../fields/ScriptField";
-import { EditableView } from "../../EditableView";
-import { KeyValueBox } from "../../nodes/KeyValueBox";
 import { Cast, NumCast, StrCast } from "../../../../fields/Types";
-import { ContentFittingDocumentView } from "../../nodes/ContentFittingDocumentView";
-import { returnFalse, returnOne, emptyFunction, emptyPath, returnTrue, returnZero, returnEmptyFilter, Utils, returnEmptyDoclist } from "../../../../Utils";
-import { Id } from "../../../../fields/FieldSymbols";
-import { Transform } from "../../../util/Transform";
-import { PropertiesButtons } from "../../PropertiesButtons";
-import { SelectionManager } from "../../../util/SelectionManager";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { Tooltip, Checkbox } from "@material-ui/core";
-import SharingManager from "../../../util/SharingManager";
+import { GetEffectiveAcl, SharingPermissions } from "../../../../fields/util";
+import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnZero } from "../../../../Utils";
 import { DocumentType } from "../../../documents/DocumentTypes";
-import { SharingPermissions, GetEffectiveAcl } from "../../../../fields/util";
-import { InkField } from "../../../../fields/InkField";
+import { DocumentManager } from "../../../util/DocumentManager";
+import { SelectionManager } from "../../../util/SelectionManager";
+import { SharingManager } from "../../../util/SharingManager";
+import { Transform } from "../../../util/Transform";
 import { undoBatch, UndoManager } from "../../../util/UndoManager";
-import { ColorState, SketchPicker } from "react-color";
-import "./FormatShapePane.scss";
+import { EditableView } from "../../EditableView";
+import { ContentFittingDocumentView } from "../../nodes/ContentFittingDocumentView";
+import { KeyValueBox } from "../../nodes/KeyValueBox";
 import { PresBox } from "../../nodes/PresBox";
-import { DocumentManager } from "../../../util/DocumentManager";
-import FormatShapePane from "./FormatShapePane";
+import { PropertiesButtons } from "../../PropertiesButtons";
+import { FormatShapePane } from "./FormatShapePane";
+import "./FormatShapePane.scss";
+import "./PropertiesView.scss";
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
 const _global = (window /* browser */ || global /* node */) as any;
 
-// import * as fa from '@fortawesome/free-solid-svg-icons';
-// import { library } from "@fortawesome/fontawesome-svg-core";
-
-// library.add(fa.faPlus, fa.faMinus, fa.faCog);
-
 interface PropertiesViewProps {
     width: number;
     height: number;
@@ -527,7 +522,12 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             <div className="inputBox-title"> {title} </div>
             <input className="inputBox-input"
                 type="text" value={value}
-                onChange={e => setter(e.target.value)} />
+                onChange={e => {
+                    setter(e.target.value);
+                }}
+                onKeyPress={e => {
+                    e.stopPropagation();
+                }} />
             <div className="inputBox-button">
                 <div className="inputBox-button-up" key="up2"
                     onPointerDown={undoBatch(action(() => this.upDownButtons("up", key)))} >
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index ed64bde32..11a905fb6 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -1,5 +1,3 @@
-import { library } from "@fortawesome/fontawesome-svg-core";
-import { faArrowLeft, faCog, faEllipsisV, faExchangeAlt, faPlus, faTable, faTimes, faTrash } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { Tooltip } from "@material-ui/core";
 import { action, computed, observable } from "mobx";
@@ -12,9 +10,6 @@ import { undoBatch } from "../../util/UndoManager";
 import './LinkEditor.scss';
 import React = require("react");
 
-library.add(faArrowLeft, faEllipsisV, faTable, faTrash, faCog, faExchangeAlt, faTimes, faPlus);
-
-
 interface GroupTypesDropdownProps {
     groupType: string;
     setGroupType: (group: string) => void;
diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx
index 519b78add..31d08edae 100644
--- a/src/client/views/linking/LinkMenu.tsx
+++ b/src/client/views/linking/LinkMenu.tsx
@@ -1,18 +1,14 @@
-import { action, observable, computed } from "mobx";
+import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
-import { DocumentView } from "../nodes/DocumentView";
-import { LinkEditor } from "./LinkEditor";
-import './LinkMenu.scss';
-import React = require("react");
 import { Doc } from "../../../fields/Doc";
 import { LinkManager } from "../../util/LinkManager";
-import { LinkMenuGroup } from "./LinkMenuGroup";
-import { faTrash } from '@fortawesome/free-solid-svg-icons';
-import { library } from "@fortawesome/fontawesome-svg-core";
 import { DocumentLinksButton } from "../nodes/DocumentLinksButton";
+import { DocumentView } from "../nodes/DocumentView";
 import { LinkDocPreview } from "../nodes/LinkDocPreview";
-
-library.add(faTrash);
+import { LinkEditor } from "./LinkEditor";
+import './LinkMenu.scss';
+import { LinkMenuGroup } from "./LinkMenuGroup";
+import React = require("react");
 
 interface Props {
     docView: DocumentView;
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 21c666a4d..a77122456 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -1,27 +1,23 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faArrowRight, faChevronDown, faChevronUp, faEdit, faEye, faTimes, faPencilAlt, faEyeSlash } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon, FontAwesomeIconProps } from '@fortawesome/react-fontawesome';
+import { Tooltip } from '@material-ui/core';
 import { action, observable, runInAction } from 'mobx';
 import { observer } from "mobx-react";
-import { Doc, DocListCast, Opt } from '../../../fields/Doc';
+import { Doc, DocListCast } from '../../../fields/Doc';
 import { Cast, StrCast } from '../../../fields/Types';
+import { WebField } from '../../../fields/URLField';
+import { emptyFunction, setupMoveUpEvents } from '../../../Utils';
+import { DocumentType } from '../../documents/DocumentTypes';
+import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager } from '../../util/DragManager';
+import { Hypothesis } from '../../util/HypothesisUtils';
 import { LinkManager } from '../../util/LinkManager';
+import { undoBatch } from '../../util/UndoManager';
 import { ContextMenu } from '../ContextMenu';
-import './LinkMenuItem.scss';
-import React = require("react");
-import { DocumentManager } from '../../util/DocumentManager';
-import { setupMoveUpEvents, emptyFunction, Utils, simulateMouseClick } from '../../../Utils';
-import { DocumentView } from '../nodes/DocumentView';
 import { DocumentLinksButton } from '../nodes/DocumentLinksButton';
+import { DocumentView } from '../nodes/DocumentView';
 import { LinkDocPreview } from '../nodes/LinkDocPreview';
-import { Hypothesis } from '../../util/HypothesisUtils';
-import { Id } from '../../../fields/FieldSymbols';
-import { Tooltip } from '@material-ui/core';
-import { DocumentType } from '../../documents/DocumentTypes';
-import { undoBatch } from '../../util/UndoManager';
-import { WebField } from '../../../fields/URLField';
-library.add(faEye, faEdit, faTimes, faArrowRight, faChevronDown, faChevronUp, faPencilAlt, faEyeSlash);
+import './LinkMenuItem.scss';
+import React = require("react");
 
 
 interface LinkMenuItemProps {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index db6d30aac..80d83c3cb 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -21,7 +21,7 @@ import { InteractionUtils } from '../../util/InteractionUtils';
 import { LinkManager } from '../../util/LinkManager';
 import { Scripting } from '../../util/Scripting';
 import { SelectionManager } from "../../util/SelectionManager";
-import SharingManager from '../../util/SharingManager';
+import { SharingManager } from '../../util/SharingManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from "../../util/Transform";
 import { undoBatch, UndoManager } from "../../util/UndoManager";
diff --git a/src/client/views/nodes/FaceRectangles.tsx b/src/client/views/nodes/FaceRectangles.tsx
index 92ca276cb..0d1e063af 100644
--- a/src/client/views/nodes/FaceRectangles.tsx
+++ b/src/client/views/nodes/FaceRectangles.tsx
@@ -17,7 +17,7 @@ export interface RectangleTemplate {
 }
 
 @observer
-export default class FaceRectangles extends React.Component<FaceRectanglesProps> {
+export class FaceRectangles extends React.Component<FaceRectanglesProps> {
 
     render() {
         const faces = DocListCast(this.props.document.faces);
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 5f31f8c8d..410033197 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -1,6 +1,3 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faEye } from '@fortawesome/free-regular-svg-icons';
-import { faAsterisk, faBrain, faFileAudio, faImage, faPaintBrush } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, observable, runInAction } from 'mobx';
 import { observer } from "mobx-react";
@@ -14,7 +11,8 @@ import { ComputedField } from '../../../fields/ScriptField';
 import { Cast, NumCast, StrCast } from '../../../fields/Types';
 import { AudioField, ImageField } from '../../../fields/URLField';
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnOne, Utils, returnZero } from '../../../Utils';
+import { emptyFunction, returnOne, returnZero, Utils } from '../../../Utils';
+import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices';
 import { Docs } from '../../documents/Documents';
 import { Networking } from '../../Network';
@@ -24,20 +22,15 @@ import { ContextMenu } from "../../views/ContextMenu";
 import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
 import { ContextMenuProps } from '../ContextMenuItem';
 import { ViewBoxAnnotatableComponent } from '../DocComponent';
-import FaceRectangles from './FaceRectangles';
+import { FaceRectangles } from './FaceRectangles';
 import { FieldView, FieldViewProps } from './FieldView';
 import "./ImageBox.scss";
 import React = require("react");
-import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 const requestImageSize = require('../../util/request-image-size');
 const path = require('path');
 const { Howl } = require('howler');
 
 
-library.add(faImage, faEye as any, faPaintBrush, faBrain);
-library.add(faFileAudio, faAsterisk);
-
-
 export const pageSchema = createSchema({
     curPage: "number",
     fitWidth: "boolean",
@@ -431,7 +424,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
                 >
                     <FontAwesomeIcon className="imageBox-audioFont"
                         style={{ color: [DocListCast(this.dataDoc[this.fieldKey + "-audioAnnotations"]).length ? "blue" : "gray", "green", "red"][this._audioState] }}
-                        icon={!DocListCast(this.dataDoc[this.fieldKey + "-audioAnnotations"]).length ? "microphone" : faFileAudio} size="sm" />
+                        icon={!DocListCast(this.dataDoc[this.fieldKey + "-audioAnnotations"]).length ? "microphone" : "file-audio"} size="sm" />
                 </div>}
             {this.considerDownloadIcon}
             {this.considerGooglePhotosLink()}
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 050ecfc49..1228a285e 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -87,14 +87,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         } else { return undefined; }
     }
     @computed get isPres(): boolean {
+        document.removeEventListener("keydown", this.keyEvents, true);
         if (this.selectedDoc?.type === DocumentType.PRES) {
-            document.removeEventListener("keydown", this.keyEvents, true);
             document.addEventListener("keydown", this.keyEvents, true);
             return true;
-        } else {
-            document.removeEventListener("keydown", this.keyEvents, true);
-            return false;
         }
+        return false;
     }
     @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
 
@@ -373,7 +371,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                         if (this.layoutDoc.presStatus === 'auto' && !this.layoutDoc.presLoop) this.layoutDoc.presStatus = "manual";
                         else if (this.layoutDoc.presLoop) this.startAutoPres(0);
                     }, duration);
-                };
+                }
             }
         };
         this.layoutDoc.presStatus = "auto";
@@ -614,6 +612,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     // Key for when the presentaiton is active
     @action
     keyEvents = (e: KeyboardEvent) => {
+        if (e.target instanceof HTMLInputElement) return;
         let handled = false;
         const anchorNode = document.activeElement as HTMLDivElement;
         if (anchorNode && anchorNode.className?.includes("lm_title")) return;
@@ -629,10 +628,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 handled = true;
             }
         } if (e.keyCode === 37 || e.keyCode === 38) { // left(37) / a(65) / up(38) to go back
-            this.back(); if (this._presTimer) clearTimeout(this._presTimer);
+            this.back();
+            if (this._presTimer) clearTimeout(this._presTimer);
             handled = true;
         } if (e.keyCode === 39 || e.keyCode === 40) { // right (39) / d(68) / down(40) to go to next
-            this.next(); if (this._presTimer) clearTimeout(this._presTimer);
+            this.next();
+            if (this._presTimer) clearTimeout(this._presTimer);
             handled = true;
         } if (e.keyCode === 32) { // spacebar to 'present' or autoplay
             if (this.layoutDoc.presStatus !== "edit") this.startAutoPres(0);
@@ -640,9 +641,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             handled = true;
         } if (e.keyCode === 8) { // delete selected items
             if (this.layoutDoc.presStatus === "edit") {
-                this._selectedArray.forEach((doc, i) => {
-                    this.removeDocument(doc);
-                });
+                this._selectedArray.forEach((doc, i) => this.removeDocument(doc));
                 this._selectedArray = [];
                 this._eleArray = [];
                 this._dragArray = [];
@@ -815,7 +814,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                             <div className="ribbon-property">
                                 <input className="presBox-input"
                                     type="number" value={transitionSpeed}
-                                    onFocus={() => { document.removeEventListener("keydown", this.keyEvents, true); }}
+                                    onFocus={() => document.removeEventListener("keydown", this.keyEvents, true)}
                                     onChange={action((e) => this.setTransitionTime(e.target.value))} /> s
                             </div>
                             <div className="ribbon-propertyUpDown">
@@ -845,7 +844,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                             <div className="ribbon-property">
                                 <input className="presBox-input"
                                     type="number" value={duration}
-                                    onFocus={() => { document.removeEventListener("keydown", this.keyEvents, true); }}
+                                    onFocus={() => document.removeEventListener("keydown", this.keyEvents, true)}
                                     onChange={action((e) => this.setDurationTime(e.target.value))} /> s
                             </div>
                             <div className="ribbon-propertyUpDown">
@@ -974,7 +973,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                         <input className="presBox-input"
                                             style={{ textAlign: 'left', width: 50 }}
                                             type="number" value={NumCast(activeItem.presPinViewX)}
-                                            onFocus={() => { document.removeEventListener("keydown", this.keyEvents, true); }}
+                                            onFocus={() => document.removeEventListener("keydown", this.keyEvents, true)}
                                             onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewX = Number(val); })} />
                                     </div>
                                 </div>
@@ -984,7 +983,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                         <input className="presBox-input"
                                             style={{ textAlign: 'left', width: 50 }}
                                             type="number" value={NumCast(activeItem.presPinViewY)}
-                                            onFocus={() => { document.removeEventListener("keydown", this.keyEvents, true); }}
+                                            onFocus={() => document.removeEventListener("keydown", this.keyEvents, true)}
                                             onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewY = Number(val); })} />
                                     </div>
                                 </div>
@@ -994,7 +993,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                         <input className="presBox-input"
                                             style={{ textAlign: 'left', width: 50 }}
                                             type="number" value={NumCast(activeItem.presPinViewScale)}
-                                            onFocus={() => { document.removeEventListener("keydown", this.keyEvents, true); }}
+                                            onFocus={() => document.removeEventListener("keydown", this.keyEvents, true)}
                                             onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewScale = Number(val); })} />
                                     </div>
                                 </div>
@@ -1044,9 +1043,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                     <div className="ribbon-box">
                         Slide Title: <br></br>
                         <input className="ribbon-textInput" placeholder="..." type="text" name="fname"
-                            onFocus={() => {
-                                document.removeEventListener("keydown", this.keyEvents, true);
-                            }}
+                            onFocus={() => document.removeEventListener("keydown", this.keyEvents, true)}
                             onChange={(e) => {
                                 e.stopPropagation();
                                 e.preventDefault();
diff --git a/src/client/views/nodes/RadialMenuItem.tsx b/src/client/views/nodes/RadialMenuItem.tsx
index bd5b3bff4..8876b4879 100644
--- a/src/client/views/nodes/RadialMenuItem.tsx
+++ b/src/client/views/nodes/RadialMenuItem.tsx
@@ -1,13 +1,9 @@
 import React = require("react");
-import { observable, action } from "mobx";
-import { observer } from "mobx-react";
-import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faAngleRight } from '@fortawesome/free-solid-svg-icons';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { observer } from "mobx-react";
 import { UndoManager } from "../../util/UndoManager";
 
-library.add(faAngleRight);
-
 export interface RadialMenuProps {
     description: string;
     event: (stuff?: any) => void;
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 1cd29d795..866e41ee0 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -1,12 +1,11 @@
 import React = require("react");
-import { library } from "@fortawesome/fontawesome-svg-core";
-import { faVideo } from "@fortawesome/free-solid-svg-icons";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { action, computed, IReactionDisposer, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import * as rp from 'request-promise';
 import { Doc } from "../../../fields/Doc";
 import { documentSchema } from "../../../fields/documentSchemas";
+import { InkTool } from "../../../fields/InkField";
 import { listSpec, makeInterface } from "../../../fields/Schema";
 import { Cast, NumCast } from "../../../fields/Types";
 import { VideoField } from "../../../fields/URLField";
@@ -18,14 +17,11 @@ import { ContextMenuProps } from "../ContextMenuItem";
 import { ViewBoxBaseComponent } from "../DocComponent";
 import { FieldView, FieldViewProps } from './FieldView';
 import "./ScreenshotBox.scss";
-import { InkTool } from "../../../fields/InkField";
 const path = require('path');
 
 type ScreenshotDocument = makeInterface<[typeof documentSchema]>;
 const ScreenshotDocument = makeInterface(documentSchema);
 
-library.add(faVideo);
-
 @observer
 export class ScreenshotBox extends ViewBoxBaseComponent<FieldViewProps, ScreenshotDocument>(ScreenshotDocument) {
     private _reactionDisposer?: IReactionDisposer;
diff --git a/src/client/views/nodes/SliderBox.tsx b/src/client/views/nodes/SliderBox.tsx
index 45cdfc5ad..d13680046 100644
--- a/src/client/views/nodes/SliderBox.tsx
+++ b/src/client/views/nodes/SliderBox.tsx
@@ -1,5 +1,3 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faEdit } from '@fortawesome/free-regular-svg-icons';
 import { runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
@@ -16,9 +14,6 @@ import { FieldView, FieldViewProps } from './FieldView';
 import { Handle, Tick, TooltipRail, Track } from './SliderBox-components';
 import './SliderBox.scss';
 
-
-library.add(faEdit as any);
-
 const SliderSchema = createSchema({
     _sliderMin: "number",
     _sliderMax: "number",
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 7d7426e31..f0e3a2b54 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -24,8 +24,8 @@ import { ContextMenu } from "../ContextMenu";
 import { ContextMenuProps } from "../ContextMenuItem";
 import { ViewBoxAnnotatableComponent } from "../DocComponent";
 import { DocumentDecorations } from "../DocumentDecorations";
-import Annotation from "../pdf/Annotation";
-import PDFMenu from "../pdf/PDFMenu";
+import { Annotation } from "../pdf/Annotation";
+import { PDFMenu } from "../pdf/PDFMenu";
 import { PdfViewerMarquee } from "../pdf/PDFViewer";
 import { FieldView, FieldViewProps } from './FieldView';
 import "./WebBox.scss";
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 77483a179..063cdb0cc 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1,5 +1,3 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faEdit, faSmile, faTextHeight, faUpload } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { isEqual } from "lodash";
 import { action, computed, IReactionDisposer, Lambda, observable, reaction, runInAction, trace } from "mobx";
@@ -22,7 +20,7 @@ import { InkTool } from '../../../../fields/InkField';
 import { PrefetchProxy } from '../../../../fields/Proxy';
 import { RichTextField } from "../../../../fields/RichTextField";
 import { RichTextUtils } from '../../../../fields/RichTextUtils';
-import { createSchema, makeInterface } from "../../../../fields/Schema";
+import { makeInterface } from "../../../../fields/Schema";
 import { Cast, DateCast, NumCast, StrCast, ScriptCast, BoolCast } from "../../../../fields/Types";
 import { TraceMobx, OVERRIDE_ACL, GetEffectiveAcl } from '../../../../fields/util';
 import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, returnZero, Utils, setupMoveUpEvents } from '../../../../Utils';
@@ -33,8 +31,8 @@ import { DocumentType } from '../../../documents/DocumentTypes';
 import { DictationManager } from '../../../util/DictationManager';
 import { DragManager } from "../../../util/DragManager";
 import { makeTemplate } from '../../../util/DropConverter';
-import buildKeymap, { updateBullets } from "./ProsemirrorExampleTransfer";
-import RichTextMenu, { RichTextMenuPlugin } from './RichTextMenu';
+import { buildKeymap, updateBullets } from "./ProsemirrorExampleTransfer";
+import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu';
 import { RichTextRules } from "./RichTextRules";
 
 //import { DashDocView } from "./DashDocView";
@@ -61,9 +59,6 @@ import { FormattedTextBoxComment, formattedTextBoxCommentPlugin, findLinkMark }
 import React = require("react");
 import { DocumentManager } from '../../../util/DocumentManager';
 
-library.add(faEdit);
-library.add(faSmile, faTextHeight, faUpload);
-
 export interface FormattedTextBoxProps {
     makeLink?: () => Opt<Doc>;  // bcz: hack: notifies the text document when the container has made a link.  allows the text doc to react and setup a hyeprlink for any selected text
     hideOnLeave?: boolean;  // used by DocumentView for setting caption's hide on leave (bcz: would prefer to have caption-hideOnLeave field set or something similar)
@@ -915,7 +910,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     return linkIndex !== -1 && marks[linkIndex].attrs.allLinks.find((item: { href: string }) => scrollToLinkID === item.href.replace(/.*\/doc\//, "")) ? node : undefined;
                 };
 
-                let start = 0;
+                const start = 0;
                 if (this._editorView && scrollToLinkID) {
                     const editor = this._editorView;
                     const ret = findLinkFrag(editor.state.doc.content, editor);
diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
index 8faf752b4..0eb675b4e 100644
--- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
+++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
@@ -33,7 +33,7 @@ export let updateBullets = (tx2: Transaction, schema: Schema, assignedMapStyle?:
     return tx2;
 };
 
-export default function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKeys?: KeyMap): KeyMap {
+export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKeys?: KeyMap): KeyMap {
     const keys: { [key: string]: any } = {};
 
     function bind(key: string, cmd: any) {
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 96628949a..a0e2d4351 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -1,8 +1,8 @@
 import React = require("react");
-import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faBold, faCaretDown, faChevronLeft, faEyeDropper, faHighlighter, faOutdent, faIndent, faHandPointLeft, faHandPointRight, faItalic, faLink, faPaintRoller, faPalette, faStrikethrough, faSubscript, faSuperscript, faUnderline } from "@fortawesome/free-solid-svg-icons";
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, observable, IReactionDisposer, reaction } from "mobx";
+import { Tooltip } from "@material-ui/core";
+import { action, IReactionDisposer, observable, reaction } from "mobx";
 import { observer } from "mobx-react";
 import { lift, wrapIn } from "prosemirror-commands";
 import { Mark, MarkType, Node as ProsNode, NodeType, ResolvedPos } from "prosemirror-model";
@@ -11,27 +11,24 @@ import { EditorState, NodeSelection, TextSelection } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
 import { Doc } from "../../../../fields/Doc";
 import { DarkPastelSchemaPalette, PastelSchemaPalette } from '../../../../fields/SchemaHeaderField';
-import { Cast, StrCast, BoolCast, NumCast } from "../../../../fields/Types";
+import { Cast, StrCast } from "../../../../fields/Types";
+import { TraceMobx } from "../../../../fields/util";
 import { unimplementedFunction, Utils } from "../../../../Utils";
 import { DocServer } from "../../../DocServer";
 import { LinkManager } from "../../../util/LinkManager";
 import { SelectionManager } from "../../../util/SelectionManager";
-import AntimodeMenu, { AntimodeMenuProps } from "../../AntimodeMenu";
+import { undoBatch, UndoManager } from "../../../util/UndoManager";
+import { AntimodeMenu, AntimodeMenuProps } from "../../AntimodeMenu";
 import { FieldViewProps } from "../FieldView";
 import { FormattedTextBox, FormattedTextBoxProps } from "./FormattedTextBox";
 import { updateBullets } from "./ProsemirrorExampleTransfer";
 import "./RichTextMenu.scss";
 import { schema } from "./schema_rts";
-import { TraceMobx } from "../../../../fields/util";
-import { UndoManager, undoBatch } from "../../../util/UndoManager";
-import { Tooltip } from "@material-ui/core";
 const { toggleMark } = require("prosemirror-commands");
 
-library.add(faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSuperscript, faSubscript, faOutdent, faIndent, faHandPointLeft, faHandPointRight, faEyeDropper, faCaretDown, faPalette, faHighlighter, faLink, faPaintRoller);
-
 
 @observer
-export default class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
+export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
     static Instance: RichTextMenu;
     public overMenu: boolean = false; // kind of hacky way to prevent selects not being selectable
 
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index a455516a3..7e632a0ee 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -9,7 +9,7 @@ import { DocServer } from "../../../DocServer";
 import { Docs, DocUtils } from "../../../documents/Documents";
 import { FormattedTextBox } from "./FormattedTextBox";
 import { wrappingInputRule } from "./prosemirrorPatches";
-import RichTextMenu from "./RichTextMenu";
+import { RichTextMenu } from "./RichTextMenu";
 import { schema } from "./schema_rts";
 import { List } from "../../../../fields/List";
 
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index d29b638e6..98638ecc2 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -6,7 +6,7 @@ import { Id } from "../../../fields/FieldSymbols";
 import { List } from "../../../fields/List";
 import { Cast, FieldValue, NumCast, StrCast } from "../../../fields/Types";
 import { DocumentManager } from "../../util/DocumentManager";
-import PDFMenu from "./PDFMenu";
+import { PDFMenu } from "./PDFMenu";
 import "./Annotation.scss";
 
 interface IAnnotationProps {
@@ -19,7 +19,7 @@ interface IAnnotationProps {
 }
 
 @observer
-export default
+export
     class Annotation extends React.Component<IAnnotationProps> {
     render() {
         return DocListCast(this.props.anno.annotations).map(a => (
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index 0f7b0a688..32dd376ac 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -1,17 +1,17 @@
 import React = require("react");
-import "./PDFMenu.scss";
-import { observable, action, computed, } from "mobx";
-import { observer } from "mobx-react";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { unimplementedFunction, returnFalse, Utils } from "../../../Utils";
-import AntimodeMenu, { AntimodeMenuProps } from "../AntimodeMenu";
-import { Doc, Opt } from "../../../fields/Doc";
+import { action, computed, observable } from "mobx";
+import { observer } from "mobx-react";
 import { ColorState } from "react-color";
+import { Doc, Opt } from "../../../fields/Doc";
+import { returnFalse, unimplementedFunction, Utils } from "../../../Utils";
+import { AntimodeMenu, AntimodeMenuProps } from "../AntimodeMenu";
 import { ButtonDropdown } from "../nodes/formattedText/RichTextMenu";
+import "./PDFMenu.scss";
 
 
 @observer
-export default class PDFMenu extends AntimodeMenu<AntimodeMenuProps> {
+export class PDFMenu extends AntimodeMenu<AntimodeMenuProps> {
     static Instance: PDFMenu;
 
     private _commentCont = React.createRef<HTMLButtonElement>();
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 201333d95..c8f98e249 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -1,39 +1,39 @@
 import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
-const pdfjs = require('pdfjs-dist/es5/build/pdf.js');
 import * as Pdfjs from "pdfjs-dist";
 import "pdfjs-dist/web/pdf_viewer.css";
 import { Dictionary } from "typescript-collections";
-import { Doc, DocListCast, FieldResult, HeightSym, Opt, WidthSym, AclAddonly, AclEdit, AclAdmin, DataSym } from "../../../fields/Doc";
+import { AclAddonly, AclAdmin, AclEdit, DataSym, Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
 import { documentSchema } from "../../../fields/documentSchemas";
 import { Id } from "../../../fields/FieldSymbols";
 import { InkTool } from "../../../fields/InkField";
 import { List } from "../../../fields/List";
-import { createSchema, makeInterface, listSpec } from "../../../fields/Schema";
-import { ScriptField, ComputedField } from "../../../fields/ScriptField";
+import { createSchema, makeInterface } from "../../../fields/Schema";
+import { ScriptField } from "../../../fields/ScriptField";
 import { Cast, NumCast } from "../../../fields/Types";
 import { PdfField } from "../../../fields/URLField";
-import { TraceMobx, GetEffectiveAcl } from "../../../fields/util";
+import { GetEffectiveAcl, TraceMobx } from "../../../fields/util";
 import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, emptyPath, intersectRect, returnZero, smoothScroll, Utils } from "../../../Utils";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { DocumentType } from "../../documents/DocumentTypes";
+import { Networking } from "../../Network";
 import { DragManager } from "../../util/DragManager";
 import { CompiledScript, CompileScript } from "../../util/Scripting";
 import { SelectionManager } from "../../util/SelectionManager";
+import { SnappingManager } from "../../util/SnappingManager";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
 import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
 import { CollectionView } from "../collections/CollectionView";
 import { ViewBoxAnnotatableComponent } from "../DocComponent";
 import { DocumentDecorations } from "../DocumentDecorations";
-import Annotation from "./Annotation";
-import PDFMenu from "./PDFMenu";
+import { Annotation } from "./Annotation";
+import { PDFMenu } from "./PDFMenu";
 import "./PDFViewer.scss";
+const pdfjs = require('pdfjs-dist/es5/build/pdf.js');
 import React = require("react");
-import { SnappingManager } from "../../util/SnappingManager";
 const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer");
 const pdfjsLib = require("pdfjs-dist");
-import { Networking } from "../../Network";
 
 export const pageSchema = createSchema({
     curPage: "number",
diff --git a/src/client/views/search/IconBar.tsx b/src/client/views/search/IconBar.tsx
index 9b7cf2fc6..f1dd106a7 100644
--- a/src/client/views/search/IconBar.tsx
+++ b/src/client/views/search/IconBar.tsx
@@ -1,28 +1,11 @@
-import * as React from 'react';
+import { action, observable } from 'mobx';
 import { observer } from 'mobx-react';
-import { observable, action } from 'mobx';
+import * as React from 'react';
+import { DocumentType } from "../../documents/DocumentTypes";
 // import "./SearchBox.scss";
 import "./IconBar.scss";
-import "./IconButton.scss";
-import { faSearch, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faMusic, faLink, faChartBar, faGlobeAsia, faBan, faTimesCircle, faCheckCircle } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { library } from '@fortawesome/fontawesome-svg-core';
-import * as _ from "lodash";
 import { IconButton } from './IconButton';
-import { DocumentType } from "../../documents/DocumentTypes";
-
-
-library.add(faSearch);
-library.add(faObjectGroup);
-library.add(faImage);
-library.add(faStickyNote);
-library.add(faFilePdf);
-library.add(faFilm);
-library.add(faMusic);
-library.add(faLink);
-library.add(faChartBar);
-library.add(faGlobeAsia);
-library.add(faBan);
+import "./IconButton.scss";
 
 export interface IconBarProps {
     setIcons: (icons: string[]) => void;
diff --git a/src/client/views/search/IconButton.tsx b/src/client/views/search/IconButton.tsx
index 52641c543..349690b20 100644
--- a/src/client/views/search/IconButton.tsx
+++ b/src/client/views/search/IconButton.tsx
@@ -1,30 +1,14 @@
-import * as React from 'react';
-import { observer } from 'mobx-react';
-import { observable, action, runInAction, IReactionDisposer, reaction } from 'mobx';
-import "./SearchBox.scss";
-import "./IconButton.scss";
-import { faSearch, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faMusic, faLink, faChartBar, faGlobeAsia, faBan, faVideo, faCaretDown } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { library, icon } from '@fortawesome/fontawesome-svg-core';
+import * as _ from "lodash";
+import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
 import { DocumentType } from "../../documents/DocumentTypes";
 import '../globalCssVariables.scss';
-import * as _ from "lodash";
 import { IconBar } from './IconBar';
-import { props } from 'bluebird';
-import { Search } from '../../../server/Search';
-import { gravity } from 'sharp';
-
-library.add(faSearch);
-library.add(faObjectGroup);
-library.add(faImage);
-library.add(faStickyNote);
-library.add(faFilePdf);
-library.add(faFilm);
-library.add(faMusic);
-library.add(faLink);
-library.add(faChartBar);
-library.add(faGlobeAsia);
-library.add(faBan);
+import "./IconButton.scss";
+import "./SearchBox.scss";
+import { Font } from '@react-pdf/renderer';
 
 interface IconButtonProps {
     type: string;
@@ -47,59 +31,46 @@ export class IconButton extends React.Component<IconButtonProps>{
     componentDidMount = () => {
         this._resetReaction = reaction(
             () => IconBar.Instance._resetClicked,
-            () => {
+            action(() => {
                 if (IconBar.Instance._resetClicked) {
-                    runInAction(() => {
-                        this.reset();
-                        IconBar.Instance._reset++;
-                        if (IconBar.Instance._reset === 9) {
-                            IconBar.Instance._reset = 0;
-                            IconBar.Instance._resetClicked = false;
-                        }
-                    });
+                    this._isSelected = false;
+                    IconBar.Instance._reset++;
+                    if (IconBar.Instance._reset === 9) {
+                        IconBar.Instance._reset = 0;
+                        IconBar.Instance._resetClicked = false;
+                    }
                 }
-            },
+            }),
         );
+
         this._selectAllReaction = reaction(
             () => IconBar.Instance._selectAllClicked,
-            () => {
+            action(() => {
                 if (IconBar.Instance._selectAllClicked) {
-                    runInAction(() => {
-                        this.select();
-                        IconBar.Instance._select++;
-                        if (IconBar.Instance._select === 9) {
-                            IconBar.Instance._select = 0;
-                            IconBar.Instance._selectAllClicked = false;
-                        }
-                    });
+                    this._isSelected = true;
+                    IconBar.Instance._select++;
+                    if (IconBar.Instance._select === 9) {
+                        IconBar.Instance._select = 0;
+                        IconBar.Instance._selectAllClicked = false;
+                    }
                 }
-            },
+            }),
         );
     }
 
     @action.bound
     getIcon() {
         switch (this.props.type) {
-            case (DocumentType.NONE):
-                return faBan;
-            case (DocumentType.AUDIO):
-                return faMusic;
-            case (DocumentType.COL):
-                return faObjectGroup;
-            case (DocumentType.IMG):
-                return faImage;
-            case (DocumentType.LINK):
-                return faLink;
-            case (DocumentType.PDF):
-                return faFilePdf;
-            case (DocumentType.RTF):
-                return faStickyNote;
-            case (DocumentType.VID):
-                return faVideo;
-            case (DocumentType.WEB):
-                return faGlobeAsia;
-            default:
-                return faCaretDown;
+            case (DocumentType.NONE): return "ban";
+            case (DocumentType.AUDIO): return "music";
+            case (DocumentType.COL): return "object-group";
+            case (DocumentType.IMG): return "image";
+            case (DocumentType.LINK): return "link";
+            case (DocumentType.PDF): return "file-pdf";
+            case (DocumentType.RTF): return "sticky-note";
+            case (DocumentType.VID): return "video";
+            case (DocumentType.WEB): return "globe-asia";
+            default: return "caret-down";
         }
     }
 
@@ -136,53 +107,16 @@ export class IconButton extends React.Component<IconButtonProps>{
         //backgroundColor: "rgb(178, 206, 248)" //$darker-alt-accent
     };
 
-    @action.bound
-    public reset() { this._isSelected = false; }
-
-    @action.bound
-    public select() { this._isSelected = true; }
-
-    @action
-    onMouseLeave = () => { this._hover = false; }
-
-    @action
-    onMouseEnter = () => { this._hover = true; }
-
-    getFA = () => {
-        switch (this.props.type) {
-            case (DocumentType.NONE):
-                return (<FontAwesomeIcon className="fontawesome-icon" icon={faBan} />);
-            case (DocumentType.AUDIO):
-                return (<FontAwesomeIcon className="fontawesome-icon" icon={faMusic} />);
-            case (DocumentType.COL):
-                return (<FontAwesomeIcon className="fontawesome-icon" icon={faObjectGroup} />);
-            case (DocumentType.IMG):
-                return (<FontAwesomeIcon className="fontawesome-icon" icon={faImage} />);
-            case (DocumentType.LINK):
-                return (<FontAwesomeIcon className="fontawesome-icon" icon={faLink} />);
-            case (DocumentType.PDF):
-                return (<FontAwesomeIcon className="fontawesome-icon" icon={faFilePdf} />);
-            case (DocumentType.RTF):
-                return (<FontAwesomeIcon className="fontawesome-icon" icon={faStickyNote} />);
-            case (DocumentType.VID):
-                return (<FontAwesomeIcon className="fontawesome-icon" icon={faVideo} />);
-            case (DocumentType.WEB):
-                return (<FontAwesomeIcon className="fontawesome-icon" icon={faGlobeAsia} />);
-            default:
-                return (<FontAwesomeIcon className="fontawesome-icon" icon={faCaretDown} />);
-        }
-    }
-
     render() {
         return (
             <div className="type-outer" id={this.props.type + "-filter"}
-                onMouseEnter={this.onMouseEnter}
-                onMouseLeave={this.onMouseLeave}
+                onMouseEnter={() => this._hover = true}
+                onMouseLeave={() => this._hover = false}
                 onClick={this.onClick}>
                 <div className="type-icon" id={this.props.type + "-icon"}
                     style={this._hover ? this.hoverStyle : this._isSelected ? this.selected : this.notSelected}
                 >
-                    {this.getFA()}
+                    <FontAwesomeIcon className="fontawesome-icon" icon={this.getIcon()} />
                 </div>
                 {/* <div className="filter-description">{this.props.type}</div> */}
             </div>
diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx
index 647e1ce6f..82c0e19c8 100644
--- a/src/client/views/webcam/DashWebRTCVideo.tsx
+++ b/src/client/views/webcam/DashWebRTCVideo.tsx
@@ -1,20 +1,16 @@
-import { observer } from "mobx-react";
-import React = require("react");
-import { CollectionFreeFormDocumentViewProps } from "../nodes/CollectionFreeFormDocumentView";
-import { FieldViewProps, FieldView } from "../nodes/FieldView";
-import { observable, action } from "mobx";
-import { DocumentDecorations } from "../DocumentDecorations";
-import "../../views/nodes/WebBox.scss";
-import "./DashWebRTCVideo.scss";
-import { initialize, hangup, refreshVideos } from "./WebCamLogic";
+import { faPhoneSlash, faSync } from "@fortawesome/free-solid-svg-icons";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faSync, faPhoneSlash } from "@fortawesome/free-solid-svg-icons";
+import { action, observable } from "mobx";
+import { observer } from "mobx-react";
 import { Doc } from "../../../fields/Doc";
 import { InkTool } from "../../../fields/InkField";
-
-library.add(faSync);
-library.add(faPhoneSlash);
+import "../../views/nodes/WebBox.scss";
+import { DocumentDecorations } from "../DocumentDecorations";
+import { CollectionFreeFormDocumentViewProps } from "../nodes/CollectionFreeFormDocumentView";
+import { FieldView, FieldViewProps } from "../nodes/FieldView";
+import "./DashWebRTCVideo.scss";
+import { hangup, initialize, refreshVideos } from "./WebCamLogic";
+import React = require("react");
 
 
 /**
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index 738de09c6..c412059dd 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -7,14 +7,14 @@ import { Utils, emptyPath, returnFalse, emptyFunction, returnOne, returnZero, re
 import { Doc, Opt } from '../fields/Doc';
 import { Cast, FieldValue } from '../fields/Types';
 import { listSpec } from '../fields/Schema';
-import MainViewModal from '../client/views/MainViewModal';
+import { MainViewModal } from '../client/views/MainViewModal';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { nullAudio } from '../fields/URLField';
 import { Transform } from '../client/util/Transform';
 import { DocumentView } from '../client/views/nodes/DocumentView';
 import { MobileInterface } from './MobileInterface';
 import { DictationOverlay } from '../client/views/DictationOverlay';
-import RichTextMenu from '../client/views/nodes/formattedText/RichTextMenu';
+import { RichTextMenu } from '../client/views/nodes/formattedText/RichTextMenu';
 import { ContextMenu } from '../client/views/ContextMenu';
 
 @observer
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
index d21d326f6..0ae952304 100644
--- a/src/mobile/ImageUpload.tsx
+++ b/src/mobile/ImageUpload.tsx
@@ -1,19 +1,19 @@
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, observable } from 'mobx';
+import { observer } from 'mobx-react';
 import * as rp from 'request-promise';
-import { Docs } from '../client/documents/Documents';
-import "./ImageUpload.scss";
-import React = require('react');
 import { DocServer } from '../client/DocServer';
-import { observer } from 'mobx-react';
-import { observable, action } from 'mobx';
-import { Utils } from '../Utils';
+import { Docs } from '../client/documents/Documents';
 import { Networking } from '../client/Network';
+import { MainViewModal } from '../client/views/MainViewModal';
 import { Doc, Opt } from '../fields/Doc';
-import { Cast } from '../fields/Types';
-import { listSpec } from '../fields/Schema';
 import { List } from '../fields/List';
-import MainViewModal from '../client/views/MainViewModal';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { listSpec } from '../fields/Schema';
+import { Cast } from '../fields/Types';
+import { Utils } from '../Utils';
+import "./ImageUpload.scss";
 import { MobileInterface } from './MobileInterface';
+import React = require('react');
 
 export interface ImageUploadProps {
     Document: Doc; // Target document for upload (upload location)
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 05a695147..8ca67f9ee 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -1,4 +1,4 @@
-import * as React from "react";
+
 import { library } from '@fortawesome/fontawesome-svg-core';
 import {
     faTasks, faReply, faQuoteLeft, faHandPointLeft, faFolderOpen, faAngleDoubleLeft, faExternalLinkSquareAlt, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus,
@@ -10,34 +10,34 @@ import {
     faAlignRight, faAlignLeft
 } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, reaction, trace, runInAction } from 'mobx';
+import { action, computed, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, DocListCast } from '../fields/Doc';
-import { CurrentUserUtils } from '../client/util/CurrentUserUtils';
-import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, returnZero, returnEmptyFilter, returnEmptyDoclist } from '../Utils';
+import * as React from "react";
 import { Docs, DocumentOptions } from '../client/documents/Documents';
+import { DocumentType } from "../client/documents/DocumentTypes";
+import { CurrentUserUtils } from '../client/util/CurrentUserUtils';
 import { Scripting } from '../client/util/Scripting';
-import { DocumentView } from '../client/views/nodes/DocumentView';
+import { SettingsManager } from '../client/util/SettingsManager';
 import { Transform } from '../client/util/Transform';
-import "./MobileInterface.scss";
-import "./ImageUpload.scss";
-import "./AudioUpload.scss";
-import SettingsManager from '../client/util/SettingsManager';
-import { Uploader } from "./ImageUpload";
+import { UndoManager } from "../client/util/UndoManager";
 import { DockedFrameRenderer } from '../client/views/collections/CollectionDockingView';
-import { InkTool } from '../fields/InkField';
-import GestureOverlay from "../client/views/GestureOverlay";
-import { ScriptField } from "../fields/ScriptField";
+import { CollectionViewType } from "../client/views/collections/CollectionView";
+import { GestureOverlay } from "../client/views/GestureOverlay";
+import { AudioBox } from "../client/views/nodes/AudioBox";
+import { DocumentView } from '../client/views/nodes/DocumentView';
+import { RichTextMenu } from "../client/views/nodes/formattedText/RichTextMenu";
 import { RadialMenu } from "../client/views/nodes/RadialMenu";
-import { UndoManager } from "../client/util/UndoManager";
+import { Doc, DocListCast } from '../fields/Doc';
+import { InkTool } from '../fields/InkField';
 import { List } from "../fields/List";
-import { AudioUpload } from "./AudioUpload";
+import { ScriptField } from "../fields/ScriptField";
 import { Cast, FieldValue } from '../fields/Types';
-import RichTextMenu from "../client/views/nodes/formattedText/RichTextMenu";
-import { AudioBox } from "../client/views/nodes/AudioBox";
-import { CollectionViewType } from "../client/views/collections/CollectionView";
-import { DocumentType } from "../client/documents/DocumentTypes";
-import { CollectionFreeFormViewChrome } from "../client/views/collections/CollectionMenu";
+import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero } from '../Utils';
+import { AudioUpload } from "./AudioUpload";
+import { Uploader } from "./ImageUpload";
+import "./AudioUpload.scss";
+import "./ImageUpload.scss";
+import "./MobileInterface.scss";
 
 library.add(faTasks, faReply, faQuoteLeft, faHandPointLeft, faFolderOpen, faAngleDoubleLeft, faExternalLinkSquareAlt, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus,
     faTerminal, faToggleOn, fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard,
@@ -47,6 +47,7 @@ library.add(faTasks, faReply, faQuoteLeft, faHandPointLeft, faFolderOpen, faAngl
     faThumbtack, faTree, faTv, faUndoAlt, faBook, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faHome, faLongArrowAltLeft, faBars, faTh, faChevronLeft,
     faAlignLeft, faAlignRight);
 
+
 @observer
 export class MobileInterface extends React.Component {
     static Instance: MobileInterface;
-- 
cgit v1.2.3-70-g09d2


From 57458679ffe87302b46c64ffaa05f967c84623df Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 25 Aug 2020 14:42:15 -0400
Subject: major rewrite of schema table and schem cells.  lists/docs work now. 
 dates display better. resizing is better and faster (but not fast).

---
 src/client/views/EditableView.tsx                  | 111 ++--
 .../views/collections/CollectionSchemaCells.tsx    | 686 +++++----------------
 src/client/views/collections/CollectionView.tsx    |   7 +-
 src/client/views/collections/SchemaTable.tsx       |  30 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   3 +-
 src/fields/DateField.ts                            |   4 +-
 src/fields/List.ts                                 |   2 +-
 src/fields/util.ts                                 |  11 +-
 8 files changed, 232 insertions(+), 622 deletions(-)

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

diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index d0e6ed463..8b2fa9472 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -52,10 +52,6 @@ export interface EditableProps {
     color?: string | undefined;
     onDrop?: any;
     placeholder?: string;
-    highlight?: boolean;
-    positions?: number[];
-    search?: string;
-    bing?: () => string | undefined;
 }
 
 /**
@@ -94,25 +90,30 @@ export class EditableView extends React.Component<EditableProps> {
 
     @action
     onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
-        if (e.key === "Tab") {
-            e.stopPropagation();
-            this.finalizeEdit(e.currentTarget.value, e.shiftKey, false);
-            this.props.OnTab && this.props.OnTab(e.shiftKey);
-        } else if (e.key === "Enter") {
-            e.stopPropagation();
-            if (!e.ctrlKey) {
+        switch (e.key) {
+            case "Tab":
+                e.stopPropagation();
                 this.finalizeEdit(e.currentTarget.value, e.shiftKey, false);
-            } else if (this.props.OnFillDown) {
-                this.props.OnFillDown(e.currentTarget.value);
+                this.props.OnTab && this.props.OnTab(e.shiftKey);
+                break;
+            case "Enter":
+                e.stopPropagation();
+                if (!e.ctrlKey) {
+                    this.finalizeEdit(e.currentTarget.value, e.shiftKey, false);
+                } else if (this.props.OnFillDown) {
+                    this.props.OnFillDown(e.currentTarget.value);
+                    this._editing = false;
+                    this.props.isEditingCallback?.(false);
+                }
+                break;
+            case "Escape":
+                e.stopPropagation();
                 this._editing = false;
                 this.props.isEditingCallback?.(false);
-            }
-        } else if (e.key === "Escape") {
-            e.stopPropagation();
-            this._editing = false;
-            this.props.isEditingCallback?.(false);
-        } else if (e.key === ":") {
-            this.props.menuCallback?.(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y);
+                break;
+            case ":":
+                this.props.menuCallback?.(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y);
+                break;
         }
     }
 
@@ -121,11 +122,9 @@ export class EditableView extends React.Component<EditableProps> {
         e.nativeEvent.stopPropagation();
         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?.(e)) {
-                this._editing = true;
-                this.props.isEditingCallback?.(true);
-            }
+        } else if (!this.props.onClick?.(e)) {
+            this._editing = true;
+            this.props.isEditingCallback?.(true);
         }
         e.stopPropagation();
     }
@@ -178,10 +177,7 @@ export class EditableView extends React.Component<EditableProps> {
                 defaultValue={this.props.GetValue()}
                 onKeyDown={this.onKeyDown}
                 autoFocus={true}
-                onKeyPress={e => {
-                    e.stopPropagation();
-                    (e.nativeEvent as any).Aaaa = 3;
-                }}
+                onKeyPress={e => e.stopPropagation()}
                 onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true)}
                 onPointerDown={this.stopPropagation} onClick={this.stopPropagation} onPointerUp={this.stopPropagation}
                 style={{ display: this.props.display, fontSize: this.props.fontSize, minWidth: 20 }}
@@ -189,54 +185,25 @@ export class EditableView extends React.Component<EditableProps> {
             />;
     }
 
-    returnHighlights() {
-        const results = [];
-        const contents = this.props.bing!();
-
-        if (contents !== undefined) {
-            if (this.props.positions !== undefined) {
-                const positions = this.props.positions;
-                const length = this.props.search!.length;
-
-                // contents = String(this.props.contents.valueOf());
-
-                results.push(<span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize, color: this.props.contents ? "black" : "grey" }}>{contents ? contents.slice(0, this.props.positions[0]) : this.props.placeholder?.valueOf()}</span>);
-                positions.forEach((num, cur) => {
-                    results.push(<span style={{ backgroundColor: "#FFFF00", fontStyle: this.props.fontStyle, fontSize: this.props.fontSize, color: this.props.contents ? "black" : "grey" }}>{contents ? contents.slice(num, num + length) : this.props.placeholder?.valueOf()}</span>);
-                    let end = 0;
-                    cur === positions.length - 1 ? end = contents.length : end = positions[cur + 1];
-                    results.push(<span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize, color: this.props.contents ? "black" : "grey" }}>{contents ? contents.slice(num + length, end) : this.props.placeholder?.valueOf()}</span>);
-                }
-                );
-            }
-            return results;
-        }
-        else {
-            return <span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize, color: this.props.contents ? "black" : "grey" }}>{this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()}</span>;
-        }
-    }
-
     render() {
         if (this._editing && this.props.GetValue() !== undefined) {
             return this.props.sizeToContent ?
                 <div style={{ display: "grid", minWidth: 100 }}>
-                    <div style={{ display: "inline-block", position: "relative", height: 0, width: "100%", overflow: "hidden" }}>{this.props.GetValue()}</div>
+                    <div style={{ display: "inline-block", position: "relative", height: 0, width: "100%", overflow: "hidden" }}>
+                        {this.props.GetValue()}
+                    </div>
                     {this.renderEditor()}
-                </div> : this.renderEditor();
-        } else {
-            setTimeout(() => this.props.autosuggestProps?.resetValue(), 0);
-            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: "17px", whiteSpace: "nowrap", height: `${this.props.height ? this.props.height : "auto"}`, maxHeight: `${this.props.maxHeight}` }}
-                    onClick={this.onClick} placeholder={this.props.placeholder}>
-                    {this.props.highlight === undefined || this.props.positions === undefined || this.props.bing === undefined ?
-                        <span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize }}>{//}, color: this.props.contents ? "black" : "grey" }}>{
-                            this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()}
-                        </span>
-                        : this.returnHighlights()}
-                </div>
-            );
+                </div> :
+                this.renderEditor();
         }
+        setTimeout(() => this.props.autosuggestProps?.resetValue(), 0);
+        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: "17px", whiteSpace: "nowrap", height: `${this.props.height ? this.props.height : "auto"}`, maxHeight: `${this.props.maxHeight}` }}
+                onClick={this.onClick} placeholder={this.props.placeholder}>
+                <span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize }}>{
+                    this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()}
+                </span>
+            </div>;
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index ac789ab48..95f425524 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -10,27 +10,24 @@ import { DateField } from "../../../fields/DateField";
 import { Doc, DocListCast, Field, Opt } from "../../../fields/Doc";
 import { Id } from "../../../fields/FieldSymbols";
 import { List } from "../../../fields/List";
-import { RichTextField } from "../../../fields/RichTextField";
 import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
 import { ComputedField } from "../../../fields/ScriptField";
 import { BoolCast, Cast, DateCast, FieldValue, NumCast, StrCast } from "../../../fields/Types";
 import { ImageField } from "../../../fields/URLField";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnZero, Utils } from "../../../Utils";
+import { Utils } from "../../../Utils";
 import { Docs } from "../../documents/Documents";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { DocumentManager } from "../../util/DocumentManager";
-import { DragManager, SetupDrag } from "../../util/DragManager";
+import { DragManager } from "../../util/DragManager";
 import { KeyCodes } from "../../util/KeyCodes";
 import { CompileScript } from "../../util/Scripting";
 import { SearchUtil } from "../../util/SearchUtil";
 import { SnappingManager } from "../../util/SnappingManager";
-import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
 import '../DocumentDecorations.scss';
 import { EditableView } from "../EditableView";
-import { COLLECTION_BORDER_WIDTH, MAX_ROW_HEIGHT } from '../globalCssVariables.scss';
+import { MAX_ROW_HEIGHT } from '../globalCssVariables.scss';
 import { DocumentIconContainer } from "../nodes/DocumentIcon";
-import { FieldViewProps } from "../nodes/FieldView";
 import { OverlayView } from "../OverlayView";
 import "./CollectionSchemaView.scss";
 import { CollectionView } from "./CollectionView";
@@ -61,20 +58,24 @@ export interface CellProps {
 
 @observer
 export class CollectionSchemaCell extends React.Component<CellProps> {
+    public static resolvedFieldKey(column: string, rowDoc: Doc) {
+        const fieldKey = column;
+        if (fieldKey.startsWith("*")) {
+            const rootKey = fieldKey.substring(1);
+            const allKeys = [...Array.from(Object.keys(rowDoc)), ...Array.from(Object.keys(Doc.GetProto(rowDoc)))];
+            const matchedKeys = allKeys.filter(key => key.includes(rootKey));
+            if (matchedKeys.length) return matchedKeys[0];
+        }
+        return fieldKey;
+    }
     @observable protected _isEditing: boolean = false;
     protected _focusRef = React.createRef<HTMLDivElement>();
-    protected _document = this.props.rowProps.original;
+    protected _rowDoc = this.props.rowProps.original;
     protected _dropDisposer?: DragManager.DragDropDisposer;
-
-    async componentDidMount() {
-        document.addEventListener("keydown", this.onKeyDown);
-    }
-
     @observable contents: string = "";
 
-    componentWillUnmount() {
-        document.removeEventListener("keydown", this.onKeyDown);
-    }
+    componentDidMount() { document.addEventListener("keydown", this.onKeyDown); }
+    componentWillUnmount() { document.removeEventListener("keydown", this.onKeyDown); }
 
     @action
     onKeyDown = (e: KeyboardEvent): void => {
@@ -96,7 +97,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
 
     @action
     onPointerDown = async (e: React.PointerEvent): Promise<void> => {
-
+        this.onItemDown(e);
         this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
         this.props.setPreviewDoc(this.props.rowProps.original);
 
@@ -110,33 +111,26 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             } catch { }
         }
 
-        // this._isEditing = true;
-        // this.props.setIsEditing(true);
-
-        const field = this.props.rowProps.original[this.props.rowProps.column.id!];
-        const doc = FieldValue(Cast(field, Doc));
-        if (typeof field === "object" && doc) this.props.setPreviewDoc(doc);
+        const doc = Cast(this._rowDoc[this.renderFieldKey], Doc, null);
+        doc && this.props.setPreviewDoc(doc);
     }
 
     @undoBatch
     applyToDoc = (doc: Doc, row: number, col: number, run: (args?: { [name: string]: any }) => any) => {
         const res = run({ this: doc, $r: row, $c: col, $: (r: number = 0, c: number = 0) => this.props.getField(r + row, c + col) });
         if (!res.success) return false;
-        // doc[this.props.fieldKey] = res.result;
-        // return true;
-        doc[this.props.rowProps.column.id as string] = res.result;
+        doc[this.renderFieldKey] = res.result;
         return true;
     }
 
     private drop = (e: Event, de: DragManager.DropEvent) => {
         if (de.complete.docDragData) {
-            const fieldKey = this.props.rowProps.column.id as string;
             if (de.complete.docDragData.draggedDocuments.length === 1) {
-                this._document[fieldKey] = de.complete.docDragData.draggedDocuments[0];
+                this._rowDoc[this.renderFieldKey] = de.complete.docDragData.draggedDocuments[0];
             }
             else {
                 const coll = Docs.Create.SchemaDocument([new SchemaHeaderField("title", "#f1efeb")], de.complete.docDragData.draggedDocuments, {});
-                this._document[fieldKey] = coll;
+                this._rowDoc[this.renderFieldKey] = coll;
             }
             e.stopPropagation();
         }
@@ -147,22 +141,9 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
         ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)));
     }
 
-    // expandDoc = (e: React.PointerEvent) => {
-    //     let field = this.props.rowProps.original[this.props.rowProps.column.id as string];
-    //     let doc = FieldValue(Cast(field, Doc));
-
-    //     this.props.setPreviewDoc(doc!);
-
-    //     // this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
-
-    //     e.stopPropagation();
-    // }
-
-    returnHighlights(bing: (() => string), positions?: number[]) {
-        const results = [];
-        const contents = bing();
-
-        if (positions !== undefined) {
+    returnHighlights(contents: string, positions?: number[]) {
+        if (positions) {
+            const results = [];
             StrCast(this.props.Document._searchString);
             const length = StrCast(this.props.Document._searchString).length;
             const color = contents ? "black" : "grey";
@@ -177,72 +158,24 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             );
             return results;
         }
-        else {
-            return <span style={{ color: contents ? "black" : "grey" }}>{contents ? contents?.valueOf() : "undefined"}</span>;
-        }
+        return <span style={{ color: contents ? "black" : "grey" }}>{contents ? contents?.valueOf() : "undefined"}</span>;
     }
-    type: string = "";
 
+    @computed get renderFieldKey() { return CollectionSchemaCell.resolvedFieldKey(this.props.rowProps.column.id!, this.props.rowProps.original); }
+    onItemDown = async (e: React.PointerEvent) => {
+        if (this.props.Document._searchDoc) {
+            const doc = Doc.GetProto(this._rowDoc);
+            const aliasdoc = await SearchUtil.GetAliasesOfDocument(doc);
+            const targetContext = aliasdoc.length <= 0 ? undefined : Cast(aliasdoc[0].context, Doc, null);
+            DocumentManager.Instance.jumpToDocument(this._rowDoc, false, () => undefined, targetContext);
+        }
+    };
     renderCellWithType(type: string | undefined) {
         const dragRef: React.RefObject<HTMLDivElement> = React.createRef();
 
-        const props: FieldViewProps = {
-            Document: this.props.rowProps.original,
-            DataDoc: this.props.rowProps.original,
-            LibraryPath: [],
-            dropAction: "alias",
-            bringToFront: emptyFunction,
-            rootSelected: returnFalse,
-            fieldKey: this.props.rowProps.column.id as string,
-            docFilters: returnEmptyFilter,
-            searchFilterDocs: returnEmptyDoclist,
-            ContainingCollectionView: this.props.CollectionView,
-            ContainingCollectionDoc: this.props.CollectionView && this.props.CollectionView.props.Document,
-            isSelected: returnFalse,
-            select: emptyFunction,
-            renderDepth: this.props.renderDepth + 1,
-            ScreenToLocalTransform: Transform.Identity,
-            focus: emptyFunction,
-            active: returnFalse,
-            whenActiveChanged: emptyFunction,
-            PanelHeight: returnZero,
-            PanelWidth: returnZero,
-            NativeHeight: returnZero,
-            NativeWidth: returnZero,
-            addDocTab: this.props.addDocTab,
-            pinToPres: this.props.pinToPres,
-            ContentScaling: returnOne
-        };
+        const fieldKey = this.renderFieldKey;
+        const field = this._rowDoc[fieldKey];
 
-        let matchedKeys = [props.fieldKey];
-        if (props.fieldKey.startsWith("*")) {
-            const allKeys = Array.from(Object.keys(props.Document));
-            allKeys.push(...Array.from(Object.keys(Doc.GetProto(props.Document))));
-            matchedKeys = allKeys.filter(key => key.includes(props.fieldKey.substring(1)));
-        }
-        const fieldKey = matchedKeys.length ? matchedKeys[0] : props.fieldKey;
-        const field = props.Document[fieldKey];
-        const doc = FieldValue(Cast(field, Doc));
-        const fieldIsDoc = (type === "document" && typeof field === "object") || (typeof field === "object" && doc);
-
-        const onItemDown = async (e: React.PointerEvent) => {
-            if (this.props.Document._searchDoc) {
-                const doc = Doc.GetProto(this.props.rowProps.original);
-                const aliasdoc = await SearchUtil.GetAliasesOfDocument(doc);
-                let targetContext = undefined;
-                if (aliasdoc.length > 0) {
-                    targetContext = Cast(aliasdoc[0].context, Doc) as Doc;
-                }
-                DocumentManager.Instance.jumpToDocument(this.props.rowProps.original, false, undefined, targetContext);
-            }
-            else {
-                fieldIsDoc &&
-                    SetupDrag(this._focusRef,
-                        () => this._document[props.fieldKey] instanceof Doc ? this._document[props.fieldKey] : this._document,
-                        this._document[props.fieldKey] instanceof Doc ? (doc: Doc | Doc[], target: Doc | undefined, addDoc: (newDoc: Doc | Doc[]) => any) => addDoc(doc) : this.props.moveDocument,
-                        this._document[props.fieldKey] instanceof Doc ? "alias" : this.props.Document.schemaDoc ? "copy" : undefined)(e);
-            }
-        };
         const onPointerEnter = (e: React.PointerEvent): void => {
             if (e.buttons === 1 && SnappingManager.GetIsDragging() && (type === "document" || type === undefined)) {
                 dragRef.current!.className = "collectionSchemaView-cellContainer doc-drag-over";
@@ -252,31 +185,8 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             dragRef.current!.className = "collectionSchemaView-cellContainer";
         };
 
-        let contents: any = "incorrect type";
-        if (type === undefined) contents = field === undefined ? undefined : Field.toString(field as Field);//StrCast(field) === "" ? "--" : <FieldView {...props} fieldKey={fieldKey} />;
-        if (type === "number") contents = typeof field === "number" ? NumCast(field) : "--" + typeof field + "--";
-        if (type === "string") {
-            fieldKey === "text" ?
-                contents = Cast(field, RichTextField)?.Text :
-                contents = typeof field === "string" ? (StrCast(field) === "" ? "--" : StrCast(field)) : "--" + typeof field + "--";
-        }
-        if (type === "boolean") contents = typeof field === "boolean" ? (BoolCast(field) ? "true" : "false") : "--" + typeof field + "--";
-        if (type === "document") {
-            const doc = FieldValue(Cast(field, Doc));
-            contents = typeof field === "object" ? doc ? StrCast(doc.title) === "" ? "--" : StrCast(doc.title) : `--${typeof field}--` : `--${typeof field}--`;
-        }
-        if (type === "image") {
-            const image = FieldValue(Cast(field, ImageField));
-            const doc = FieldValue(Cast(field, Doc));
-            contents = typeof field === "object" ? doc ? StrCast(doc.title) === "" ? "--" : StrCast(doc.title) : `--${typeof field}--` : `--${typeof field}--`;
-        }
-        if (type === "list") {
-            contents = typeof field === "object" ? doc ? StrCast(field) === "" ? "--" : StrCast(field) : `--${typeof field}--` : `--${typeof field}--`;
-        }
-        if (type === "date") {
-            contents = typeof field === "object" ? doc ? StrCast(field) === "" ? "--" : StrCast(field) : `--${typeof field}--` : `--${typeof field}--`;
-        }
-
+        let contents = Field.toString(field as Field);
+        contents = contents === "" ? "--" : contents;
 
         let className = "collectionSchemaView-cellWrapper";
         if (this._isEditing) className += " editing";
@@ -284,11 +194,8 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
         if (this.props.isFocused && !this.props.isEditable) className += " inactive";
 
         const positions = [];
-        let cfield = props.Document[props.fieldKey];
-        this.type = props.fieldKey;
         if (StrCast(this.props.Document._searchString).toLowerCase() !== "") {
-            let term = (cfield instanceof Promise) ? "...promise pending..." : Field.toString(cfield as Field);
-            term = term.toLowerCase();
+            let term = (field instanceof Promise) ? "...promise pending..." : contents.toLowerCase();
             const search = StrCast(this.props.Document._searchString).toLowerCase();
             let start = term.indexOf(search);
             let tally = 0;
@@ -305,125 +212,55 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
                 positions.pop();
             }
         }
-        let search = false;
-        if (this.props.Document._searchDoc) {
-            search = true;
-        }
-
         const placeholder = type === "number" ? "0" : contents === "" ? "--" : "undefined";
         return (
-            <div className="collectionSchemaView-cellContainer" style={{ cursor: fieldIsDoc ? "grab" : "auto" }}
+            <div className="collectionSchemaView-cellContainer" style={{ cursor: field instanceof Doc ? "grab" : "auto" }}
                 ref={dragRef} onPointerDown={this.onPointerDown} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}>
-                <div className={className} ref={this._focusRef} onPointerDown={onItemDown} tabIndex={-1}>
-                    <div className="collectionSchemaView-cellContents"
-                        ref={type === undefined || type === "document" ? this.dropRef : null}>
-                        {!search ?
+                <div className={className} ref={this._focusRef} tabIndex={-1}>
+                    <div className="collectionSchemaView-cellContents" ref={type === undefined || type === "document" ? this.dropRef : null}>
+                        {!this.props.Document._searchDoc ?
                             <EditableView
-                                positions={positions.length > 0 ? positions : undefined}
-                                search={Cast(this.props.Document._searchString, "string", null)}
                                 editing={this._isEditing}
                                 isEditingCallback={this.isEditingCallback}
                                 display={"inline"}
                                 contents={contents}
-                                highlight={positions.length > 0 ? true : undefined}
-                                //contents={StrCast(contents)}
                                 height={"auto"}
                                 maxHeight={Number(MAX_ROW_HEIGHT)}
                                 placeholder={placeholder}
-                                bing={() => {
-                                    const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
-                                    if (cfield !== undefined) {
-                                        // if (typeof(cfield)===RichTextField)
-                                        const a = cfield as RichTextField;
-                                        const b = cfield as DateField;
-                                        console.log(b);
-                                        if (a.Text !== undefined) {
-                                            return (a.Text);
-                                        }
-                                        else if (b.toString() !== undefined) {
-                                            return b.toString();
-                                        }
-                                        else if (StrCast(cfield)) {
-                                            return StrCast(cfield);
-                                        }
-                                        else {
-                                            return String(NumCast(cfield));
-                                        }
-                                    }
-                                }}
                                 GetValue={() => {
-                                    if (type === "number" && (contents === 0 || contents === "0")) {
-                                        return "0";
-                                    } else {
-                                        const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
-                                        if (type === "number") {
-                                            return StrCast(cfield);
-                                        }
-                                        const cscript = cfield instanceof ComputedField ? cfield.script.originalScript : undefined;
-                                        const cfinalScript = cscript?.split("return")[cscript.split("return").length - 1];
-                                        const val = cscript !== undefined ? (cfinalScript?.endsWith(";") ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) :
-                                            Field.IsField(cfield) ? Field.toScriptString(cfield) : "";
-                                        return val;
-
-                                    }
-
+                                    const cfield = ComputedField.WithoutComputed(() => FieldValue(field));
+                                    const cscript = cfield instanceof ComputedField ? cfield.script.originalScript : undefined;
+                                    const cfinalScript = cscript?.split("return")[cscript.split("return").length - 1];
+                                    return cscript ? (cfinalScript?.endsWith(";") ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) :
+                                        Field.IsField(cfield) ? Field.toScriptString(cfield) : "";
                                 }}
                                 SetValue={action((value: string) => {
                                     let retVal = false;
-
                                     if (value.startsWith(":=") || value.startsWith("=:=")) {
                                         const script = value.substring(value.startsWith("=:=") ? 3 : 2);
-                                        retVal = this.props.setComputed(script, value.startsWith(":=") ? Doc.GetProto(props.Document) : props.Document, this.props.rowProps.column.id!, this.props.row, this.props.col);
+                                        retVal = this.props.setComputed(script, value.startsWith(":=") ? Doc.GetProto(this.props.Document) : this.props.Document, this.renderFieldKey, this.props.row, this.props.col);
                                     } else {
                                         const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
-                                        if (script.compiled) {
-                                            retVal = this.applyToDoc(props.Document, this.props.row, this.props.col, script.run);
-                                        }
-
+                                        script.compiled && (retVal = this.applyToDoc(this._rowDoc, this.props.row, this.props.col, script.run));
                                     }
                                     if (retVal) {
                                         this._isEditing = false; // need to set this here. otherwise, the assignment of the field will invalidate & cause render() to be called with the wrong value for 'editing'
                                         this.props.setIsEditing(false);
                                     }
                                     return retVal;
-
-                                    //return true;
                                 })}
                                 OnFillDown={async (value: string) => {
                                     const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
-                                    if (script.compiled) {
-                                        DocListCast(this.props.Document[this.props.fieldKey]).
-                                            forEach((doc, i) => value.startsWith(":=") ?
-                                                this.props.setComputed(value.substring(2), doc, this.props.rowProps.column.id!, i, this.props.col) :
-                                                this.applyToDoc(doc, i, this.props.col, script.run));
-                                    }
+                                    script.compiled && DocListCast(field).
+                                        forEach((doc, i) => value.startsWith(":=") ?
+                                            this.props.setComputed(value.substring(2), doc, this.renderFieldKey, i, this.props.col) :
+                                            this.applyToDoc(doc, i, this.props.col, script.run));
                                 }}
                             />
                             :
-                            this.returnHighlights(() => {
-                                const dateCheck: Date | undefined = this.props.rowProps.original[this.props.rowProps.column.id as string] instanceof DateField ? DateCast(this.props.rowProps.original[this.props.rowProps.column.id as string]).date : undefined;
-                                if (dateCheck !== undefined) {
-                                    cfield = dateCheck.toLocaleString();
-                                }
-                                if (props.fieldKey === "context") {
-                                    cfield = this.contents;
-                                }
-                                if (props.fieldKey === "*lastModified") {
-                                    if (FieldValue(props.Document["data-lastModified"]) !== undefined) {
-                                        const d = ComputedField.WithoutComputed(() => FieldValue(props.Document["data-lastModified"])) as DateField;
-                                        cfield = d.date.toLocaleString();
-                                    }
-
-                                    else if (FieldValue(props.Document["text-lastModified"]) !== undefined) {
-                                        const d = ComputedField.WithoutComputed(() => FieldValue(props.Document["text-lastModified"])) as DateField;
-                                        cfield = d.date.toLocaleString();
-                                    }
-                                }
-                                return Field.toString(cfield as Field);
-                            }, positions)
+                            this.returnHighlights(contents, positions)
                         }
                     </div >
-                    {/* {fieldIsDoc ? docExpander : null} */}
                 </div>
             </div>
         );
@@ -433,43 +270,36 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
 }
 
 @observer
-export class CollectionSchemaNumberCell extends CollectionSchemaCell {
-    render() { return this.renderCellWithType("number"); }
-}
+export class CollectionSchemaNumberCell extends CollectionSchemaCell { render() { return this.renderCellWithType("number"); } }
 
 @observer
-export class CollectionSchemaBooleanCell extends CollectionSchemaCell {
-    render() { return this.renderCellWithType("boolean"); }
-}
+export class CollectionSchemaBooleanCell extends CollectionSchemaCell { render() { return this.renderCellWithType("boolean"); } }
 
 @observer
-export class CollectionSchemaStringCell extends CollectionSchemaCell {
-    render() { return this.renderCellWithType("string"); }
-}
+export class CollectionSchemaStringCell extends CollectionSchemaCell { render() { return this.renderCellWithType("string"); } }
 
 @observer
 export class CollectionSchemaDateCell extends CollectionSchemaCell {
-    @observable private _date: Date = this.props.rowProps.original[this.props.rowProps.column.id as string] instanceof DateField ? DateCast(this.props.rowProps.original[this.props.rowProps.column.id as string]).date :
-        this.props.rowProps.original[this.props.rowProps.column.id as string] instanceof Date ? this.props.rowProps.original[this.props.rowProps.column.id as string] : new Date();
+    @computed get _date(): Opt<DateField> { return this._rowDoc[this.renderFieldKey] instanceof DateField ? DateCast(this._rowDoc[this.renderFieldKey]) : undefined; }
 
     @action
     handleChange = (date: any) => {
-        this._date = date;
         // const script = CompileScript(date.toString(), { requiredType: "Date", addReturn: true, params: { this: Doc.name } });
         // if (script.compiled) {
         //     this.applyToDoc(this._document, this.props.row, this.props.col, script.run);
         // } else {
         // ^ DateCast is always undefined for some reason, but that is what the field should be set to
-        this._document[this.props.rowProps.column.id as string] = date as Date;
+        this._rowDoc[this.renderFieldKey] = new DateField(date as Date);
         //}
     }
 
     render() {
-        return <DatePicker
-            selected={this._date}
-            onSelect={date => this.handleChange(date)}
-            onChange={date => this.handleChange(date)}
-        />;
+        return !this.props.isFocused ? <span onPointerDown={this.onPointerDown}>{this._date ? Field.toString(this._date as Field) : "--"}</span> :
+            <DatePicker
+                selected={this._date?.date || new Date}
+                onSelect={date => this.handleChange(date)}
+                onChange={date => this.handleChange(date)}
+            />;
     }
 }
 
@@ -478,45 +308,11 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell {
 
     _overlayDisposer?: () => void;
 
-    private prop: FieldViewProps = {
-        Document: this.props.rowProps.original,
-        DataDoc: this.props.rowProps.original,
-        LibraryPath: [],
-        dropAction: "alias",
-        bringToFront: emptyFunction,
-        rootSelected: returnFalse,
-        fieldKey: this.props.rowProps.column.id as string,
-        ContainingCollectionView: this.props.CollectionView,
-        ContainingCollectionDoc: this.props.CollectionView && this.props.CollectionView.props.Document,
-        isSelected: returnFalse,
-        select: emptyFunction,
-        renderDepth: this.props.renderDepth + 1,
-        ScreenToLocalTransform: Transform.Identity,
-        focus: emptyFunction,
-        active: returnFalse,
-        whenActiveChanged: emptyFunction,
-        PanelHeight: returnZero,
-        PanelWidth: returnZero,
-        NativeHeight: returnZero,
-        NativeWidth: returnZero,
-        addDocTab: this.props.addDocTab,
-        pinToPres: this.props.pinToPres,
-        ContentScaling: returnOne,
-        docFilters: returnEmptyFilter,
-        searchFilterDocs: returnEmptyDoclist,
-    };
-    @observable private _field = this.prop.Document[this.prop.fieldKey];
-    @observable private _doc = FieldValue(Cast(this._field, Doc));
-    @observable private _docTitle = this._doc?.title;
-    @observable private _preview = false;
-    @computed get previewWidth() { return () => NumCast(this.props.Document.schemaPreviewWidth); }
-    @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); }
-    @computed get tableWidth() { return this.prop.PanelWidth() - 2 * this.borderWidth - 4 - this.previewWidth(); }
+    @computed get _doc() { return FieldValue(Cast(this._rowDoc[this.renderFieldKey], Doc)); }
 
     @action
     onSetValue = (value: string) => {
-        this._docTitle = value;
-        //this.prop.Document[this.prop.fieldKey] = this._text;
+        this._doc && (Doc.GetProto(this._doc).title = value);
 
         const script = CompileScript(value, {
             addReturn: true,
@@ -526,46 +322,22 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell {
 
         const results = script.compiled && script.run();
         if (results && results.success) {
-            this._doc = results.result;
-            this._document[this.prop.fieldKey] = results.result;
-            this._docTitle = this._doc?.title;
-
+            this._rowDoc[this.renderFieldKey] = results.result;
             return true;
         }
         return false;
     }
 
+    componentWillUnmount() { this.onBlur(); }
+
+    onBlur = () => { this._overlayDisposer?.(); }
     onFocus = () => {
-        this._overlayDisposer?.();
+        this.onBlur();
         this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
     }
 
     @action
-    onOpenClick = () => {
-        this._preview = false;
-        if (this._doc) {
-            this.props.addDocTab(this._doc, "onRight");
-            return true;
-        }
-        return false;
-    }
-
-    @action
-    showPreview = (bool: boolean, e: any) => {
-        if (this._isEditing) {
-            this._preview = false;
-        } else {
-            if (bool) {
-                this.props.showDoc(this._doc, this.prop.DataDoc, e.clientX, e.clientY);
-            } else {
-                this.props.showDoc(undefined);
-            }
-        }
-    }
-
-    @action
-    isEditingCalling = (isEditing: boolean): void => {
-        this.showPreview(false, "");
+    isEditingCallback = (isEditing: boolean): void => {
         document.removeEventListener("keydown", this.onKeyDown);
         isEditing && document.addEventListener("keydown", this.onKeyDown);
         this._isEditing = isEditing;
@@ -573,201 +345,80 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell {
         this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
     }
 
-    onDown = (e: any) => {
-        this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
-        this.props.setPreviewDoc(this.props.rowProps.original);
-
-        let url: string;
-        if (url = StrCast(this.props.rowProps.row.href)) {
-            try {
-                new URL(url);
-                const temp = window.open(url)!;
-                temp.blur();
-                window.focus();
-            } catch { }
-        }
-
-        const field = this.props.rowProps.original[this.props.rowProps.column.id!];
-        const doc = FieldValue(Cast(field, Doc));
-        if (typeof field === "object" && doc) this.props.setPreviewDoc(doc);
-
-        this.showPreview(true, e);
-
-    }
-
     render() {
-        if (typeof this._field === "object" && this._doc && this._docTitle) {
-            return (
-                <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1}
-                    onPointerDown={this.onDown}
-                    onPointerEnter={(e) => { this.showPreview(true, e); }}
-                    onPointerLeave={(e) => { this.showPreview(false, e); }}
+        return !this._doc ? this.renderCellWithType("document") :
+            <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1}
+                onPointerDown={this.onPointerDown}
+            >
+                <div className="collectionSchemaView-cellContents-document"
+                    style={{ padding: "5.9px" }}
+                    ref={this.dropRef}
+                    onFocus={this.onFocus}
+                    onBlur={this.onBlur}
                 >
-
-                    <div className="collectionSchemaView-cellContents-document"
-                        style={{ padding: "5.9px" }}
-                        ref={this.dropRef}
-                        onFocus={this.onFocus}
-                        onBlur={() => this._overlayDisposer?.()}
-                    >
-
-                        <EditableView
-                            editing={this._isEditing}
-                            isEditingCallback={this.isEditingCalling}
-                            display={"inline"}
-                            contents={this._docTitle}
-                            height={"auto"}
-                            maxHeight={Number(MAX_ROW_HEIGHT)}
-                            GetValue={() => {
-                                return StrCast(this._docTitle);
-                            }}
-                            SetValue={action((value: string) => {
-                                this.onSetValue(value);
-                                this.showPreview(false, "");
-                                return true;
-                            })}
-                        />
-                    </div >
-                    <div onClick={this.onOpenClick} className="collectionSchemaView-cellContents-docButton">
-                        <FontAwesomeIcon icon="external-link-alt" size="lg" ></FontAwesomeIcon> </div>
+                    <EditableView
+                        editing={this._isEditing}
+                        isEditingCallback={this.isEditingCallback}
+                        display={"inline"}
+                        contents={this._doc.title || "--"}
+                        height={"auto"}
+                        maxHeight={Number(MAX_ROW_HEIGHT)}
+                        GetValue={() => StrCast(this._doc?.title)}
+                        SetValue={action((value: string) => {
+                            this.onSetValue(value);
+                            return true;
+                        })}
+                    />
+                </div >
+                <div onClick={() => this._doc && this.props.addDocTab(this._doc, "onRight")} className="collectionSchemaView-cellContents-docButton">
+                    <FontAwesomeIcon icon="external-link-alt" size="lg" />
                 </div>
-            );
-        } else {
-            return this.renderCellWithType("document");
-        }
+            </div>;
     }
 }
 
 @observer
 export class CollectionSchemaImageCell extends CollectionSchemaCell {
-    // render() {
-    //     return this.renderCellWithType("image");
-    // }
-
-    choosePath(url: URL, dataDoc: any) {
-        const lower = url.href.toLowerCase();
-        if (url.protocol === "data") {
-            return url.href;
-        } else if (url.href.indexOf(window.location.origin) === -1) {
-            return Utils.CorsProxy(url.href);
-        } else if (!/\.(png|jpg|jpeg|gif|webp)$/.test(lower)) {
-            return url.href;//Why is this here
-        }
+
+    choosePath(url: URL) {
+        if (url.protocol === "data") return url.href;
+        if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href);
+        if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href;//Why is this here
+
         const ext = path.extname(url.href);
-        const _curSuffix = "_o";
-        return url.href.replace(ext, _curSuffix + ext);
+        return url.href.replace(ext, "_o" + path.extname(url.href));
     }
 
     render() {
-        const props: FieldViewProps = {
-            Document: this.props.rowProps.original,
-            DataDoc: this.props.rowProps.original,
-            LibraryPath: [],
-            dropAction: "alias",
-            bringToFront: emptyFunction,
-            rootSelected: returnFalse,
-            fieldKey: this.props.rowProps.column.id as string,
-            ContainingCollectionView: this.props.CollectionView,
-            ContainingCollectionDoc: this.props.CollectionView && this.props.CollectionView.props.Document,
-            isSelected: returnFalse,
-            select: emptyFunction,
-            renderDepth: this.props.renderDepth + 1,
-            ScreenToLocalTransform: Transform.Identity,
-            focus: emptyFunction,
-            active: returnFalse,
-            whenActiveChanged: emptyFunction,
-            PanelHeight: returnZero,
-            PanelWidth: returnZero,
-            NativeHeight: returnZero,
-            NativeWidth: returnZero,
-            addDocTab: this.props.addDocTab,
-            pinToPres: this.props.pinToPres,
-            ContentScaling: returnOne,
-            docFilters: returnEmptyFilter,
-            searchFilterDocs: returnEmptyDoclist,
-        };
+        const field = Cast(this._rowDoc[this.renderFieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc
+        const alts = DocListCast(this._rowDoc[this.renderFieldKey + "-alternates"]); // retrieve alternate documents that may be rendered as alternate images
+        const altpaths = alts.map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url).filter(url => url).map(url => this.choosePath(url)); // access the primary layout data of the alternate documents
+        const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths;
+        const url = paths.length ? paths : [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")];
 
-        let image = true;
-        let url = [];
-        if (props.DataDoc) {
-            const field = Cast(props.DataDoc[props.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc
-            const alts = DocListCast(props.DataDoc[props.fieldKey + "-alternates"]); // retrieve alternate documents that may be rendered as alternate images
-            const altpaths = alts.map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url).filter(url => url).map(url => this.choosePath(url, props.DataDoc)); // access the primary layout data of the alternate documents
-            const paths = field ? [this.choosePath(field.url, props.DataDoc), ...altpaths] : altpaths;
-            if (paths.length) {
-                url = paths;
-            } else {
-                url = [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")];
-                image = false;
-            }
-            //url = paths.length ? paths : [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")];
-        } else {
-            url = [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")];
-            image = false;
-        }
+        const heightToWidth = NumCast(this._rowDoc._nativeHeight) / NumCast(this._rowDoc._nativeWidth);
+        let width = Math.min(75, this.props.rowProps.width);
+        const height = Math.min(75, width * heightToWidth);
+        width = height / heightToWidth;
 
-        const heightToWidth = NumCast(props.DataDoc?._nativeHeight) / NumCast(props.DataDoc?._nativeWidth);
-        const height = this.props.rowProps.width * heightToWidth;
-
-        if (props.fieldKey === "data") {
-            if (url !== []) {
-                const reference = React.createRef<HTMLDivElement>();
-                return (
-                    <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
-                        <div className="collectionSchemaView-cellContents" key={this._document[Id]} ref={reference}>
-                            <img src={url[0]} width={image ? this.props.rowProps.width : "30px"}
-                                height={image ? height : "30px"} />
-                        </div >
-                    </div>
-                );
-
-            } else {
-                return this.renderCellWithType("image");
-            }
-        } else {
-            return this.renderCellWithType("image");
-        }
+        const reference = React.createRef<HTMLDivElement>();
+        return <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
+            <div className="collectionSchemaView-cellContents" key={this._rowDoc[Id]} ref={reference}>
+                <img src={url[0]}
+                    width={paths.length ? width : "20px"}
+                    height={paths.length ? height : "20px"} />
+            </div >
+        </div>;
     }
 }
 
 
-
-
-
 @observer
 export class CollectionSchemaListCell extends CollectionSchemaCell {
-
     _overlayDisposer?: () => void;
 
-    private prop: FieldViewProps = {
-        Document: this.props.rowProps.original,
-        DataDoc: this.props.rowProps.original,
-        LibraryPath: [],
-        dropAction: "alias",
-        bringToFront: emptyFunction,
-        rootSelected: returnFalse,
-        fieldKey: this.props.rowProps.column.id as string,
-        ContainingCollectionView: this.props.CollectionView,
-        ContainingCollectionDoc: this.props.CollectionView && this.props.CollectionView.props.Document,
-        isSelected: returnFalse,
-        select: emptyFunction,
-        renderDepth: this.props.renderDepth + 1,
-        ScreenToLocalTransform: Transform.Identity,
-        focus: emptyFunction,
-        active: returnFalse,
-        whenActiveChanged: emptyFunction,
-        PanelHeight: returnZero,
-        PanelWidth: returnZero,
-        NativeHeight: returnZero,
-        NativeWidth: returnZero,
-        addDocTab: this.props.addDocTab,
-        pinToPres: this.props.pinToPres,
-        ContentScaling: returnOne,
-        docFilters: returnEmptyFilter,
-        searchFilterDocs: returnEmptyDoclist,
-    };
-    @observable private _field = this.prop.Document[this.prop.fieldKey];
-    @observable private _optionsList = this._field as List<any>;
+    @computed get _field() { return this._rowDoc[this.renderFieldKey]; }
+    @computed get _optionsList() { return this._field as List<any>; }
     @observable private _opened = false;
     @observable private _text = "select an item";
     @observable private _selectedNum = 0;
@@ -777,7 +428,7 @@ export class CollectionSchemaListCell extends CollectionSchemaCell {
         // change if its a document
         this._optionsList[this._selectedNum] = this._text = value;
 
-        (this.prop.Document[this.prop.fieldKey] as List<any>).splice(this._selectedNum, 1, value);
+        (this._field as List<any>).splice(this._selectedNum, 1, value);
     }
 
     @action
@@ -792,33 +443,22 @@ export class CollectionSchemaListCell extends CollectionSchemaCell {
     }
 
     render() {
-        let type = "list";
         let link = false;
         const reference = React.createRef<HTMLDivElement>();
 
-        if (typeof this._field === "object" && this._optionsList[0]) {
-            const options = !this._opened ? (null) : <div>
-                {this._optionsList.map((element, index) => {
-                    let title = "";
-                    if (element instanceof Doc) {
-                        type = "document";
-                        if (this.prop.fieldKey.toLowerCase() === "links") {
-                            link = true;
-                            type = "link";
-                        }
-                        title = StrCast(element.title);
-                    }
-                    return <div className="collectionSchemaView-dropdownOption" style={{ padding: "6px" }}
-                        onPointerDown={(e) => this.onSelected(StrCast(element), index)} >
-                        {element}
-                        {title}
-                    </div>;
-                })}
-            </div>;
+        if (this._optionsList?.length) {
+            const options = !this._opened ? (null) :
+                <div>
+                    {this._optionsList.map((element, index) => {
+                        const val = Field.toString(element);
+                        return <div className="collectionSchemaView-dropdownOption" key={index} style={{ padding: "6px" }} onPointerDown={(e) => this.onSelected(StrCast(element), index)} >
+                            {val}
+                        </div>;
+                    })}
+                </div>;
 
             const plainText = <div style={{ padding: "5.9px" }}>{this._text}</div>;
-            const textarea = <div className="collectionSchemaView-cellContents" key={this.prop.Document[Id]} style={{ padding: "5.9px" }}
-                ref={type === undefined || type === "document" ? this.dropRef : null} >
+            const textarea = <div className="collectionSchemaView-cellContents" key={this._rowDoc[Id]} style={{ padding: "5.9px" }} ref={this.dropRef} >
                 <EditableView
                     editing={this._isEditing}
                     isEditingCallback={this.isEditingCallback}
@@ -838,11 +478,11 @@ export class CollectionSchemaListCell extends CollectionSchemaCell {
             //☰
             return (
                 <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
-                    <div className="collectionSchemaView-cellContents" key={this._document[Id]} ref={reference}>
+                    <div className="collectionSchemaView-cellContents" key={this._rowDoc[Id]} ref={reference}>
                         <div className="collectionSchemaView-dropDownWrapper">
                             <button type="button" className="collectionSchemaView-dropdownButton" style={{ right: "length", position: "relative" }}
                                 onClick={action(e => this._opened = !this._opened)} >
-                                <FontAwesomeIcon icon={this._opened ? "caret-up" : "caret-down"} size="lg" />
+                                <FontAwesomeIcon icon={this._opened ? "caret-up" : "caret-down"} size="sm" />
                             </button>
                             <div className="collectionSchemaView-dropdownText"> {link ? plainText : textarea} </div>
                         </div>
@@ -858,26 +498,13 @@ export class CollectionSchemaListCell extends CollectionSchemaCell {
 
 @observer
 export class CollectionSchemaCheckboxCell extends CollectionSchemaCell {
-    @observable private _isChecked: boolean = typeof this.props.rowProps.original[this.props.rowProps.column.id as string] === "boolean" ? BoolCast(this.props.rowProps.original[this.props.rowProps.column.id as string]) : false;
-
-    @action
-    toggleChecked = (e: React.ChangeEvent<HTMLInputElement>) => {
-        this._isChecked = e.target.checked;
-        const script = CompileScript(e.target.checked.toString(), { requiredType: "boolean", addReturn: true, params: { this: Doc.name } });
-        script.compiled && this.applyToDoc(this._document, this.props.row, this.props.col, script.run);
-    }
+    @computed get _isChecked() { return BoolCast(this._rowDoc[this.renderFieldKey]); }
 
     render() {
         const reference = React.createRef<HTMLDivElement>();
-        const onItemDown = (e: React.PointerEvent) => {
-            (!this.props.CollectionView?.props.isSelected() ? undefined :
-                SetupDrag(reference, () => this._document, this.props.moveDocument, this.props.Document.schemaDoc ? "copy" : undefined)(e));
-        };
         return (
             <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
-                <div className="collectionSchemaView-cellContents" onPointerDown={onItemDown} key={this._document[Id]} ref={reference}>
-                    <input type="checkbox" checked={this._isChecked} onChange={this.toggleChecked} />
-                </div >
+                <input type="checkbox" checked={this._isChecked} onChange={e => this._rowDoc[this.renderFieldKey] = e.target.checked} />
             </div>
         );
     }
@@ -887,23 +514,14 @@ export class CollectionSchemaCheckboxCell extends CollectionSchemaCell {
 @observer
 export class CollectionSchemaButtons extends CollectionSchemaCell {
     render() {
-        const doc = this.props.rowProps.original;
-        const searchMatch = (backward: boolean = true) => Doc.SearchMatchNext(doc, backward);
-        // const reference = React.createRef<HTMLDivElement>();
-        // const onItemDown = (e: React.PointerEvent) => {
-        //     (!this.props.CollectionView || !this.props.CollectionView.props.isSelected() ? undefined :
-        //         SetupDrag(reference, () => this._document, this.props.moveDocument, this.props.Document.schemaDoc ? "copy" : undefined)(e));
-        // };
-        return !this.props.Document._searchDoc ? <></>
-            : [DocumentType.PDF, DocumentType.RTF].includes(StrCast(doc.type) as DocumentType) ?
-                <div style={{ paddingTop: 8, paddingLeft: 3, }} >
-                    <button style={{ padding: 2, left: 77 }} onClick={() => searchMatch(true)}>
-                        <FontAwesomeIcon icon="arrow-up" size="sm" />
-                    </button>
-                    <button style={{ padding: 2 }} onClick={() => searchMatch(false)} >
-                        <FontAwesomeIcon icon="arrow-down" size="sm" />
-                    </button>
-                </div> :
-                <></>;
+        return !this._rowDoc._searchDoc || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this._rowDoc.type) as DocumentType) ? <></> :
+            <div style={{ paddingTop: 8, paddingLeft: 3 }} >
+                <button style={{ padding: 2, left: 77 }} onClick={() => Doc.SearchMatchNext(this._rowDoc, true)}>
+                    <FontAwesomeIcon icon="arrow-up" size="sm" />
+                </button>
+                <button style={{ padding: 2 }} onClick={() => Doc.SearchMatchNext(this._rowDoc, false)} >
+                    <FontAwesomeIcon icon="arrow-down" size="sm" />
+                </button>
+            </div>;
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 828cdd282..bf81e4509 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -157,7 +157,10 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 }
 
                 if (effectiveAcl === AclAddonly) {
-                    added.map(doc => Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc));
+                    added.map(doc => {
+                        Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc);
+                        doc.context = this.props.Document;
+                    });
                 }
                 else {
                     added.map(doc => {
@@ -180,8 +183,6 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                     });
                     (targetDataDoc[this.props.fieldKey] as List<Doc>).push(...added);
                     targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
-                    const lastModified = "lastModified";
-                    targetDataDoc[lastModified] = new DateField(new Date(Date.now()));
                 }
             }
         }
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index 7f8ccf6ac..28242a5aa 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -5,7 +5,7 @@ import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
 import ReactTable, { CellInfo, Column, ComponentPropsGetterR, Resize, SortingRule } from "react-table";
 import "react-table/react-table.css";
-import { Doc, DocListCast, Field, Opt } from "../../../fields/Doc";
+import { Doc, DocListCast, Field, Opt, AclPrivate, AclReadonly, DataSym } from "../../../fields/Doc";
 import { Id } from "../../../fields/FieldSymbols";
 import { List } from "../../../fields/List";
 import { listSpec } from "../../../fields/Schema";
@@ -27,6 +27,9 @@ import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC";
 import "./CollectionSchemaView.scss";
 import { CollectionView } from "./CollectionView";
 import { DocumentType } from "../../documents/DocumentTypes";
+import { GetEffectiveAcl } from "../../../fields/util";
+import { DateField } from "../../../fields/DateField";
+import { ImageField } from "../../../fields/URLField";
 
 
 enum ColumnType {
@@ -227,7 +230,8 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                         showDoc: this.showDoc,
                     };
 
-                    switch (this.getColumnType(col)) {
+
+                    switch (this.getColumnType(col, rowProps.original, rowProps.column.id)) {
                         case ColumnType.Number: return <CollectionSchemaNumberCell {...props} />;
                         case ColumnType.String: return <CollectionSchemaStringCell {...props} />;
                         case ColumnType.Boolean: return <CollectionSchemaCheckboxCell {...props} />;
@@ -235,7 +239,8 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                         case ColumnType.Image: return <CollectionSchemaImageCell {...props} />;
                         case ColumnType.List: return <CollectionSchemaListCell {...props} />;
                         case ColumnType.Date: return <CollectionSchemaDateCell {...props} />;
-                        default: return <CollectionSchemaCell {...props} />;
+                        default:
+                            return <CollectionSchemaCell {...props} />;
                     }
                 },
                 minWidth: 200,
@@ -295,7 +300,15 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     }
 
     tableAddDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => {
-        return Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before);
+        const tableDoc = this.props.Document[DataSym];
+        const effectiveAcl = GetEffectiveAcl(tableDoc);
+
+        if (effectiveAcl !== AclPrivate && effectiveAcl !== AclReadonly) {
+            doc.context = this.props.Document;
+            tableDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+            return Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before);
+        }
+        return false;
     }
 
     private getTrProps: ComponentPropsGetterR = (state, rowInfo) => {
@@ -380,7 +393,14 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     }
 
     @action
-    getColumnType = (column: SchemaHeaderField): ColumnType => {
+    getColumnType = (column: SchemaHeaderField, doc?: Doc, field?: string): ColumnType => {
+        if (doc && field && column.type === ColumnType.Any) {
+            const val = doc[CollectionSchemaCell.resolvedFieldKey(field, doc)];
+            if (val instanceof ImageField) return ColumnType.Image;
+            if (val instanceof Doc) return ColumnType.Doc;
+            if (val instanceof DateField) return ColumnType.Date;
+            if (val instanceof List) return ColumnType.List;
+        }
         if (column.type && column.type !== 0) {
             return column.type;
         }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 549610e53..491c7e7e0 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1408,7 +1408,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
                     viewDefDivClick={this.props.viewDefDivClick}
                     zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
                     {this.children}
-                </CollectionFreeFormViewPannableContents></div>
+                </CollectionFreeFormViewPannableContents>
+            </div>
             {this.showTimeline ? <Timeline ref={this._timelineRef} {...this.props} /> : (null)}
         </MarqueeView>;
     }
diff --git a/src/fields/DateField.ts b/src/fields/DateField.ts
index bee62663e..48106d978 100644
--- a/src/fields/DateField.ts
+++ b/src/fields/DateField.ts
@@ -20,14 +20,14 @@ export class DateField extends ObjectField {
     }
 
     toString() {
-        return `${this.date.toISOString()}`;
+        return `${this.date.toLocaleString()}`;
     }
 
     [ToScriptString]() {
         return `new DateField(new Date(${this.date.toISOString()}))`;
     }
     [ToString]() {
-        return this.date.toISOString();
+        return this.date.toLocaleString();
     }
 
     getDate() {
diff --git a/src/fields/List.ts b/src/fields/List.ts
index 3601f282b..c9e4bd3c1 100644
--- a/src/fields/List.ts
+++ b/src/fields/List.ts
@@ -324,7 +324,7 @@ class ListImpl<T extends Field> extends ObjectField {
         return `new List([${(this as any).map((field: any) => Field.toScriptString(field))}])`;
     }
     [ToString]() {
-        return "List";
+        return `List(${(this as any).length})`;
     }
 }
 export type List<T extends Field> = ListImpl<T> & (T | (T extends RefField ? Promise<T> : never))[];
diff --git a/src/fields/util.ts b/src/fields/util.ts
index d8523dfa2..9679527e4 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -156,14 +156,17 @@ export enum SharingPermissions {
  */
 export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number, user?: string): symbol {
     if (!target) return AclPrivate;
+
+    // all changes received fromt the server must be processed as Admin
     if (in_prop === UpdatingFromServer || target[UpdatingFromServer]) return AclAdmin;
 
-    if (target[AclSym] && Object.keys(target[AclSym]).length) {
+    // if the current user is the author of the document / the current user is a member of the admin group
+    const userChecked = user || Doc.CurrentUserEmail;
+    if (userChecked === (target.__fields?.author || target.author)) return AclAdmin;
 
-        const userChecked = user || Doc.CurrentUserEmail;
+    if (target[AclSym] && Object.keys(target[AclSym]).length) {
 
-        // if the current user is the author of the document / the current user is a member of the admin group
-        if (userChecked === (target.__fields?.author || target.author) || currentUserGroups.includes("admin")) return AclAdmin;
+        if (currentUserGroups.includes("admin")) return AclAdmin;
 
         // if the ACL is being overriden or the property being modified is one of the playground fields (which can be freely modified)
         if (_overrideAcl || (in_prop && DocServer.PlaygroundFields?.includes(in_prop.toString()))) return AclEdit;
-- 
cgit v1.2.3-70-g09d2


From 6471ccff7dd145d3725492ccccaecc6035e851f2 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 26 Aug 2020 02:30:44 -0400
Subject: fixed warnings.  fixed url / annoation updating when navigating web
 pages.

---
 src/client/views/collections/CollectionMenu.tsx        | 6 +++---
 src/client/views/collections/CollectionSchemaCells.tsx | 6 +++---
 src/client/views/collections/CollectionTreeView.tsx    | 2 +-
 3 files changed, 7 insertions(+), 7 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 2f257d00b..5f40ac59c 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -725,6 +725,8 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
         if (this.selectedDoc) {
             Doc.GetProto(this.selectedDoc).data = new WebField(value);
             Doc.SetInPlace(this.selectedDoc, "title", value, true);
+            const annots = Doc.GetProto(this.selectedDoc)["data-annotations-" + this.urlHash(value)];
+            Doc.GetProto(this.selectedDoc)["data-annotations"] = annots instanceof ObjectField ? ObjectField.MakeCopy(annots) : new List<Doc>([]);
         }
     }
 
@@ -751,9 +753,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
                         }
                         future && (future.length = 0);
                     }
-                    Doc.GetProto(selectedDoc).data = new WebField(URLy);
-                    const annots = Doc.GetProto(selectedDoc)["data-annotations-" + this.urlHash(url)];
-                    Doc.GetProto(selectedDoc)["data-annotations"] = annots instanceof ObjectField ? ObjectField.MakeCopy(annots) : new List<Doc>([]);
+                    this._url = url;
                 }
             }
         } catch (e) {
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 95f425524..18ca29aaa 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -169,7 +169,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             const targetContext = aliasdoc.length <= 0 ? undefined : Cast(aliasdoc[0].context, Doc, null);
             DocumentManager.Instance.jumpToDocument(this._rowDoc, false, () => undefined, targetContext);
         }
-    };
+    }
     renderCellWithType(type: string | undefined) {
         const dragRef: React.RefObject<HTMLDivElement> = React.createRef();
 
@@ -330,7 +330,7 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell {
 
     componentWillUnmount() { this.onBlur(); }
 
-    onBlur = () => { this._overlayDisposer?.(); }
+    onBlur = () => { this._overlayDisposer?.(); };
     onFocus = () => {
         this.onBlur();
         this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
@@ -443,7 +443,7 @@ export class CollectionSchemaListCell extends CollectionSchemaCell {
     }
 
     render() {
-        let link = false;
+        const link = false;
         const reference = React.createRef<HTMLDivElement>();
 
         if (this._optionsList?.length) {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 918377052..5099f0022 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -825,7 +825,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
     whenActiveChanged = (isActive: boolean) => {
         this.props.whenActiveChanged(this._isChildActive = isActive);
     }
-    active = (outsideReaction: boolean | undefined) => { return this.props.active(outsideReaction) || this._isChildActive; }
+    active = (outsideReaction: boolean | undefined) => this.props.active(outsideReaction) || this._isChildActive;
     render() {
         TraceMobx();
         if (!(this.doc instanceof Doc)) return (null);
-- 
cgit v1.2.3-70-g09d2


From 4f3c8cfab12f1c5fff27faa0998a286d210148d2 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 29 Aug 2020 16:39:17 -0400
Subject: major restructure of how addDocTabs works.  now you can add/replace
 with options for left/right/top/bottom and specific panel names

---
 src/client/documents/Documents.ts                  |   2 +-
 src/client/util/CurrentUserUtils.ts                |   2 +-
 src/client/util/DictationManager.ts                |   4 +-
 src/client/util/DocumentManager.ts                 |   4 +-
 src/client/views/DocumentButtonBar.tsx             |   2 +-
 src/client/views/DocumentDecorations.tsx           |   2 +-
 src/client/views/GlobalKeyHandler.ts               |   4 +-
 src/client/views/MainView.tsx                      |   8 +-
 src/client/views/PropertiesButtons.tsx             |   4 +-
 src/client/views/PropertiesDocContextSelector.tsx  |   2 +-
 src/client/views/PropertiesView.tsx                |   2 +-
 src/client/views/animationtimeline/Keyframe.tsx    |   2 +-
 .../views/collections/CollectionDockingView.tsx    | 298 ++++++++-------------
 .../views/collections/CollectionSchemaCells.tsx    |   2 +-
 .../CollectionSchemaMovableTableHOC.tsx            |   2 +-
 .../views/collections/CollectionTreeView.tsx       |   2 +-
 src/client/views/collections/CollectionView.tsx    |   8 +-
 src/client/views/collections/SchemaTable.tsx       |   2 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |   4 +-
 src/client/views/linking/LinkEditor.tsx            |  20 +-
 src/client/views/linking/LinkMenuItem.tsx          |   2 +-
 src/client/views/nodes/DocumentView.tsx            |  16 +-
 src/client/views/nodes/FontIconBox.tsx             |   2 +-
 src/client/views/nodes/KeyValueBox.tsx             |   2 +-
 src/client/views/nodes/KeyValuePair.tsx            |   2 +-
 src/client/views/nodes/LinkAnchorBox.tsx           |   6 +-
 src/client/views/nodes/LinkDocPreview.tsx          |   6 +-
 src/client/views/nodes/PresBox.tsx                 |   6 +-
 src/client/views/nodes/VideoBox.tsx                |   2 +-
 .../views/nodes/formattedText/DashFieldView.tsx    |   4 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  12 +-
 .../formattedText/FormattedTextBoxComment.tsx      |  16 +-
 .../formattedText/ProsemirrorExampleTransfer.ts    |   2 +-
 .../views/nodes/formattedText/RichTextMenu.tsx     |   4 +-
 .../views/nodes/formattedText/RichTextRules.ts     |   2 +-
 src/client/views/nodes/formattedText/nodes_rts.ts  |   4 +-
 src/client/views/pdf/Annotation.tsx                |   2 +-
 src/client/views/pdf/PDFViewer.tsx                 |   2 +-
 src/fields/RichTextUtils.ts                        |   2 +-
 39 files changed, 202 insertions(+), 268 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 2ca1b95d7..262086735 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -847,7 +847,7 @@ export namespace Docs {
                     {
                         type: type,
                         content: [
-                            ...configs.map(config => CollectionDockingView.makeDocumentConfig(config.doc, false, config.initialWidth))
+                            ...configs.map(config => CollectionDockingView.makeDocumentConfig(config.doc, undefined, config.initialWidth))
                         ]
                     }
                 ]
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 7937072da..20f8fe9c1 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1063,7 +1063,7 @@ export class CurrentUserUtils {
 Scripting.addGlobal(function openDragFactory(dragFactory: Doc) {
     const copy = Doc.copyDragFactory(dragFactory);
     if (copy) {
-        CollectionDockingView.AddRightSplit(copy);
+        CollectionDockingView.AddSplit(copy, "right");
         const view = DocumentManager.Instance.getFirstDocumentView(copy);
         view && SelectionManager.SelectDoc(view, false);
     }
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index e66c15fcb..231e1fa8d 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -323,7 +323,7 @@ export namespace DictationManager {
             ["open fields", {
                 action: (target: DocumentView) => {
                     const kvp = Docs.Create.KVPDocument(target.props.Document, { _width: 300, _height: 300 });
-                    target.props.addDocTab(kvp, "onRight");
+                    target.props.addDocTab(kvp, "add:right");
                 }
             }],
 
@@ -337,7 +337,7 @@ export namespace DictationManager {
                     const proseMirrorState = `{"doc":{"type":"doc","content":[{"type":"ordered_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","text":"${prompt}"}]}]}]}]},"selection":{"type":"text","anchor":${anchor},"head":${head}}}`;
                     proto.data = new RichTextField(proseMirrorState);
                     proto.backgroundColor = "#eeffff";
-                    target.props.addDocTab(newBox, "onRight");
+                    target.props.addDocTab(newBox, "add:right");
                 }
             }]
 
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index fb54fbefc..93c37dbd1 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -124,7 +124,7 @@ export class DocumentManager {
     }
 
     static addRightSplit = (doc: Doc, finished?: () => void) => {
-        CollectionDockingView.AddRightSplit(doc);
+        CollectionDockingView.AddSplit(doc, "right");
         finished?.();
     }
     public jumpToDocument = async (
@@ -231,7 +231,7 @@ export class DocumentManager {
                     containerDoc._currentTimecode = targetTimecode;
                     const targetContext = await target?.context as Doc;
                     const targetNavContext = !Doc.AreProtosEqual(targetContext, currentContext) ? targetContext : undefined;
-                    DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "onRight"), finished), targetNavContext, linkDoc, undefined, doc, finished);
+                    DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "add:right"), finished), targetNavContext, linkDoc, undefined, doc, finished);
                 } else {
                     finished?.();
                 }
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index dd223390a..764a2547c 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -156,7 +156,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                             googleDoc = Docs.Create.WebDocument(googleDocUrl, options);
                             dataDoc.googleDoc = googleDoc;
                         }
-                        CollectionDockingView.AddRightSplit(googleDoc);
+                        CollectionDockingView.AddSplit(googleDoc, "right");
                     } else if (e.altKey) {
                         e.preventDefault();
                         window.open(googleDocUrl);
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 6c64a3714..c7a24133c 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -188,7 +188,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 const alias = Doc.MakeAlias(selectedDocs[0].props.Document);
                 alias.context = undefined;
                 //CollectionDockingView.Instance?.OpenFullScreen(selectedDocs[0]);
-                CollectionDockingView.AddRightSplit(alias);
+                CollectionDockingView.AddSplit(alias, "right");
             }
         }
         SelectionManager.DeselectAll();
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 2794a9f4e..db3e3d0dd 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -210,7 +210,7 @@ export class KeyManager {
                         return { stopPropagation: false, preventDefault: false };
                     }
                 }
-                MainView.Instance.mainFreeform && CollectionDockingView.AddRightSplit(MainView.Instance.mainFreeform);
+                MainView.Instance.mainFreeform && CollectionDockingView.AddSplit(MainView.Instance.mainFreeform, "right");
                 break;
             case "arrowleft":
                 if (document.activeElement) {
@@ -218,7 +218,7 @@ export class KeyManager {
                         return { stopPropagation: false, preventDefault: false };
                     }
                 }
-                MainView.Instance.mainFreeform && CollectionDockingView.CloseRightSplit(MainView.Instance.mainFreeform);
+                MainView.Instance.mainFreeform && CollectionDockingView.CloseSplit(MainView.Instance.mainFreeform);
                 break;
             case "backspace":
                 if (document.activeElement) {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 6a960f4d5..7b0c6fa9f 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -236,7 +236,7 @@ export class MainView extends React.Component {
                 reaction(() => CollectionDockingView.Instance && CollectionDockingView.Instance.initialized,
                     initialized => initialized && received && DocServer.GetRefField(received).then(docField => {
                         if (docField instanceof Doc && docField._viewType !== CollectionViewType.Docking) {
-                            CollectionDockingView.AddRightSplit(docField);
+                            CollectionDockingView.AddSplit(docField, "right");
                         }
                     }),
                 );
@@ -260,7 +260,7 @@ export class MainView extends React.Component {
         }
         const pres = Docs.Create.PresDocument(new List<Doc>(),
             { title: "Untitled Presentation", _viewType: CollectionViewType.Stacking, _width: 400, _height: 500, targetDropAction: "alias", _chromeStatus: "replaced", boxShadow: "0 0", system: true });
-        CollectionDockingView.AddRightSplit(pres);
+        CollectionDockingView.AddSplit(pres, "right");
         Doc.UserDoc().activePresentation = pres;
         const myPresentations = Doc.UserDoc().myPresentations as Doc;
         Doc.AddDocToList(myPresentations, "data", pres);
@@ -382,9 +382,9 @@ export class MainView extends React.Component {
     @computed get topOffset() { return (CollectionMenu.Instance?.Pinned ? 35 : 0) + Number(SEARCH_PANEL_HEIGHT.replace("px", "")); }
     flyoutWidthFunc = () => this.flyoutWidth;
     addDocTabFunc = (doc: Doc, where: string, libraryPath?: Doc[]): boolean => {
-        return where === "close" ? CollectionDockingView.CloseRightSplit(doc) :
+        return where === "close" ? CollectionDockingView.CloseSplit(doc) :
             doc.dockingConfig ? CurrentUserUtils.openDashboard(Doc.UserDoc(), doc) :
-                CollectionDockingView.AddRightSplit(doc);
+                CollectionDockingView.AddSplit(doc, "right");
     }
     sidebarScreenToLocal = () => new Transform(0, (CollectionMenu.Instance.Pinned ? -35 : 0) - Number(SEARCH_PANEL_HEIGHT.replace("px", "")), 1);
     mainContainerXf = () => this.sidebarScreenToLocal().translate(-58, 0);
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index e95b28d6c..6ac6571d3 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -160,7 +160,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                                 googleDoc = Docs.Create.WebDocument(googleDocUrl, options);
                                 dataDoc.googleDoc = googleDoc;
                             }
-                            CollectionDockingView.AddRightSplit(googleDoc);
+                            CollectionDockingView.AddRight(googleDoc, "right");
                         } else if (e.altKey) {
                             e.preventDefault();
                             window.open(googleDocUrl);
@@ -343,7 +343,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                 dv.toggleFollowLink("inPlace", true, false);
             } else if (value === "linkOnRight") {
                 dv.noOnClick();
-                dv.toggleFollowLink("onRight", false, false);
+                dv.toggleFollowLink("add:right", false, false);
             }
         });
     }
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index b382298f3..427748fe7 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -44,7 +44,7 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
             col._panX = NumCast(target.x) + NumCast(target._width) / 2;
             col._panY = NumCast(target.y) + NumCast(target._height) / 2;
         }
-        this.props.addDocTab(col, "inTab");
+        this.props.addDocTab(col, "add:right");
     }
 
     render() {
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index fef0a3e00..d9ab5d029 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -258,7 +258,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     @computed get contexts() {
-        return !this.selectedDoc ? (null) : <PropertiesDocContextSelector Document={this.selectedDoc} hideTitle={true} addDocTab={(doc, where) => CollectionDockingView.AddRightSplit(doc)} />;
+        return !this.selectedDoc ? (null) : <PropertiesDocContextSelector Document={this.selectedDoc} hideTitle={true} addDocTab={(doc, where) => CollectionDockingView.AddSplit(doc, "right")} />;
     }
 
     previewBackground = () => "lightgrey";
diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx
index 4fb362ab1..e84022366 100644
--- a/src/client/views/animationtimeline/Keyframe.tsx
+++ b/src/client/views/animationtimeline/Keyframe.tsx
@@ -331,7 +331,7 @@ export class Keyframe extends React.Component<IProps> {
         }),
             TimelineMenu.Instance.addItem("button", "Show Data", action(() => {
                 const kvp = Docs.Create.KVPDocument(kf, { _width: 300, _height: 300 });
-                CollectionDockingView.AddRightSplit(kvp);
+                CollectionDockingView.AddSplit(kvp, "right");
             })),
             TimelineMenu.Instance.addItem("button", "Delete", action(() => {
                 (this.regiondata.keyframes as List<Doc>).splice(this.keyframes.indexOf(kf), 1);
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 8301d3df8..62c865436 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -1,6 +1,6 @@
 import 'golden-layout/src/css/goldenlayout-base.css';
 import 'golden-layout/src/css/goldenlayout-dark-theme.css';
-import { clamp } from 'lodash';
+import { clamp, pull } from 'lodash';
 import { action, computed, IReactionDisposer, Lambda, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import * as ReactDOM from 'react-dom';
@@ -38,7 +38,7 @@ const _global = (window /* browser */ || global /* node */) as any;
 @observer
 export class CollectionDockingView extends CollectionSubView(doc => doc) {
     @observable public static Instance: CollectionDockingView;
-    public static makeDocumentConfig(document: Doc, isDisplayPanel?: boolean, width?: number) {
+    public static makeDocumentConfig(document: Doc, panelName?: string, width?: number) {
         return {
             type: 'react-component',
             component: 'DocumentFrameRenderer',
@@ -46,7 +46,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
             width: width,
             props: {
                 documentId: document[Id],
-                isDisplayPanel   // flag for whether a tab should be considered a placeholder that has its contents replaced with new content
+                panelName   // name of tab that can be used to close or replace its contents
             }
         };
     }
@@ -85,26 +85,20 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
     }
 
     @undoBatch
-    @action
-    public static CloseRightSplit(document: Opt<Doc>): boolean {
-        const tryClose = (childItem: any) => {
-            if (childItem.config?.component === "DocumentFrameRenderer") {
-                if ((!document && childItem.config.props.isDisplayPanel) || (document && childItem.config.props.documentId === document[Id])) {
-                    childItem.remove();
-                    return true;
-                }
+    public static CloseSplit(document: Opt<Doc>, panelName?: string): boolean {
+        const tab = Array.from(CollectionDockingView.Instance.tabMap.keys()).find((tab) => panelName ? tab.contentItem.config.props.panelName === panelName : tab.DashDoc === document);
+        if (tab) {
+            const j = tab.header.parent.contentItems.indexOf(tab.contentItem);
+            if (j !== -1) {
+                tab.header.parent.contentItems[j].remove();
+                return CollectionDockingView.Instance.layoutChanged();
             }
-            return false;
-        };
-        const retVal = !CollectionDockingView.Instance?._goldenLayout.root.contentItems[0].isRow ? false :
-            Array.from(CollectionDockingView.Instance._goldenLayout.root.contentItems[0].contentItems).some((child: any) => Array.from(child.contentItems).some(tryClose));
+        }
 
-        retVal && document && CollectionDockingView.Instance.layoutChanged();
-        return retVal;
+        return false;
     }
 
     @undoBatch
-    @action
     public static OpenFullScreen(doc: Doc, libraryPath?: Doc[]) {
         const instance = CollectionDockingView.Instance;
         if (doc._viewType === CollectionViewType.Docking && doc.layoutKey === "layout") {
@@ -124,176 +118,94 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
         return true;
     }
 
-    public static ReplaceRightSplit(document: Doc, libraryPath?: Doc[], addToSplit?: boolean): boolean {
-        if (!CollectionDockingView.Instance) return false;
-        const instance = CollectionDockingView.Instance;
-        const retVal = !instance._goldenLayout.root.contentItems[0].isRow ? false :
-            Array.from(instance._goldenLayout.root.contentItems[0].contentItems).some((child: any) => {
-                if (child.contentItems.length === 1 && child.contentItems[0].config.component === "DocumentFrameRenderer" &&
-                    child.contentItems[0].config.isDisplayPanel) {
-                    const newItemStackConfig = CollectionDockingView.makeDocumentConfig(document, true);
-                    child.addChild(newItemStackConfig, undefined);
-                    !addToSplit && child.contentItems[0].remove();
-                    return true;
-                }
-                return Array.from(child.contentItems).filter((tab: any) => tab.config.component === "DocumentFrameRenderer").some((tab: any, j: number) => {
-                    if (tab.config.props.isDisplayPanel) {
-                        const newItemStackConfig = CollectionDockingView.makeDocumentConfig(document, true);
-                        child.addChild(newItemStackConfig, undefined);
-                        !addToSplit && child.contentItems[j].remove();
-                        return true;
-                    }
-                    return false;
-                });
-            });
-        retVal && instance.layoutChanged();
-        return retVal;
-    }
-
-    //
-    //  Creates a vertical split on the right side of the docking view, and then adds the Document to the right of that split
-    //
     @undoBatch
-    @action
-    public static AddRightSplit(document: Doc, isDisplayPanel: Opt<boolean> = undefined) {
-        if (!CollectionDockingView.Instance) return false;
-
-        const ind = Array.from(CollectionDockingView.Instance.tabMap.keys()).findIndex((tab) => tab.DashDoc === document);
-        if (ind !== -1) {
-            const tab = Array.from(CollectionDockingView.Instance.tabMap.keys())[ind];
-            const activeContentItem = tab.header.parent.getActiveContentItem();
-            if (tab.contentItem !== activeContentItem) {
-                tab.header.parent.setActiveContentItem(tab.contentItem);
-            }
-            tab.setActive(true);
-        } else {
-            if (document._viewType === CollectionViewType.Docking) return CurrentUserUtils.openDashboard(Doc.UserDoc(), document);
-            const instance = CollectionDockingView.Instance;
-            const newItemStackConfig = {
-                type: 'stack',
-                content: [CollectionDockingView.makeDocumentConfig(document, isDisplayPanel)]
-            };
-
-            const newContentItem = instance._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout);
-
-            if (instance._goldenLayout.root.contentItems.length === 0) {
-                instance._goldenLayout.root.addChild(newContentItem);
-            } else if (instance._goldenLayout.root.contentItems[0].isRow) {
-                instance._goldenLayout.root.contentItems[0].addChild(newContentItem);
-            } else {
-                const collayout = instance._goldenLayout.root.contentItems[0];
-                const newRow = collayout.layoutManager.createContentItem({ type: "row" }, instance._goldenLayout);
-                collayout.parent.replaceChild(collayout, newRow);
-
-                newRow.addChild(newContentItem, undefined, true);
-                newRow.addChild(collayout, 0, true);
-
-                collayout.config.width = 50;
-                newContentItem.config.width = 50;
-            }
-            newContentItem.callDownwards('_$init');
-            instance.layoutChanged();
+    public static ReplaceTab(document: Doc, panelName: string, stack: any, addToSplit?: boolean): boolean {
+        const instance = CollectionDockingView.Instance;
+        if (!instance) return false;
+        const newConfig = CollectionDockingView.makeDocumentConfig(document, panelName);
+        if (!panelName && stack) {
+            const activeContentItemIndex = stack.contentItems.findIndex((item: any) => item.config === stack._activeContentItem.config);
+            const newContentItem = stack.layoutManager.createContentItem(newConfig, instance._goldenLayout);
+            stack.addChild(newContentItem.contentItems[0], undefined);
+            stack.contentItems[activeContentItemIndex].remove();
+            return CollectionDockingView.Instance.layoutChanged();
         }
-        return true;
+        const tab = Array.from(CollectionDockingView.Instance.tabMap.keys()).find((tab) => tab.contentItem.config.props.panelName === panelName);
+        if (tab) {
+            tab.header.parent.addChild(newConfig, undefined);
+            const j = tab.header.parent.contentItems.indexOf(tab.contentItem);
+            !addToSplit && j !== -1 && tab.header.parent.contentItems[j].remove();
+            return CollectionDockingView.Instance.layoutChanged();
+        }
+        return CollectionDockingView.AddSplit(document, panelName, stack, panelName);
     }
 
-
     //
     //  Creates a split on any side of the docking view based on the passed input pullSide and then adds the Document to the requested side
     //
-    @action
-    public static AddSplit(document: Doc, pullSide: string, libraryPath?: Doc[]) {
-        if (!CollectionDockingView.Instance) return false;
+    @undoBatch
+    public static AddSplit(document: Doc, pullSide: string, stack?: any, panelName?: string) {
         const instance = CollectionDockingView.Instance;
-        const newItemStackConfig = {
-            type: 'stack',
-            content: [CollectionDockingView.makeDocumentConfig(document, undefined)]
-        };
+        if (!instance) return false;
+        const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName);
 
-        const newContentItem = instance._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout);
-
-        if (instance._goldenLayout.root.contentItems.length === 0) { // if no rows / columns
-            instance._goldenLayout.root.addChild(newContentItem);
-        } else if (instance._goldenLayout.root.contentItems[0].isRow) { // if row
-            if (pullSide === "left") {
-                instance._goldenLayout.root.contentItems[0].addChild(newContentItem, 0);
-            } else if (pullSide === "right") {
-                instance._goldenLayout.root.contentItems[0].addChild(newContentItem);
-            } else if (pullSide === "top" || pullSide === "bottom") {
-                // if not going in a row layout, must add already existing content into column
-                const rowlayout = instance._goldenLayout.root.contentItems[0];
-                const newColumn = rowlayout.layoutManager.createContentItem({ type: "column" }, instance._goldenLayout);
-                rowlayout.parent.replaceChild(rowlayout, newColumn);
-                if (pullSide === "top") {
-                    newColumn.addChild(rowlayout, undefined, true);
-                    newColumn.addChild(newContentItem, 0, true);
-                } else if (pullSide === "bottom") {
-                    newColumn.addChild(newContentItem, undefined, true);
-                    newColumn.addChild(rowlayout, 0, true);
+        if (!pullSide && stack) {
+            stack.addChild(docContentConfig, undefined);
+        } else {
+            const newItemStackConfig = { type: 'stack', content: [docContentConfig] };
+            const newContentItem = instance._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout);
+            if (instance._goldenLayout.root.contentItems.length === 0) { // if no rows / columns
+                instance._goldenLayout.root.addChild(newContentItem);
+            } else if (instance._goldenLayout.root.contentItems[0].isRow) { // if row
+                switch (pullSide) {
+                    default:
+                    case "right": instance._goldenLayout.root.contentItems[0].addChild(newContentItem); break;
+                    case "left": instance._goldenLayout.root.contentItems[0].addChild(newContentItem, 0); break;
+                    case "top":
+                    case "bottom":
+                        // if not going in a row layout, must add already existing content into column
+                        const rowlayout = instance._goldenLayout.root.contentItems[0];
+                        const newColumn = rowlayout.layoutManager.createContentItem({ type: "column" }, instance._goldenLayout);
+                        rowlayout.parent.replaceChild(rowlayout, newColumn);
+                        if (pullSide === "top") {
+                            newColumn.addChild(rowlayout, undefined, true);
+                            newColumn.addChild(newContentItem, 0, true);
+                        } else if (pullSide === "bottom") {
+                            newColumn.addChild(newContentItem, undefined, true);
+                            newColumn.addChild(rowlayout, 0, true);
+                        }
+
+                        rowlayout.config.height = 50;
+                        newContentItem.config.height = 50;
                 }
-
-                rowlayout.config.height = 50;
-                newContentItem.config.height = 50;
-            }
-        } else if (instance._goldenLayout.root.contentItems[0].isColumn) { // if column
-            if (pullSide === "top") {
-                instance._goldenLayout.root.contentItems[0].addChild(newContentItem, 0);
-            } else if (pullSide === "bottom") {
-                instance._goldenLayout.root.contentItems[0].addChild(newContentItem);
-            } else if (pullSide === "left" || pullSide === "right") {
-                // if not going in a row layout, must add already existing content into column
-                const collayout = instance._goldenLayout.root.contentItems[0];
-                const newRow = collayout.layoutManager.createContentItem({ type: "row" }, instance._goldenLayout);
-                collayout.parent.replaceChild(collayout, newRow);
-
-                if (pullSide === "left") {
-                    newRow.addChild(collayout, undefined, true);
-                    newRow.addChild(newContentItem, 0, true);
-                } else if (pullSide === "right") {
-                    newRow.addChild(newContentItem, undefined, true);
-                    newRow.addChild(collayout, 0, true);
+            } else if (instance._goldenLayout.root.contentItems[0].isColumn) { // if column
+                switch (pullSide) {
+                    case "top": instance._goldenLayout.root.contentItems[0].addChild(newContentItem, 0); break;
+                    case "bottom": instance._goldenLayout.root.contentItems[0].addChild(newContentItem); break;
+                    case "left":
+                    case "right":
+                    default:
+                        // if not going in a row layout, must add already existing content into column
+                        const collayout = instance._goldenLayout.root.contentItems[0];
+                        const newRow = collayout.layoutManager.createContentItem({ type: "row" }, instance._goldenLayout);
+                        collayout.parent.replaceChild(collayout, newRow);
+
+                        if (pullSide === "left") {
+                            newRow.addChild(collayout, undefined, true);
+                            newRow.addChild(newContentItem, 0, true);
+                        } else {
+                            newRow.addChild(newContentItem, undefined, true);
+                            newRow.addChild(collayout, 0, true);
+                        }
+
+                        collayout.config.width = 50;
+                        newContentItem.config.width = 50;
                 }
-
-                collayout.config.width = 50;
-                newContentItem.config.width = 50;
             }
+            newContentItem.callDownwards('_$init');
         }
 
-        newContentItem.callDownwards('_$init');
-        instance.layoutChanged();
-        return true;
-    }
-
-    //
-    //  Creates a vertical split on the right side of the docking view, and then adds the Document to that split
-    //
-    @undoBatch
-    public static UseRightSplit(document: Doc, libraryPath?: Doc[], shiftKey?: boolean) {
-        if (shiftKey || !CollectionDockingView.ReplaceRightSplit(document, libraryPath, shiftKey)) {
-            return CollectionDockingView.AddRightSplit(document, true);
-        }
-        return false;
-    }
-
-    @undoBatch
-    public static AddTab(stack: any, document: Doc, libraryPath?: Doc[]) {
-        const instance = CollectionDockingView.Instance;
-        const docContentConfig = CollectionDockingView.makeDocumentConfig(document, undefined);
-        if (stack === undefined) {
-            stack = instance._goldenLayout.root;
-            while (!stack.isStack) {
-                if (stack.contentItems.length) {
-                    stack = stack.contentItems[0];
-                } else {
-                    stack.addChild({ type: 'stack', content: [docContentConfig] });
-                    stack = undefined;
-                    break;
-                }
-            }
-        }
-        stack?.addChild(docContentConfig, undefined);
-        instance.layoutChanged();
-        return true;
+        return instance.layoutChanged();
     }
 
     @undoBatch
@@ -303,6 +215,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
         this._goldenLayout.emit('stateChanged');
         this._ignoreStateChange = JSON.stringify(this._goldenLayout.toConfig());
         this.stateChanged();
+        return true;
     }
 
     async setupGoldenLayout() {
@@ -450,7 +363,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
         tab.reactComponents?.forEach((ele: any) => ReactDOM.unmountComponentAtNode(ele));
     }
     tabCreated = (tab: any) => {
-        tab.contentItem.element[0]?.firstChild?.firstChild?.InitTab(tab);  // have to explicitly initialize tabs that reuse contents from previous abs (ie, when dragging a tab around a new tab is created for the old content)
+        tab.contentItem.element[0]?.firstChild?.firstChild?.InitTab?.(tab);  // have to explicitly initialize tabs that reuse contents from previous abs (ie, when dragging a tab around a new tab is created for the old content)
     }
 
     stackCreated = (stack: any) => {
@@ -458,9 +371,9 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
             if (e.target === stack.header.element[0] && e.button === 2) {
                 const emptyPane = CurrentUserUtils.EmptyPane;
                 emptyPane["dragFactory-count"] = NumCast(emptyPane["dragFactory-count"]) + 1;
-                CollectionDockingView.AddTab(stack, Docs.Create.FreeformDocument([], {
+                CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], {
                     _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), title: `Untitled Tab ${NumCast(emptyPane["dragFactory-count"])}`
-                }));
+                }), "", stack);
             }
         });
 
@@ -477,9 +390,9 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
                 // stack.config.fixed = !stack.config.fixed;  // force the stack to have a fixed size
                 const emptyPane = CurrentUserUtils.EmptyPane;
                 emptyPane["dragFactory-count"] = NumCast(emptyPane["dragFactory-count"]) + 1;
-                CollectionDockingView.AddTab(stack, Docs.Create.FreeformDocument([], {
+                CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], {
                     _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), title: `Untitled Tab ${NumCast(emptyPane["dragFactory-count"])}`
-                }));
+                }), "", stack);
             }));
     }
 
@@ -601,7 +514,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
                 Doc.AddDocToList(curPres, "data", pinDoc);
                 if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
                 if (!DocumentManager.Instance.getDocumentView(curPres)) {
-                    CollectionDockingView.AddRightSplit(curPres);
+                    CollectionDockingView.AddSplit(curPres, "right");
                 }
                 DocumentManager.Instance.jumpToDocument(doc, false, undefined, Cast(doc.context, Doc, null));
             }
@@ -688,17 +601,26 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
     get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this._panelWidth * 100}% ` : undefined; }
 
+    // adds a tab to the layout based on the locaiton parameter which can be:
+    //  close[:{left,right,top,bottom}]  - e.g., "close" will close the tab, "close:left" will close the left tab, 
+    //  add[:{left,right,top,bottom}] - e.g., "add" will add a tab to the current stack, "add:right" will add a tab on the right
+    //  replace[:{left,right,top,bottom,<any string>}] - e.g., "replace" will replace the current stack contents, 
+    //                                  "replace:right" - will replace the stack on the right named "right" if it exists, or create a stack on the right with that name, 
+    //                                   "replace:monkeys" - will replace any tab that has the label 'monkeys', or a tab with that label will be created by default on the right
+    //  inPlace - will add the document to any collection along the path from the document to the docking view that has a field isInPlaceContainer. if none is found, inPlace adds a tab to current stack
     addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => {
         SelectionManager.DeselectAll();
         if (doc._viewType === CollectionViewType.Docking) return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc);
-        switch (location) {
-            case "onRight": return Array.from(CollectionDockingView.Instance.tabMap.keys()).findIndex((tab) => tab.DashDoc === doc) !== -1 ?
-                CollectionDockingView.CloseRightSplit(doc) : CollectionDockingView.AddRightSplit(doc);
-            case "close": return CollectionDockingView.CloseRightSplit(doc);
-            case "replace": return CollectionDockingView.UseRightSplit(doc);
+        const locationFields = location.split(":");
+        const locationParams = locationFields.length > 1 ? locationFields[1] : "";
+        switch (locationFields[0]) {
+            case "close": return CollectionDockingView.CloseSplit(doc, locationParams);
             case "fullScreen": return CollectionDockingView.OpenFullScreen(doc);
+            case "replace": return CollectionDockingView.ReplaceTab(doc, locationParams, this.stack);
             case "inPlace":
-            default: return CollectionDockingView.AddTab(this.stack, doc);
+            case "add":
+            default: return Array.from(CollectionDockingView.Instance.tabMap.keys()).findIndex((tab) => tab.DashDoc === doc) !== -1 ?
+                CollectionDockingView.CloseSplit(doc) : CollectionDockingView.AddSplit(doc, locationParams, this.stack);
         }
     }
 
@@ -830,6 +752,6 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             </div >);
     }
 }
-Scripting.addGlobal(function openOnRight(doc: any) { CollectionDockingView.AddRightSplit(doc); },
+Scripting.addGlobal(function openOnRight(doc: any) { CollectionDockingView.AddSplit(doc, "right"); },
     "opens up the inputted document on the right side of the screen", "(doc: any)");
-Scripting.addGlobal(function useRightSplit(doc: any, shiftKey?: boolean) { CollectionDockingView.UseRightSplit(doc, undefined, shiftKey); });
+Scripting.addGlobal(function useRightSplit(doc: any, shiftKey?: boolean) { CollectionDockingView.ReplaceTab(doc, "right", undefined, shiftKey); });
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 18ca29aaa..0d3a951cf 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -370,7 +370,7 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell {
                         })}
                     />
                 </div >
-                <div onClick={() => this._doc && this.props.addDocTab(this._doc, "onRight")} className="collectionSchemaView-cellContents-docButton">
+                <div onClick={() => this._doc && this.props.addDocTab(this._doc, "add:right")} className="collectionSchemaView-cellContents-docButton">
                     <FontAwesomeIcon icon="external-link-alt" size="lg" />
                 </div>
             </div>;
diff --git a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
index a3475b481..383a9312f 100644
--- a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
+++ b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
@@ -246,7 +246,7 @@ export class MovableRow extends React.Component<MovableRowProps> {
                         <div className="row-dragger">
                             <div className="row-option" style={{ left: 5 }} onClick={undoBatch(() => this.props.removeDoc(this.props.rowInfo.original))}><FontAwesomeIcon icon="trash" size="sm" /></div>
                             <div className="row-option" style={{ cursor: "grab", left: 25 }} ref={reference} onPointerDown={onItemDown}><FontAwesomeIcon icon="grip-vertical" size="sm" /></div>
-                            <div className="row-option" style={{ left: 40 }} onClick={() => this.props.addDocTab(this.props.rowInfo.original, "onRight")}><FontAwesomeIcon icon="external-link-alt" size="sm" /></div>
+                            <div className="row-option" style={{ left: 40 }} onClick={() => this.props.addDocTab(this.props.rowInfo.original, "add:right")}><FontAwesomeIcon icon="external-link-alt" size="sm" /></div>
                         </div>
                         {children}
                     </ReactTableDefaults.TrComponent>
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index fffbe65a3..80a6afba7 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -117,7 +117,7 @@ class TreeView extends React.Component<TreeViewProps> {
             Doc.ComputeContentBounds(DocListCast(this.props.document[this.fieldKey]));
     }
 
-    @undoBatch openRight = () => this.props.addDocTab(this.doc, "onRight");
+    @undoBatch openRight = () => this.props.addDocTab(this.doc, "add:right");
     @undoBatch move = (doc: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => {
         return this.doc !== target && this.props.removeDoc?.(doc) === true && addDoc(doc);
     }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 1da0e601a..64ad3abbf 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -305,7 +305,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
             this.setupViewTypes("UI Controls...", vtype => {
                 const newRendition = Doc.MakeAlias(this.props.Document);
                 newRendition._viewType = vtype;
-                this.props.addDocTab(newRendition, "onRight");
+                this.props.addDocTab(newRendition, "add:right");
                 return newRendition;
             }, false);
 
@@ -313,10 +313,10 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
             const optionItems = options && "subitems" in options ? options.subitems : [];
             !Doc.UserDoc().noviceMode ? optionItems.splice(0, 0, { description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" }) : null;
             if (this.props.Document.childLayout instanceof Doc) {
-                optionItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, "onRight"), icon: "project-diagram" });
+                optionItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, "add:right"), icon: "project-diagram" });
             }
             if (this.props.Document.childClickedOpenTemplateView instanceof Doc) {
-                optionItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childClickedOpenTemplateView as Doc, "onRight"), icon: "project-diagram" });
+                optionItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childClickedOpenTemplateView as Doc, "add:right"), icon: "project-diagram" });
             }
             !Doc.UserDoc().noviceMode && optionItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" });
 
@@ -331,7 +331,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 description: `Edit ${func.name} script`, icon: "edit", event: (obj: any) => {
                     const alias = Doc.MakeAlias(this.props.Document);
                     DocUtils.makeCustomViewClicked(alias, undefined, func.key);
-                    this.props.addDocTab(alias, "onRight");
+                    this.props.addDocTab(alias, "add:right");
                 }
             }));
             DocListCast(Cast(Doc.UserDoc()["clickFuncs-child"], Doc, null).data).forEach(childClick =>
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index 2fe00a245..1fb7aa04a 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -545,7 +545,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     }
 
     onOpenClick = () => {
-        this._showDoc && this.props.addDocTab(this._showDoc, "onRight");
+        this._showDoc && this.props.addDocTab(this._showDoc, "add:right");
     }
 
     getPreviewTransform = (): Transform => {
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 759d142ea..1aa30fc02 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -76,7 +76,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         const [x, y] = this.props.getTransform().transformPoint(this._downX, this._downY);
         if (e.key === "?") {
             cm.setDefaultItem("?", (str: string) => this.props.addDocTab(
-                Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 200, x, y, _nativeHeight: 962, _nativeWidth: 850, isAnnotating: false, title: "bing", UseCors: true }), "onRight"));
+                Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 200, x, y, _nativeHeight: 962, _nativeWidth: 850, isAnnotating: false, title: "bing", UseCors: true }), "add:right"));
 
             cm.displayMenu(this._downX, this._downY);
             e.stopPropagation();
@@ -400,7 +400,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             Doc.AddDocToList(curPres, "data", pinDoc);
             if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
             if (!DocumentManager.Instance.getDocumentView(curPres)) {
-                CollectionDockingView.AddRightSplit(curPres);
+                CollectionDockingView.AddSplit(curPres, "right");
             }
             if (e instanceof KeyboardEvent ? e.key === "c" : true) {
                 const x = this.Bounds.left + this.Bounds.width / 2;
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index 8e391f995..c9c2e657b 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -376,21 +376,33 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
                         Default
                         </div>
                     <div className="linkEditor-followingDropdown-option"
-                        onPointerDown={() => this.changeFollowBehavior("onRight")}>
-                        Always open in a new pane
+                        onPointerDown={() => this.changeFollowBehavior("add:left")}>
+                        Always open in new left pane
                         </div>
                     <div className="linkEditor-followingDropdown-option"
-                        onPointerDown={() => this.changeFollowBehavior("replace")}>
+                        onPointerDown={() => this.changeFollowBehavior("add:right")}>
+                        Always open in new right pane
+                        </div>
+                    <div className="linkEditor-followingDropdown-option"
+                        onPointerDown={() => this.changeFollowBehavior("replace:right")}>
                         Always replace right tab
                         </div>
+                    <div className="linkEditor-followingDropdown-option"
+                        onPointerDown={() => this.changeFollowBehavior("replace:left")}>
+                        Always replace left tab
+                        </div>
                     <div className="linkEditor-followingDropdown-option"
                         onPointerDown={() => this.changeFollowBehavior("fullScreen")}>
                         Always open full screen
                         </div>
                     <div className="linkEditor-followingDropdown-option"
-                        onPointerDown={() => this.changeFollowBehavior("inTab")}>
+                        onPointerDown={() => this.changeFollowBehavior("add")}>
                         Always open in a new tab
                         </div>
+                    <div className="linkEditor-followingDropdown-option"
+                        onPointerDown={() => this.changeFollowBehavior("replace")}>
+                        Replace Tab
+                        </div>
                     {this.props.linkDoc.linksToAnnotation ?
                         <div className="linkEditor-followingDropdown-option"
                             onPointerDown={() => this.changeFollowBehavior("openExternal")}>
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index a77122456..05b6b584d 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -167,7 +167,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
                 });
             }
         } else {
-            DocumentManager.Instance.FollowLink(this.props.linkDoc, this.props.sourceDoc, doc => this.props.addDocTab(doc, "onRight"), false);
+            DocumentManager.Instance.FollowLink(this.props.linkDoc, this.props.sourceDoc, doc => this.props.addDocTab(doc, "add:right"), false);
         }
 
         linkDoc.linksToAnnotation && Hypothesis.scrollToAnnotation(StrCast(this.props.linkDoc.annotationId), this.props.destinationDoc);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 2d03c5154..48a1688a6 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -180,10 +180,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const pt = me.touchEvent.touches[me.touchEvent.touches.length - 1];
         RadialMenu.Instance.openMenu(pt.pageX - 15, pt.pageY - 15);
 
-        // RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "map-pin", selected: -1 });
+        // RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "add:right"), icon: "map-pin", selected: -1 });
         const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
         (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) && RadialMenu.Instance.addItem({ description: "Delete", event: () => { this.props.ContainingCollectionView?.removeDocument(this.props.Document), RadialMenu.Instance.closeMenu(); }, icon: "external-link-square-alt", selected: -1 });
-        // RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, "onRight"), icon: "trash", selected: -1 });
+        // RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, "add:right"), icon: "trash", selected: -1 });
         RadialMenu.Instance.addItem({ description: "Pin", event: () => this.props.pinToPres(this.props.Document), icon: "map-pin", selected: -1 });
         RadialMenu.Instance.addItem({ description: "Open", event: () => MobileInterface.Instance.handleClick(this.props.Document), icon: "trash", selected: -1 });
 
@@ -323,7 +323,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                                     fullScreenDoc = Doc.MakeAlias(this.props.Document);
                                     fullScreenDoc.layoutKey = "layout_fullScreen";
                                 }
-                                this.props.addDocTab(fullScreenDoc, "inTab");
+                                this.props.addDocTab(fullScreenDoc, "add");
                             }, "double tap");
                             SelectionManager.DeselectAll();
                         }
@@ -351,7 +351,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                     this._timeout = setTimeout(() => { this._timeout = undefined; clickFunc(); }, 500);
                 } else clickFunc();
             } else if (this.Document["onClick-rawScript"] && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) {// bcz: hack? don't edit a script if you're clicking on a scripting box itself
-                this.props.addDocTab(DocUtils.makeCustomViewClicked(Doc.MakeAlias(this.props.Document), undefined, "onClick"), "onRight");
+                this.props.addDocTab(DocUtils.makeCustomViewClicked(Doc.MakeAlias(this.props.Document), undefined, "onClick"), "add:right");
             } else if (this.allLinks && this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) {
                 this.allLinks.length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey);
             } else {
@@ -748,7 +748,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layoutKey)], Doc, null);
         const appearance = cm.findByDescription("UI Controls...");
         const appearanceItems: ContextMenuProps[] = appearance && "subitems" in appearance ? appearance.subitems : [];
-        templateDoc && appearanceItems.push({ description: "Open Template   ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" });
+        templateDoc && appearanceItems.push({ description: "Open Template   ", event: () => this.props.addDocTab(templateDoc, "add:right"), icon: "eye" });
         //DocListCast(this.Document.links).length && appearanceItems.splice(0, 0, { description: `${this.layoutDoc.hideLinkButton ? "Show" : "Hide"} Link Button`, event: action(() => this.layoutDoc.hideLinkButton = !this.layoutDoc.hideLinkButton), icon: "eye" });
         !appearance && cm.addItem({ description: "UI Controls...", subitems: appearanceItems, icon: "compass" });
 
@@ -766,7 +766,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.Document.layoutKey}")`), icon: "concierge-bell" });
             onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" });
             onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: () => this.toggleFollowLink("inPlace", true, false), icon: "link" });
-            !this.Document.isLinkButton && onClicks.push({ description: "Follow Link on Right", event: () => this.toggleFollowLink("onRight", false, false), icon: "link" });
+            !this.Document.isLinkButton && onClicks.push({ description: "Follow Link on Right", event: () => this.toggleFollowLink("add:right", false, false), icon: "link" });
             onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? "Remove Click Behavior" : "Follow Link", event: () => this.toggleFollowLink(undefined, false, false), icon: "link" });
             onClicks.push({ description: (this.Document.isPushpin ? "Remove" : "Make") + " Pushpin", event: () => this.toggleFollowLink(undefined, false, true), icon: "map-pin" });
             onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "terminal" });
@@ -810,8 +810,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
         const help = cm.findByDescription("Help...");
         const helpItems: ContextMenuProps[] = help && "subitems" in help ? help.subitems : [];
-        !Doc.UserDoc().novice && helpItems.push({ description: "Show Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
-        helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument(Utils.prepend("/assets/cheat-sheet.pdf"), { _width: 300, _height: 300 }), "onRight"), icon: "keyboard" });
+        !Doc.UserDoc().novice && helpItems.push({ description: "Show Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "add:right"), icon: "layer-group" });
+        helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument(Utils.prepend("/assets/cheat-sheet.pdf"), { _width: 300, _height: 300 }), "add:right"), icon: "keyboard" });
         helpItems.push({ description: "Print Document in Console", event: () => console.log(this.props.Document), icon: "hand-point-right" });
         cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" });
 
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index bc5abb0a4..87142babd 100644
--- a/src/client/views/nodes/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox.tsx
@@ -39,7 +39,7 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
 
     showTemplate = (): void => {
         const dragFactory = Cast(this.layoutDoc.dragFactory, Doc, null);
-        dragFactory && this.props.addDocTab(dragFactory, "onRight");
+        dragFactory && this.props.addDocTab(dragFactory, "add:right");
     }
     dragAsTemplate = (): void => {
         this.layoutDoc.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)');
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index b732f5f83..c5ff42a1a 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -230,7 +230,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
         openItems.push({
             description: "Default Perspective", event: () => {
                 this.props.addDocTab(this.props.Document, "close");
-                this.props.addDocTab(this.fieldDocToLayout, "onRight");
+                this.props.addDocTab(this.fieldDocToLayout, "add:right");
             }, icon: "image"
         });
         !open && cm.addItem({ description: "Change Perspective...", subitems: openItems, icon: "external-link-alt" });
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 6dd85b7f5..74d10d087 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -46,7 +46,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
         if (value instanceof Doc) {
             e.stopPropagation();
             e.preventDefault();
-            ContextMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(value, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
+            ContextMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(value, { _width: 300, _height: 300 }), "add:right"), icon: "layer-group" });
             ContextMenu.Instance.displayMenu(e.clientX, e.clientY);
         }
     }
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index 8e5ee09ff..10b6aa02e 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -73,7 +73,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch
             anchorContainerDoc && this.props.bringToFront(anchorContainerDoc, false);
             if (anchorContainerDoc && !this.layoutDoc.onClick && !this._isOpen) {
                 this._timeout = setTimeout(action(() => {
-                    DocumentManager.Instance.FollowLink(this.rootDoc, anchorContainerDoc, document => this.props.addDocTab(document, StrCast(this.layoutDoc.linkOpenLocation, e.altKey ? "inTab" : "onRight")), false);
+                    DocumentManager.Instance.FollowLink(this.rootDoc, anchorContainerDoc, document => this.props.addDocTab(document, StrCast(this.layoutDoc.linkOpenLocation, "add:right")), false);
                     this._editing = false;
                 }), 300 - (Date.now() - this._lastTap));
             }
@@ -87,14 +87,14 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch
     }
 
     openLinkDocOnRight = (e: React.MouseEvent) => {
-        this.props.addDocTab(this.rootDoc, "onRight");
+        this.props.addDocTab(this.rootDoc, "add:right");
     }
     openLinkTargetOnRight = (e: React.MouseEvent) => {
         const alias = Doc.MakeAlias(Cast(this.layoutDoc[this.fieldKey], Doc, null));
         alias.isLinkButton = undefined;
         alias._isBackground = undefined;
         alias.layoutKey = "layout";
-        this.props.addDocTab(alias, "onRight");
+        this.props.addDocTab(alias, "add:right");
     }
     @action
     openLinkEditor = action((e: React.MouseEvent) => {
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index f154c5f56..e174a95af 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -40,7 +40,7 @@ export class LinkDocPreview extends React.Component<Props> {
     async followDefault() {
         DocumentLinksButton.EditLink = undefined;
         LinkDocPreview.LinkInfo = undefined;
-        this._targetDoc ? DocumentManager.Instance.FollowLink(this.props.linkDoc, this._targetDoc, doc => this.props.addDocTab(doc, "onRight"), false) : null;
+        this._targetDoc ? DocumentManager.Instance.FollowLink(this.props.linkDoc, this._targetDoc, doc => this.props.addDocTab(doc, "add:right"), false) : null;
     }
 
     componentDidUpdate() { this.updatePreview(); }
@@ -69,9 +69,9 @@ export class LinkDocPreview extends React.Component<Props> {
     pointerDown = (e: React.PointerEvent) => {
         if (this.props.linkDoc && this.props.linkSrc) {
             DocumentManager.Instance.FollowLink(this.props.linkDoc, this.props.linkSrc,
-                (doc: Doc, followLinkLocation: string) => this.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation));
+                (doc: Doc, followLinkLocation: string) => this.props.addDocTab(doc, e.ctrlKey ? "add" : followLinkLocation));
         } else if (this.props.href) {
-            this.props.addDocTab(Docs.Create.WebDocument(this.props.href, { title: this.props.href, _width: 200, _height: 400, UseCors: true }), "onRight");
+            this.props.addDocTab(Docs.Create.WebDocument(this.props.href, { title: this.props.href, _width: 200, _height: 400, UseCors: true }), "add:right");
         }
     }
     width = () => Math.min(225, NumCast(this._targetDoc?.[WidthSym](), 225));
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index f60c521ad..a03c45a53 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -238,7 +238,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
 
         // If openDocument is selected then it should open the document for the user
         if (activeItem.openDocument) {
-            this.props.addDocTab(activeItem, "replace");
+            this.props.addDocTab(activeItem, "replace:right");
         } else
             //docToJump stayed same meaning, it was not in the group or was the last element in the group
             if (activeItem.zoomProgressivize && this.rootDoc.presStatus !== 'edit') {
@@ -443,7 +443,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         if (this.layoutDoc.inOverlay) {
             this.layoutDoc.presStatus = 'edit';
             Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc);
-            CollectionDockingView.AddRightSplit(this.rootDoc);
+            CollectionDockingView.AddSplit(this.rootDoc, "right");
             this.layoutDoc.inOverlay = false;
         } else if (this.layoutDoc.context && docView) {
             this.layoutDoc.presStatus = 'manual';
@@ -1115,7 +1115,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 DockedFrameRenderer.PinDoc(doc, false);
                 this.gotoDocument(this.childDocs.length, this.itemIndex);
             } else {
-                this.props.addDocTab(doc, "onRight");
+                this.props.addDocTab(doc, "add:right");
             }
         }
     }
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 578061344..d50a10bdd 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -82,7 +82,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
     @action public FullScreen() {
         this._fullScreen = true;
         this.player && this.player.requestFullscreen();
-        this._youtubePlayer && this.props.addDocTab(this.rootDoc, "inTab");
+        this._youtubePlayer && this.props.addDocTab(this.rootDoc, "add");
     }
 
     choosePath(url: string) {
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index 924079096..f2658e77e 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -169,7 +169,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
     onPointerDownEnumerables = async (e: any) => {
         e.stopPropagation();
         const collview = await DocUtils.addFieldEnumerations(this._textBoxDoc, this._fieldKey, [{ title: this._fieldKey }]);
-        collview instanceof Doc && this.props.tbox.props.addDocTab(collview, "onRight");
+        collview instanceof Doc && this.props.tbox.props.addDocTab(collview, "add:right");
     }
 
 
@@ -191,7 +191,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
             list.map(c => c.heading).indexOf(this._fieldKey) === -1 && list.push(new SchemaHeaderField(this._fieldKey, "#f1efeb"));
             list.map(c => c.heading).indexOf("text") === -1 && list.push(new SchemaHeaderField("text", "#f1efeb"));
             alias._pivotField = this._fieldKey.startsWith("#") ? "#" : this._fieldKey;
-            this.props.tbox.props.addDocTab(alias, "onRight");
+            this.props.tbox.props.addDocTab(alias, "add:right");
         }
     }
 
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 356e36b76..c49e38f72 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -222,7 +222,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
 
                     const id = Utils.GenerateDeterministicGuid(this.dataDoc[Id] + key);
                     const allLinks = [{ href: Utils.prepend("/doc/" + id), title: value, targetId: id }];
-                    const link = this._editorView.state.schema.marks.linkAnchor.create({ allLinks, location: "onRight", title: value });
+                    const link = this._editorView.state.schema.marks.linkAnchor.create({ allLinks, location: "add:right", title: value });
                     const mval = this._editorView.state.schema.marks.metadataVal.create();
                     const offset = (tx.selection.to === range!.end - 1 ? -1 : 0);
                     tx = tx.addMark(textEndSelection - value.length + offset, textEndSelection, link).addMark(textEndSelection - value.length + offset, textEndSelection, mval);
@@ -465,7 +465,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         const linkDoc = data.linkDocument!;
         const anchor1Title = linkDoc.anchor1 instanceof Doc ? StrCast(linkDoc.anchor1.title) : "-untitled-";
         const anchor1Id = linkDoc.anchor1 instanceof Doc ? linkDoc.anchor1[Id] : "";
-        this.makeLinkToSelection(linkDoc[Id], anchor1Title, "onRight", anchor1Id);
+        this.makeLinkToSelection(linkDoc[Id], anchor1Title, "add:right", anchor1Id);
     }
 
     getNodeEndpoints(context: Node, node: Node): { from: number, to: number } | null {
@@ -811,7 +811,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 if (linkDoc) {
                     const anchor2Title = linkDoc.anchor2 instanceof Doc ? StrCast(linkDoc.anchor2.title) : "-untitled-";
                     const anchor2Id = linkDoc.anchor2 instanceof Doc ? linkDoc.anchor2[Id] : "";
-                    this.makeLinkToSelection(linkDoc[Id], anchor2Title, "onRight", anchor2Id);
+                    this.makeLinkToSelection(linkDoc[Id], anchor2Title, "add:right", anchor2Id);
                 }
             },
             { fireImmediately: true }
@@ -1096,7 +1096,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             const marks = [...node.marks];
             const linkIndex = marks.findIndex(mark => mark.type.name === "link");
             const allLinks = [{ href: Utils.prepend(`/doc/${linkId}`), title, linkId }];
-            const link = view.state.schema.mark(view.state.schema.marks.linkAnchor, { allLinks, location: "onRight", title, docref: true });
+            const link = view.state.schema.mark(view.state.schema.marks.linkAnchor, { allLinks, location: "add:right", title, docref: true });
             marks.splice(linkIndex === -1 ? 0 : linkIndex, 1, link);
             return node.mark(marks);
         }
@@ -1243,10 +1243,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         FormattedTextBoxComment.Hide();
         if (FormattedTextBoxComment.linkDoc) {
             if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) {
-                this.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "inTab" : "onRight");
+                this.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "add" : "add:right");
             } else {
                 DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, this.props.Document,
-                    (doc: Doc, followLinkLocation: string) => this.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation));
+                    (doc: Doc, followLinkLocation: string) => this.props.addDocTab(doc, e.ctrlKey ? "add" : followLinkLocation));
             }
         }
 
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index 55d225adc..f41f03620 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -103,7 +103,7 @@ export class FormattedTextBoxComment {
                             this.deleteLink();
                         } else if (FormattedTextBoxComment._followRef && FormattedTextBoxComment._followRef.contains(e.target as any)) {
                             if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) {
-                                textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "inTab" : "onRight");
+                                textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "add" : "add:right");
                             } else {
                                 const anchor = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(FormattedTextBoxComment.linkDoc.anchor1, Doc)), textBox.dataDoc) ?
                                     Cast(FormattedTextBoxComment.linkDoc.anchor2, Doc) : (Cast(FormattedTextBoxComment.linkDoc.anchor1, Doc))
@@ -112,28 +112,28 @@ export class FormattedTextBoxComment {
 
                                 if (FormattedTextBoxComment.linkDoc.follow) {
                                     if (FormattedTextBoxComment.linkDoc.follow === "Default") {
-                                        DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "onRight"), false);
+                                        DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "add:right"), false);
                                     } else if (FormattedTextBoxComment.linkDoc.follow === "Always open in right tab") {
-                                        if (target) { textBox.props.addDocTab(target, "onRight"); }
+                                        if (target) { textBox.props.addDocTab(target, "add:right"); }
                                     } else if (FormattedTextBoxComment.linkDoc.follow === "Always open in new tab") {
-                                        if (target) { textBox.props.addDocTab(target, "inTab"); }
+                                        if (target) { textBox.props.addDocTab(target, "add"); }
                                     }
                                 } else {
-                                    DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "onRight"), false);
+                                    DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "add:right"), false);
                                 }
                             }
                         } else {
                             if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) {
-                                textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "inTab" : "onRight");
+                                textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "add" : "add:right");
                             } else {
                                 DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document,
-                                    (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation));
+                                    (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "add" : followLinkLocation));
                             }
                         }
 
                     }
                 } else if (textBox && (FormattedTextBoxComment.tooltipText as any).href) {
-                    textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400, UseCors: true }), "onRight");
+                    textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400, UseCors: true }), "add:right");
                 }
                 keep && textBox && FormattedTextBoxComment.start !== undefined && textBox.adoptAnnotation(
                     FormattedTextBoxComment.start, FormattedTextBoxComment.end, FormattedTextBoxComment.mark);
diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
index a65eea50f..c6bacc1a8 100644
--- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
+++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
@@ -104,7 +104,7 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
     //Command to create a new Tab with a PDF of all the command shortcuts
     bind("Mod-/", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
         const newDoc = Docs.Create.PdfDocument(Utils.prepend("/assets/cheat-sheet.pdf"), { _fitWidth: true, _width: 300, _height: 300 });
-        props.addDocTab(newDoc, "onRight");
+        props.addDocTab(newDoc, "add:right");
     });
 
     //Commands to modify BlockType
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 399f72608..307238ea1 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -810,7 +810,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
             <div className="dropdown link-menu">
                 <p>Linked to:</p>
                 <input value={link} placeholder="Enter URL" onChange={onLinkChange} />
-                <button className="make-button" onPointerDown={e => this.makeLinkToURL(link, "onRight")}>Apply hyperlink</button>
+                <button className="make-button" onPointerDown={e => this.makeLinkToURL(link, "add:right")}>Apply hyperlink</button>
                 <div className="divider"></div>
                 <button className="remove-button" onPointerDown={e => this.deleteLink()}>Remove link</button>
             </div>;
@@ -857,7 +857,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
     // TODO: should check for valid URL
     @undoBatch
     makeLinkToURL = (target: string, lcoation: string) => {
-        ((this.view as any)?.TextView as FormattedTextBox).makeLinkToSelection("", target, "onRight", "", target);
+        ((this.view as any)?.TextView as FormattedTextBox).makeLinkToSelection("", target, "onRadd:rightight", "", target);
     }
 
     @undoBatch
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index 7e632a0ee..3fadfe842 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -279,7 +279,7 @@ export class RichTextRules {
                                 DocUtils.Publish(target, docid, returnFalse, returnFalse);
                                 DocUtils.MakeLink({ doc: this.Document }, { doc: target }, "portal to");
                             });
-                            const link = state.schema.marks.linkAnchor.create({ href: Utils.prepend("/doc/" + docid), location: "onRight", title: docid, targetId: docid });
+                            const link = state.schema.marks.linkAnchor.create({ href: Utils.prepend("/doc/" + docid), location: "add:right", title: docid, targetId: docid });
                             return state.tr.deleteRange(end - 1, end).deleteRange(start, start + 2).addMark(start, end - 3, link);
                         }
                         return state.tr;
diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts
index 1616500f6..64f7d27e5 100644
--- a/src/client/views/nodes/formattedText/nodes_rts.ts
+++ b/src/client/views/nodes/formattedText/nodes_rts.ts
@@ -148,7 +148,7 @@ export const nodes: { [index: string]: NodeSpec } = {
             alt: { default: null },
             title: { default: null },
             float: { default: "left" },
-            location: { default: "onRight" },
+            location: { default: "add:right" },
             docid: { default: "" }
         },
         group: "inline",
@@ -177,7 +177,7 @@ export const nodes: { [index: string]: NodeSpec } = {
             height: { default: 100 },
             title: { default: null },
             float: { default: "right" },
-            location: { default: "onRight" },
+            location: { default: "add:right" },
             hidden: { default: false },
             fieldKey: { default: "" },
             docid: { default: "" },
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 98638ecc2..a33068a18 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -99,7 +99,7 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
         else if (e.button === 0) {
             const annoGroup = await Cast(this.props.document.group, Doc);
             if (annoGroup) {
-                DocumentManager.Instance.FollowLink(undefined, annoGroup, (doc, followLinkLocation) => this.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation), false, undefined);
+                DocumentManager.Instance.FollowLink(undefined, annoGroup, (doc, followLinkLocation) => this.props.addDocTab(doc, e.ctrlKey ? "add" : followLinkLocation), false, undefined);
                 e.stopPropagation();
             }
         }
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index ed33ac822..d89e66ec5 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -604,7 +604,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
                     if (!e.aborted && e.annoDragData && !e.annoDragData.linkedToDoc) {
                         const link = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation");
                         annotationDoc.isLinkButton = true;
-                        if (link) link.followLinkLocation = "onRight";
+                        if (link) link.followLinkLocation = "add:right";
                     }
                 }
             });
diff --git a/src/fields/RichTextUtils.ts b/src/fields/RichTextUtils.ts
index a590c88c4..0b5f14d74 100644
--- a/src/fields/RichTextUtils.ts
+++ b/src/fields/RichTextUtils.ts
@@ -278,7 +278,7 @@ export namespace RichTextUtils {
             } else {
                 docid = backingDocId;
             }
-            return schema.node("image", { src, agnostic, width, docid, float: null, location: "onRight" });
+            return schema.node("image", { src, agnostic, width, docid, float: null, location: "add:right" });
         };
 
         const textNode = (schema: any, run: docs_v1.Schema$TextRun) => {
-- 
cgit v1.2.3-70-g09d2


From 0b798005fd4e917ecad4a961d638e1062f618d2c Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 1 Sep 2020 00:06:09 -0400
Subject: fixed shortcut buttons not showing up.  fixed nex/prev search buttons
 not showing up.  fixed search drag/delete/open buttons not showing up.

---
 src/client/views/MainView.tsx                      | 76 ++++++++++------------
 .../views/collections/CollectionSchemaCells.tsx    |  2 +-
 .../views/collections/CollectionSchemaView.scss    |  1 +
 src/client/views/search/SearchBox.tsx              |  2 +-
 4 files changed, 39 insertions(+), 42 deletions(-)

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

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index d479f0f78..4eccbaeb1 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -297,41 +297,40 @@ export class MainView extends React.Component {
     }
 
     @computed get flyout() {
-        return !this._sidebarContent || !this._flyoutWidth ? (null) :
-            <div className={`mainView-libraryFlyout${this._flyoutWidth ? "" : "-out"}`} style={{ minWidth: this._flyoutWidth, width: this._flyoutWidth }} >
-                <div className="mainView-contentArea" >
-                    <DocumentView
-                        Document={this._sidebarContent}
-                        DataDoc={undefined}
-                        LibraryPath={emptyPath}
-                        addDocument={undefined}
-                        addDocTab={this.addDocTabFunc}
-                        pinToPres={emptyFunction}
-                        NativeHeight={returnZero}
-                        NativeWidth={returnZero}
-                        rootSelected={returnTrue}
-                        removeDocument={returnFalse}
-                        onClick={undefined}
-                        ScreenToLocalTransform={this.mainContainerXf}
-                        ContentScaling={returnOne}
-                        PanelWidth={this.flyoutWidthFunc}
-                        PanelHeight={this.getContentsHeight}
-                        renderDepth={0}
-                        focus={emptyFunction}
-                        backgroundColor={this.defaultBackgroundColors}
-                        parentActive={returnTrue}
-                        whenActiveChanged={emptyFunction}
-                        bringToFront={emptyFunction}
-                        docFilters={returnEmptyFilter}
-                        searchFilterDocs={returnEmptyDoclist}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
-                        relative={true}
-                        forcedBackgroundColor={() => "lightgrey"}
-                    />
-                </div>
-                {this.docButtons}
-            </div>;
+        return <div className={`mainView-libraryFlyout${this._flyoutWidth ? "" : "-out"}`} style={{ minWidth: this._flyoutWidth, width: this._flyoutWidth }} >
+            <div className="mainView-contentArea" >
+                <DocumentView
+                    Document={this._sidebarContent}
+                    DataDoc={undefined}
+                    LibraryPath={emptyPath}
+                    addDocument={undefined}
+                    addDocTab={this.addDocTabFunc}
+                    pinToPres={emptyFunction}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
+                    rootSelected={returnTrue}
+                    removeDocument={returnFalse}
+                    onClick={undefined}
+                    ScreenToLocalTransform={this.mainContainerXf}
+                    ContentScaling={returnOne}
+                    PanelWidth={this.flyoutWidthFunc}
+                    PanelHeight={this.getContentsHeight}
+                    renderDepth={0}
+                    focus={emptyFunction}
+                    backgroundColor={this.defaultBackgroundColors}
+                    parentActive={returnTrue}
+                    whenActiveChanged={emptyFunction}
+                    bringToFront={emptyFunction}
+                    docFilters={returnEmptyFilter}
+                    searchFilterDocs={returnEmptyDoclist}
+                    ContainingCollectionView={undefined}
+                    ContainingCollectionDoc={undefined}
+                    relative={true}
+                    forcedBackgroundColor={() => "lightgrey"}
+                />
+            </div>
+            {this.docButtons}
+        </div>;
     }
 
     @computed get menuPanel() {
@@ -371,19 +370,16 @@ export class MainView extends React.Component {
     @action
     selectMenu = (button: Doc) => {
         const title = StrCast(Doc.GetProto(button).title);
-        if (this._panelContent === title && this._flyoutWidth) {
-            this.closeFlyout();
-        } else {
+        this.closeFlyout();
+        if (this._panelContent !== title || !this._flyoutWidth) {
             switch (this._panelContent = title) {
                 case "Settings":
                     SettingsManager.Instance.open();
-                    this.closeFlyout();
                     break;
                 case "Catalog":
                     SearchBox.Instance._searchFullDB = "My Stuff";
                     SearchBox.Instance.newsearchstring = "";
                     SearchBox.Instance.enter(undefined);
-                    this.closeFlyout();
                     break;
                 default:
                     this._sidebarContent.proto = button.target as any;
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 0d3a951cf..18ae260e8 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -514,7 +514,7 @@ export class CollectionSchemaCheckboxCell extends CollectionSchemaCell {
 @observer
 export class CollectionSchemaButtons extends CollectionSchemaCell {
     render() {
-        return !this._rowDoc._searchDoc || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this._rowDoc.type) as DocumentType) ? <></> :
+        return !this.props.Document._searchDoc || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this._rowDoc.type) as DocumentType) ? <></> :
             <div style={{ paddingTop: 8, paddingLeft: 3 }} >
                 <button style={{ padding: 2, left: 77 }} onClick={() => Doc.SearchMatchNext(this._rowDoc, true)}>
                     <FontAwesomeIcon icon="arrow-up" size="sm" />
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
index a8ec1db39..8d2f645d9 100644
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ b/src/client/views/collections/CollectionSchemaView.scss
@@ -409,6 +409,7 @@ button.add-column {
             display: flex;
             flex-direction: column;
             justify-content: center;
+            z-index: 2;
 
             &:hover {
                 color: gray;
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index ee38046be..7ce772748 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -381,7 +381,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             Doc.UnBrushDoc(result[0]);
             Doc.ClearSearchMatches();
         });
-        close && (this._searchbarOpen = false);
+        close && (this.open = this._searchbarOpen = false);
     }
 
     @action.bound
-- 
cgit v1.2.3-70-g09d2

