From 525766cd02ec38174334e62709c36a3b0caa208a Mon Sep 17 00:00:00 2001
From: andrewdkim <adkim414@gmail.com>
Date: Sat, 22 Feb 2020 14:06:39 -0500
Subject: new file

---
 src/client/views/SearchDocBox.tsx | 198 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 198 insertions(+)
 create mode 100644 src/client/views/SearchDocBox.tsx

(limited to 'src/client/views/SearchDocBox.tsx')

diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
new file mode 100644
index 000000000..596129c73
--- /dev/null
+++ b/src/client/views/SearchDocBox.tsx
@@ -0,0 +1,198 @@
+import { observer } from "mobx-react";
+import React = require("react");
+import { observable, action, computed, runInAction } from "mobx";
+import Measure from "react-measure";
+import "./RecommendationsBox.scss";
+import { Doc, DocListCast, WidthSym, HeightSym } from "../../new_fields/Doc";
+import { DocumentIcon } from "./nodes/DocumentIcon";
+import { StrCast, NumCast } from "../../new_fields/Types";
+import { returnFalse, emptyFunction, returnEmptyString, returnOne } from "../../Utils";
+import { Transform } from "../util/Transform";
+import { ObjectField } from "../../new_fields/ObjectField";
+import { DocumentView } from "./nodes/DocumentView";
+import { DocumentType } from '../documents/DocumentTypes';
+import { ClientRecommender } from "../ClientRecommender";
+import { DocServer } from "../DocServer";
+import { Id } from "../../new_fields/FieldSymbols";
+import { FieldView, FieldViewProps } from "./nodes/FieldView";
+import { DocumentManager } from "../util/DocumentManager";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { library } from "@fortawesome/fontawesome-svg-core";
+import { faBullseye, faLink } from "@fortawesome/free-solid-svg-icons";
+import { DocUtils } from "../documents/Documents";
+
+export interface RecProps {
+    documents: { preview: Doc, similarity: number }[];
+    node: Doc;
+}
+
+library.add(faBullseye, faLink);
+
+@observer
+export class SearchDocBox extends React.Component<FieldViewProps> {
+
+    public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(SearchDocBox, fieldKey); }
+
+    // @observable private _display: boolean = false;
+    @observable private _pageX: number = 0;
+    @observable private _pageY: number = 0;
+    @observable private _width: number = 0;
+    @observable private _height: number = 0;
+    @observable.shallow private _docViews: JSX.Element[] = [];
+    // @observable private _documents: { preview: Doc, score: number }[] = [];
+    private previewDocs: Doc[] = [];
+
+    constructor(props: FieldViewProps) {
+        super(props);
+    }
+
+    @action
+    private DocumentIcon(doc: Doc) {
+        let layoutresult = StrCast(doc.type);
+        let renderDoc = doc;
+        //let box: number[] = [];
+        if (layoutresult.indexOf(DocumentType.COL) !== -1) {
+            renderDoc = Doc.MakeDelegate(renderDoc);
+        }
+        let returnXDimension = () => 150;
+        let returnYDimension = () => 150;
+        let scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension());
+        //let scale = () => 1;
+        let newRenderDoc = Doc.MakeAlias(renderDoc); ///   newRenderDoc -> renderDoc -> render"data"Doc -> TextProt
+        newRenderDoc.height = NumCast(this.props.Document.documentIconHeight);
+        newRenderDoc.autoHeight = false;
+        const docview = <div>
+            <DocumentView
+                fitToBox={StrCast(doc.type).indexOf(DocumentType.COL) !== -1}
+                Document={newRenderDoc}
+                addDocument={returnFalse}
+                removeDocument={returnFalse}
+                ruleProvider={undefined}
+                ScreenToLocalTransform={Transform.Identity}
+                addDocTab={returnFalse}
+                pinToPres={returnFalse}
+                renderDepth={1}
+                PanelWidth={returnXDimension}
+                PanelHeight={returnYDimension}
+                focus={emptyFunction}
+                backgroundColor={returnEmptyString}
+                parentActive={returnFalse}
+                whenActiveChanged={returnFalse}
+                bringToFront={emptyFunction}
+                zoomToScale={emptyFunction}
+                getScale={returnOne}
+                ContainingCollectionView={undefined}
+                ContainingCollectionDoc={undefined}
+                ContentScaling={scale}
+            />
+        </div>;
+        return docview;
+
+    }
+
+    // @action
+    // closeMenu = () => {
+    //     this._display = false;
+    //     this.previewDocs.forEach(doc => DocServer.DeleteDocument(doc[Id]));
+    //     this.previewDocs = [];
+    // }
+
+    // @action
+    // resetDocuments = () => {
+    //     this._documents = [];
+    // }
+
+    // @action
+    // displayRecommendations(x: number, y: number) {
+    //     this._pageX = x;
+    //     this._pageY = y;
+    //     this._display = true;
+    // }
+
+    static readonly buffer = 20;
+
+    // get pageX() {
+    //     const x = this._pageX;
+    //     if (x < 0) {
+    //         return 0;
+    //     }
+    //     const width = this._width;
+    //     if (x + width > window.innerWidth - RecommendationsBox.buffer) {
+    //         return window.innerWidth - RecommendationsBox.buffer - width;
+    //     }
+    //     return x;
+    // }
+
+    // get pageY() {
+    //     const y = this._pageY;
+    //     if (y < 0) {
+    //         return 0;
+    //     }
+    //     const height = this._height;
+    //     if (y + height > window.innerHeight - RecommendationsBox.buffer) {
+    //         return window.innerHeight - RecommendationsBox.buffer - height;
+    //     }
+    //     return y;
+    // }
+
+    // get createDocViews() {
+    //     return DocListCast(this.props.Document.data).map(doc => {
+    //         return (
+    //             <div className="content">
+    //                 <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
+    //                     {this.DocumentIcon(doc)}
+    //                 </span>
+    //                 <span className="score">{NumCast(doc.score).toFixed(4)}</span>
+    //                 <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
+    //                     <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
+    //                 </div>
+    //                 <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}>
+    //                     <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
+    //                 </div>
+    //             </div>
+    //         );
+    //     });
+    // }
+
+    componentDidMount() { //TODO: invoking a computedFn from outside an reactive context won't be memoized, unless keepAlive is set
+        runInAction(() => {
+            if (this._docViews.length === 0) {
+                this._docViews = DocListCast(this.props.Document.data).map(doc => {
+                    return (
+                        <div className="content">
+                            <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
+                                {this.DocumentIcon(doc)}
+                            </span>
+                            <span className="score">{NumCast(doc.score).toFixed(4)}</span>
+                            <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
+                                <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
+                            </div>
+                            <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}>
+                                <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
+                            </div>
+                        </div>
+                    );
+                });
+            }
+        });
+    }
+
+    render() { //TODO: Invariant violation: max depth exceeded error. Occurs when images are rendered. 
+        // if (!this._display) {
+        //     return null;
+        // }
+        // let style = { left: this.pageX, top: this.pageY };
+        //const transform = "translate(" + (NumCast(this.props.node.x) + 350) + "px, " + NumCast(this.props.node.y) + "px"
+        // let title = StrCast((this.props.Document.sourceDoc as Doc).title);
+        // if (title.length > 15) {
+        //     title = title.substring(0, 15) + "...";
+        // }
+        return (
+            <div className="rec-scroll">
+                {this._docViews}
+            </div>
+        );
+    }
+    // 
+    // 
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From ad83dfcfaea5a6b525351b022158ebf5ff1f8c2f Mon Sep 17 00:00:00 2001
From: andrewdkim <adkim414@gmail.com>
Date: Sat, 22 Feb 2020 15:00:52 -0500
Subject: replacing search drag functionality

---
 solr-8.3.1/bin/solr-8983.pid                       |  2 +-
 src/client/documents/DocumentTypes.ts              |  2 +-
 src/client/documents/Documents.ts                  |  7 +--
 src/client/views/SearchDocBox.tsx                  | 54 +++++++++++++---------
 src/client/views/search/SearchBox.scss             |  2 +-
 src/client/views/search/SearchBox.tsx              |  3 +-
 .../authentication/models/current_user_utils.ts    |  2 +-
 7 files changed, 42 insertions(+), 30 deletions(-)

(limited to 'src/client/views/SearchDocBox.tsx')

diff --git a/solr-8.3.1/bin/solr-8983.pid b/solr-8.3.1/bin/solr-8983.pid
index d1b546ea3..2dfa22ed7 100644
--- a/solr-8.3.1/bin/solr-8983.pid
+++ b/solr-8.3.1/bin/solr-8983.pid
@@ -1 +1 @@
-7100
+13872
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index e02382661..adc61aa80 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -28,5 +28,5 @@ export enum DocumentType {
     PDFANNO = "pdfanno",
     INK = "ink",
     DOCUMENT = "document",
-    SEARCH = "search",
+    SEARCHBOX = "searchbox",
 }
\ No newline at end of file
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 144554cbc..86e459561 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -46,6 +46,7 @@ import { DocumentType } from "./DocumentTypes";
 import { RecommendationsBox } from "../views/RecommendationsBox";
 import { SearchDocBox } from "../views/SearchDocBox";
 
+
 //import { PresBox } from "../views/nodes/PresBox";
 //import { PresField } from "../../new_fields/PresField";
 import { LinkFollowBox } from "../views/linking/LinkFollowBox";
@@ -258,7 +259,7 @@ export namespace Docs {
                 layout: { view: InkingStroke, dataField: data },
                 options: { backgroundColor: "transparent" }
             }],
-            [DocumentType.SEARCH, {
+            [DocumentType.SEARCHBOX, {
                 layout: { view: SearchDocBox },
                 options: { width: 200, height: 200 },
             }]
@@ -594,8 +595,8 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.RECOMMENDATION), new List<Doc>(data), options);
         }
 
-        export function SearchDocument(options: DocumentOptions = {}) {
-            return InstanceFromProto(Prototypes.get(DocumentType.SEARCH), new List<Doc>(), options);
+        export function SearchDocument(documents: Array<Doc>, options: DocumentOptions = {}) {
+            return InstanceFromProto(Prototypes.get(DocumentType.SEARCHBOX), new List(documents), options);
         }
 
         export type DocConfig = {
diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
index 596129c73..c64b7285a 100644
--- a/src/client/views/SearchDocBox.tsx
+++ b/src/client/views/SearchDocBox.tsx
@@ -19,7 +19,8 @@ import { DocumentManager } from "../util/DocumentManager";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { library } from "@fortawesome/fontawesome-svg-core";
 import { faBullseye, faLink } from "@fortawesome/free-solid-svg-icons";
-import { DocUtils } from "../documents/Documents";
+import { DocUtils, Docs } from "../documents/Documents";
+import { ContentFittingDocumentView } from "./nodes/ContentFittingDocumentView";
 
 export interface RecProps {
     documents: { preview: Doc, similarity: number }[];
@@ -156,27 +157,33 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
 
     componentDidMount() { //TODO: invoking a computedFn from outside an reactive context won't be memoized, unless keepAlive is set
         runInAction(() => {
-            if (this._docViews.length === 0) {
-                this._docViews = DocListCast(this.props.Document.data).map(doc => {
-                    return (
-                        <div className="content">
-                            <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
-                                {this.DocumentIcon(doc)}
-                            </span>
-                            <span className="score">{NumCast(doc.score).toFixed(4)}</span>
-                            <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
-                                <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
-                            </div>
-                            <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}>
-                                <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
-                            </div>
-                        </div>
-                    );
-                });
-            }
+            //if (this._docViews.length === 0) {
+            //this._docViews =
+            this.content = (Docs.Create.TreeDocument(DocListCast(Doc.GetProto(this.props.Document).data), { _width: 200, _height: 400, backgroundColor: "grey", title: `Search Docs: "Results"` }));
+
+            // this._docViews = DocListCast(this.props.Document.data).map(doc => {
+            //     return (
+            //         <div className="content">
+            //             <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
+            //                 {this.DocumentIcon(doc)}
+            //             </span>
+            //             <span className="score">{NumCast(doc.score).toFixed(4)}</span>
+            //             <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
+            //                 <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
+            //             </div>
+            //             <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}>
+            //                 <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
+            //             </div>
+            //         </div>
+            //     );
+            // });
+            //}
         });
     }
 
+    @observable
+    private content: Doc | undefined;
+
     render() { //TODO: Invariant violation: max depth exceeded error. Occurs when images are rendered. 
         // if (!this._display) {
         //     return null;
@@ -188,9 +195,12 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
         //     title = title.substring(0, 15) + "...";
         // }
         return (
-            <div className="rec-scroll">
-                {this._docViews}
-            </div>
+            //<div className="rec-scroll">
+            <ContentFittingDocumentView {...this.props}
+                Document={this.content}
+                getTransform={this.props.ScreenToLocalTransform}>
+            </ContentFittingDocumentView>
+            //</div>
         );
     }
     // 
diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss
index f492ea773..11714748a 100644
--- a/src/client/views/search/SearchBox.scss
+++ b/src/client/views/search/SearchBox.scss
@@ -19,7 +19,7 @@
     padding-left: 2px;
     padding-right: 2px;
 
-    .searchBox-barChild {
+.searchBox-barChild {
 
         &.searchBox-collection {
             flex: 0 1 auto;
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index be13dae03..7628297c0 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -234,7 +234,8 @@ export class SearchBox extends React.Component {
                 y += 300;
             }
         }
-        return Docs.Create.TreeDocument(docs, { _width: 200, _height: 400, backgroundColor: "grey", title: `Search Docs: "${this._searchString}"` });
+        //return Docs.Create.TreeDocument(docs, { _width: 200, _height: 400, backgroundColor: "grey", title: `Search Docs: "${this._searchString}"` });
+        return Docs.Create.SearchDocument(docs, { _width: 200, _height: 400, backgroundColor: "grey", title: `Search Docs: "${this._searchString}"` });
     }
 
     @action.bound
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index ec6fdc021..58958f1fc 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -64,7 +64,7 @@ export class CurrentUserUtils {
             { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc },
             { title: "use scrubber", icon: "eraser", click: 'activateScrubber(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "green", activePen: doc },
             { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc },
-            { title: "searc", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.SearchDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 200, title: "an image of a cat" })' },
+            { title: "search", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.SearchDocument({ _width: 200, title: "an image of a cat" })' },
 
 
         ];
-- 
cgit v1.2.3-70-g09d2


From ac59127b264386bdfbf6443822984d002afb7da9 Mon Sep 17 00:00:00 2001
From: andrewdkim <adkim414@gmail.com>
Date: Sun, 23 Feb 2020 16:47:40 -0500
Subject: css menu

---
 src/client/documents/Documents.ts     |   2 +
 src/client/views/SearchDocBox.tsx     | 213 +++++++++++-----------------------
 src/client/views/search/SearchBox.tsx |   2 +-
 3 files changed, 72 insertions(+), 145 deletions(-)

(limited to 'src/client/views/SearchDocBox.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 86e459561..8ade14251 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -146,6 +146,8 @@ export interface DocumentOptions {
     flexDirection?: "unset" | "row" | "column" | "row-reverse" | "column-reverse";
     selectedIndex?: number;
     syntaxColor?: string; // can be applied to text for syntax highlighting all matches in the text
+    searchText?: string, //for searchbox
+
 }
 
 class EmptyBox {
diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
index c64b7285a..da0872c43 100644
--- a/src/client/views/SearchDocBox.tsx
+++ b/src/client/views/SearchDocBox.tsx
@@ -2,10 +2,10 @@ import { observer } from "mobx-react";
 import React = require("react");
 import { observable, action, computed, runInAction } from "mobx";
 import Measure from "react-measure";
-import "./RecommendationsBox.scss";
+import "./SearchBoxDoc.scss";
 import { Doc, DocListCast, WidthSym, HeightSym } from "../../new_fields/Doc";
 import { DocumentIcon } from "./nodes/DocumentIcon";
-import { StrCast, NumCast } from "../../new_fields/Types";
+import { StrCast, NumCast, BoolCast } from "../../new_fields/Types";
 import { returnFalse, emptyFunction, returnEmptyString, returnOne } from "../../Utils";
 import { Transform } from "../util/Transform";
 import { ObjectField } from "../../new_fields/ObjectField";
@@ -21,13 +21,16 @@ import { library } from "@fortawesome/fontawesome-svg-core";
 import { faBullseye, faLink } from "@fortawesome/free-solid-svg-icons";
 import { DocUtils, Docs } from "../documents/Documents";
 import { ContentFittingDocumentView } from "./nodes/ContentFittingDocumentView";
+import { EditableView } from "./EditableView";
 
 export interface RecProps {
     documents: { preview: Doc, similarity: number }[];
     node: Doc;
+
 }
 
 library.add(faBullseye, faLink);
+export const keyPlaceholder = "Query";
 
 @observer
 export class SearchDocBox extends React.Component<FieldViewProps> {
@@ -45,164 +48,86 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
 
     constructor(props: FieldViewProps) {
         super(props);
+        this.editingMetadata = this.editingMetadata || false;
     }
 
-    @action
-    private DocumentIcon(doc: Doc) {
-        let layoutresult = StrCast(doc.type);
-        let renderDoc = doc;
-        //let box: number[] = [];
-        if (layoutresult.indexOf(DocumentType.COL) !== -1) {
-            renderDoc = Doc.MakeDelegate(renderDoc);
-        }
-        let returnXDimension = () => 150;
-        let returnYDimension = () => 150;
-        let scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension());
-        //let scale = () => 1;
-        let newRenderDoc = Doc.MakeAlias(renderDoc); ///   newRenderDoc -> renderDoc -> render"data"Doc -> TextProt
-        newRenderDoc.height = NumCast(this.props.Document.documentIconHeight);
-        newRenderDoc.autoHeight = false;
-        const docview = <div>
-            <DocumentView
-                fitToBox={StrCast(doc.type).indexOf(DocumentType.COL) !== -1}
-                Document={newRenderDoc}
-                addDocument={returnFalse}
-                removeDocument={returnFalse}
-                ruleProvider={undefined}
-                ScreenToLocalTransform={Transform.Identity}
-                addDocTab={returnFalse}
-                pinToPres={returnFalse}
-                renderDepth={1}
-                PanelWidth={returnXDimension}
-                PanelHeight={returnYDimension}
-                focus={emptyFunction}
-                backgroundColor={returnEmptyString}
-                parentActive={returnFalse}
-                whenActiveChanged={returnFalse}
-                bringToFront={emptyFunction}
-                zoomToScale={emptyFunction}
-                getScale={returnOne}
-                ContainingCollectionView={undefined}
-                ContainingCollectionDoc={undefined}
-                ContentScaling={scale}
-            />
-        </div>;
-        return docview;
 
+    @computed
+    private get editingMetadata() {
+        return BoolCast(this.props.Document.editingMetadata);
     }
 
-    // @action
-    // closeMenu = () => {
-    //     this._display = false;
-    //     this.previewDocs.forEach(doc => DocServer.DeleteDocument(doc[Id]));
-    //     this.previewDocs = [];
-    // }
-
-    // @action
-    // resetDocuments = () => {
-    //     this._documents = [];
-    // }
-
-    // @action
-    // displayRecommendations(x: number, y: number) {
-    //     this._pageX = x;
-    //     this._pageY = y;
-    //     this._display = true;
-    // }
+    @computed
+    private set editingMetadata(value: boolean) {
+        this.props.Document.editingMetadata = value;
+    }
 
     static readonly buffer = 20;
 
-    // get pageX() {
-    //     const x = this._pageX;
-    //     if (x < 0) {
-    //         return 0;
-    //     }
-    //     const width = this._width;
-    //     if (x + width > window.innerWidth - RecommendationsBox.buffer) {
-    //         return window.innerWidth - RecommendationsBox.buffer - width;
-    //     }
-    //     return x;
-    // }
-
-    // get pageY() {
-    //     const y = this._pageY;
-    //     if (y < 0) {
-    //         return 0;
-    //     }
-    //     const height = this._height;
-    //     if (y + height > window.innerHeight - RecommendationsBox.buffer) {
-    //         return window.innerHeight - RecommendationsBox.buffer - height;
-    //     }
-    //     return y;
-    // }
-
-    // get createDocViews() {
-    //     return DocListCast(this.props.Document.data).map(doc => {
-    //         return (
-    //             <div className="content">
-    //                 <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
-    //                     {this.DocumentIcon(doc)}
-    //                 </span>
-    //                 <span className="score">{NumCast(doc.score).toFixed(4)}</span>
-    //                 <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
-    //                     <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
-    //                 </div>
-    //                 <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}>
-    //                     <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
-    //                 </div>
-    //             </div>
-    //         );
-    //     });
-    // }
-
-    componentDidMount() { //TODO: invoking a computedFn from outside an reactive context won't be memoized, unless keepAlive is set
+    componentDidMount() {
         runInAction(() => {
-            //if (this._docViews.length === 0) {
-            //this._docViews =
-            this.content = (Docs.Create.TreeDocument(DocListCast(Doc.GetProto(this.props.Document).data), { _width: 200, _height: 400, backgroundColor: "grey", title: `Search Docs: "Results"` }));
-
-            // this._docViews = DocListCast(this.props.Document.data).map(doc => {
-            //     return (
-            //         <div className="content">
-            //             <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
-            //                 {this.DocumentIcon(doc)}
-            //             </span>
-            //             <span className="score">{NumCast(doc.score).toFixed(4)}</span>
-            //             <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
-            //                 <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
-            //             </div>
-            //             <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}>
-            //                 <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
-            //             </div>
-            //         </div>
-            //     );
-            // });
-            //}
+            this.content = (Docs.Create.TreeDocument(DocListCast(Doc.GetProto(this.props.Document).data), { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs: "Results"` }));
+            this.query = StrCast(this.props.Document.searchText);
         });
     }
 
     @observable
     private content: Doc | undefined;
 
-    render() { //TODO: Invariant violation: max depth exceeded error. Occurs when images are rendered. 
-        // if (!this._display) {
-        //     return null;
-        // }
-        // let style = { left: this.pageX, top: this.pageY };
-        //const transform = "translate(" + (NumCast(this.props.node.x) + 350) + "px, " + NumCast(this.props.node.y) + "px"
-        // let title = StrCast((this.props.Document.sourceDoc as Doc).title);
-        // if (title.length > 15) {
-        //     title = title.substring(0, 15) + "...";
-        // }
+    @action
+    updateKey = (newKey: string) => {
+        this.query = newKey;
+        //this.keyRef.current && this.keyRef.current.setIsFocused(false);
+        //this.query.length === 0 && (this.query = keyPlaceholder);
+        return true;
+    }
+
+    @computed
+    public get query() {
+        return StrCast(this.props.Document.query);
+    }
+
+    public set query(value: string) {
+        this.props.Document.query = value;
+    }
+
+    render() {
+        const isEditing = this.editingMetadata;
+        console.log(isEditing);
         return (
-            //<div className="rec-scroll">
-            <ContentFittingDocumentView {...this.props}
-                Document={this.content}
-                getTransform={this.props.ScreenToLocalTransform}>
-            </ContentFittingDocumentView>
-            //</div>
+            <div style={{ pointerEvents: "all" }}>
+                <div
+                    style={{
+                        position: "absolute",
+                        right: 0,
+                        width: 20,
+                        height: 20,
+                        background: "black",
+                        pointerEvents: "all",
+                        opacity: 1,
+                        transition: "0.4s opacity ease",
+                        zIndex: 99,
+                    }}
+                    title={"Add Metadata"}
+                    onClick={action(() => this.editingMetadata = !this.editingMetadata)}
+                />
+                <div className="editableclass" style={{ opacity: isEditing ? 1 : 0, pointerEvents: isEditing ? "auto" : "none", transition: "0.4s opacity ease", }}>
+                    <EditableView
+                        contents={this.query}
+                        SetValue={this.updateKey}
+                        GetValue={() => ""}
+                    />
+                </div>
+                <div style={{
+                    pointerEvents: "none",
+                }}>
+                    <ContentFittingDocumentView {...this.props}
+                        Document={this.content}
+                        getTransform={this.props.ScreenToLocalTransform}>
+                    </ContentFittingDocumentView>
+                </div>
+            </div >
         );
     }
-    // 
-    // 
+
 }
\ No newline at end of file
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 7628297c0..9af8829fa 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -235,7 +235,7 @@ export class SearchBox extends React.Component {
             }
         }
         //return Docs.Create.TreeDocument(docs, { _width: 200, _height: 400, backgroundColor: "grey", title: `Search Docs: "${this._searchString}"` });
-        return Docs.Create.SearchDocument(docs, { _width: 200, _height: 400, backgroundColor: "grey", title: `Search Docs: "${this._searchString}"` });
+        return Docs.Create.SearchDocument(docs, { _width: 200, _height: 400, searchText: this._searchString, title: `Search Docs: "${this._searchString}"` });
     }
 
     @action.bound
-- 
cgit v1.2.3-70-g09d2


From 6c389c764c39c9b446996cc1a4aa777a9302f677 Mon Sep 17 00:00:00 2001
From: Andy Rickert <andrew_rickert@brown.edu>
Date: Mon, 24 Feb 2020 21:58:12 -0500
Subject: researching tentatively works

---
 package-lock.json                 |  92 -----------
 package.json                      |   1 -
 src/client/views/SearchDocBox.tsx | 324 ++++++++++++++++++++++++++++++++++++--
 src/server/Recommender.ts         |   2 +-
 4 files changed, 316 insertions(+), 103 deletions(-)

(limited to 'src/client/views/SearchDocBox.tsx')

diff --git a/package-lock.json b/package-lock.json
index 833710fe7..f6b1e80da 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -287,17 +287,6 @@
             "resolved": "https://registry.npmjs.org/@tensorflow-models/universal-sentence-encoder/-/universal-sentence-encoder-1.2.2.tgz",
             "integrity": "sha512-fGCl/gwB7jmKCRI2FhgIBeIa/LCSUcjlEcckH2Bc2dIjhJ+2nspp+22lubxcseN6jjrmP42kkXt/reAPe+KJkQ=="
         },
-        "@tensorflow/tfjs": {
-            "version": "1.5.2",
-            "resolved": "https://registry.npmjs.org/@tensorflow/tfjs/-/tfjs-1.5.2.tgz",
-            "integrity": "sha512-BCvcbnkE/zMdORIGE7TFAiJU3zLLVUaRv/HyWucVVyHU40oU4L5mGyRXK6RwqU38KmeK3HSI5rUHop4cLNUaRQ==",
-            "requires": {
-                "@tensorflow/tfjs-converter": "1.5.2",
-                "@tensorflow/tfjs-core": "1.5.2",
-                "@tensorflow/tfjs-data": "1.5.2",
-                "@tensorflow/tfjs-layers": "1.5.2"
-            }
-        },
         "@tensorflow/tfjs-converter": {
             "version": "1.5.2",
             "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-1.5.2.tgz",
@@ -323,69 +312,6 @@
                 }
             }
         },
-        "@tensorflow/tfjs-data": {
-            "version": "1.5.2",
-            "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-data/-/tfjs-data-1.5.2.tgz",
-            "integrity": "sha512-ruCsTSyH67CADWthgLQlWKh8u8YGEXD+4vsW8uOGdFNcDFLcL0ffy4jsSzIV/X6NdPIWYsvSHmiz57LtgfCFew==",
-            "requires": {
-                "@types/node-fetch": "^2.1.2",
-                "node-fetch": "~2.1.2"
-            },
-            "dependencies": {
-                "node-fetch": {
-                    "version": "2.1.2",
-                    "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz",
-                    "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U="
-                }
-            }
-        },
-        "@tensorflow/tfjs-layers": {
-            "version": "1.5.2",
-            "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-layers/-/tfjs-layers-1.5.2.tgz",
-            "integrity": "sha512-fn2hi5D1sOKGEgiBCuoU/hTHO87znODweGivIn6x2HMtF1EC39QWroYQBWzJyrWWMOUZZ4nOFR6coA0Fkhc+nA=="
-        },
-        "@tensorflow/tfjs-node": {
-            "version": "1.5.2",
-            "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-node/-/tfjs-node-1.5.2.tgz",
-            "integrity": "sha512-qihOkKbCLTDcqe3TTDbA9v00PacMzPwhspV8MEHWpohVb7itqQ8cMSE8w38b2oA+FE38c1RI7KOd2qAl5bCNHA==",
-            "requires": {
-                "@tensorflow/tfjs": "1.5.2",
-                "adm-zip": "^0.4.11",
-                "google-protobuf": "^3.9.2",
-                "https-proxy-agent": "^2.2.1",
-                "node-pre-gyp": "0.14.0",
-                "progress": "^2.0.0",
-                "rimraf": "^2.6.2",
-                "tar": "^4.4.6"
-            },
-            "dependencies": {
-                "node-pre-gyp": {
-                    "version": "0.14.0",
-                    "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz",
-                    "integrity": "sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==",
-                    "requires": {
-                        "detect-libc": "^1.0.2",
-                        "mkdirp": "^0.5.1",
-                        "needle": "^2.2.1",
-                        "nopt": "^4.0.1",
-                        "npm-packlist": "^1.1.6",
-                        "npmlog": "^4.0.2",
-                        "rc": "^1.2.7",
-                        "rimraf": "^2.6.1",
-                        "semver": "^5.3.0",
-                        "tar": "^4.4.2"
-                    }
-                },
-                "rimraf": {
-                    "version": "2.7.1",
-                    "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
-                    "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
-                    "requires": {
-                        "glob": "^7.1.3"
-                    }
-                }
-            }
-        },
         "@trendmicro/react-buttons": {
             "version": "1.3.1",
             "resolved": "https://registry.npmjs.org/@trendmicro/react-buttons/-/react-buttons-1.3.1.tgz",
@@ -781,14 +707,6 @@
             "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.13.tgz",
             "integrity": "sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg=="
         },
-        "@types/node-fetch": {
-            "version": "2.5.4",
-            "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.4.tgz",
-            "integrity": "sha512-Oz6id++2qAOFuOlE1j0ouk1dzl3mmI1+qINPNBhi9nt/gVOz0G+13Ao6qjhdF0Ys+eOkhu6JnFmt38bR3H0POQ==",
-            "requires": {
-                "@types/node": "*"
-            }
-        },
         "@types/nodemailer": {
             "version": "4.6.8",
             "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-4.6.8.tgz",
@@ -6445,11 +6363,6 @@
                 }
             }
         },
-        "google-protobuf": {
-            "version": "3.11.3",
-            "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.11.3.tgz",
-            "integrity": "sha512-Sp8E+0AJLxmiPwAk9VH3MkYAmYYheNUhywIyXOS7wvRkqbIYcHtGzJzIYicNqYsqgKmY35F9hxRkI+ZTqTB4Tg=="
-        },
         "googleapis": {
             "version": "40.0.1",
             "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-40.0.1.tgz",
@@ -13423,11 +13336,6 @@
             "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
             "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
         },
-        "progress": {
-            "version": "2.0.3",
-            "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
-            "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
-        },
         "promise": {
             "version": "7.3.1",
             "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
diff --git a/package.json b/package.json
index 7e0adfba6..cd97e590c 100644
--- a/package.json
+++ b/package.json
@@ -61,7 +61,6 @@
         "@tensorflow-models/universal-sentence-encoder": "^1.2.2",
         "@tensorflow/tfjs-converter": "^1.3.2",
         "@tensorflow/tfjs-core": "^1.5.2",
-        "@tensorflow/tfjs-node": "^1.5.2",
         "@trendmicro/react-dropdown": "^1.3.0",
         "@types/adm-zip": "^0.4.32",
         "@types/animejs": "^2.0.2",
diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
index da0872c43..06d434789 100644
--- a/src/client/views/SearchDocBox.tsx
+++ b/src/client/views/SearchDocBox.tsx
@@ -2,10 +2,10 @@ import { observer } from "mobx-react";
 import React = require("react");
 import { observable, action, computed, runInAction } from "mobx";
 import Measure from "react-measure";
-import "./SearchBoxDoc.scss";
+//import "./SearchBoxDoc.scss";
 import { Doc, DocListCast, WidthSym, HeightSym } from "../../new_fields/Doc";
 import { DocumentIcon } from "./nodes/DocumentIcon";
-import { StrCast, NumCast, BoolCast } from "../../new_fields/Types";
+import { StrCast, NumCast, BoolCast, Cast } from "../../new_fields/Types";
 import { returnFalse, emptyFunction, returnEmptyString, returnOne } from "../../Utils";
 import { Transform } from "../util/Transform";
 import { ObjectField } from "../../new_fields/ObjectField";
@@ -22,6 +22,10 @@ import { faBullseye, faLink } from "@fortawesome/free-solid-svg-icons";
 import { DocUtils, Docs } from "../documents/Documents";
 import { ContentFittingDocumentView } from "./nodes/ContentFittingDocumentView";
 import { EditableView } from "./EditableView";
+import { SearchUtil } from "../util/SearchUtil";
+import { SearchItem } from "./search/SearchItem";
+import { FilterBox } from "./search/FilterBox";
+import { SearchBox } from "./search/SearchBox";
 
 export interface RecProps {
     documents: { preview: Doc, similarity: number }[];
@@ -35,8 +39,6 @@ export const keyPlaceholder = "Query";
 @observer
 export class SearchDocBox extends React.Component<FieldViewProps> {
 
-    public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(SearchDocBox, fieldKey); }
-
     // @observable private _display: boolean = false;
     @observable private _pageX: number = 0;
     @observable private _pageY: number = 0;
@@ -49,6 +51,8 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
     constructor(props: FieldViewProps) {
         super(props);
         this.editingMetadata = this.editingMetadata || false;
+        //SearchBox.Instance = this;
+        this.resultsScrolled = this.resultsScrolled.bind(this);
     }
 
 
@@ -57,7 +61,6 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
         return BoolCast(this.props.Document.editingMetadata);
     }
 
-    @computed
     private set editingMetadata(value: boolean) {
         this.props.Document.editingMetadata = value;
     }
@@ -66,16 +69,32 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
 
     componentDidMount() {
         runInAction(() => {
-            this.content = (Docs.Create.TreeDocument(DocListCast(Doc.GetProto(this.props.Document).data), { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs: "Results"` }));
             this.query = StrCast(this.props.Document.searchText);
+            this.content = (Docs.Create.TreeDocument(DocListCast(Doc.GetProto(this.props.Document).data), { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query}));
+
         });
+        if (this.inputRef.current) {
+            this.inputRef.current.focus();
+            runInAction(() => {
+                this._searchbarOpen = true;
+            });
+        }
     }
 
     @observable
     private content: Doc | undefined;
 
     @action
-    updateKey = (newKey: string) => {
+    updateKey = async (newKey: string) => {
+        if (newKey.length >1){
+            let newdocs= await this.getAllResults(this.query)
+            let things = newdocs.docs
+            console.log(things);
+            await runInAction(() => {
+                this.content=Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query });   
+                        });     
+                    }
+
         this.query = newKey;
         //this.keyRef.current && this.keyRef.current.setIsFocused(false);
         //this.query.length === 0 && (this.query = keyPlaceholder);
@@ -91,6 +110,293 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
         this.props.Document.query = value;
     }
 
+    @observable private _searchString: string = "";
+    @observable private _resultsOpen: boolean = false;
+    @observable private _searchbarOpen: boolean = false;
+    @observable private _results: [Doc, string[], string[]][] = [];
+    private _resultsSet = new Map<Doc, number>();
+    @observable private _openNoResults: boolean = false;
+    @observable private _visibleElements: JSX.Element[] = [];
+
+    private resultsRef = React.createRef<HTMLDivElement>();
+    public inputRef = React.createRef<HTMLInputElement>();
+
+    private _isSearch: ("search" | "placeholder" | undefined)[] = [];
+    private _numTotalResults = -1;
+    private _endIndex = -1;
+
+
+    private _maxSearchIndex: number = 0;
+    private _curRequest?: Promise<any> = undefined;
+
+    @action
+    getViews = async (doc: Doc) => {
+        const results = await SearchUtil.GetViewsOfDocument(doc);
+        let toReturn: Doc[] = [];
+        await runInAction(() => {
+            toReturn = results;
+        });
+        return toReturn;
+    }
+
+    @action.bound
+    onChange(e: React.ChangeEvent<HTMLInputElement>) {
+        this._searchString = e.target.value;
+
+        this._openNoResults = false;
+        this._results = [];
+        this._resultsSet.clear();
+        this._visibleElements = [];
+        this._numTotalResults = -1;
+        this._endIndex = -1;
+        this._curRequest = undefined;
+        this._maxSearchIndex = 0;
+    }
+
+    enter = async (e: React.KeyboardEvent) => {
+        console.log(e.key);
+        if (e.key === "Enter") {
+            let newdocs= await this.getAllResults(this.query)
+            let things = newdocs.docs
+            console.log(things);
+            this.content=Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs: "Results"` });
+        
+        }
+    }
+
+
+    @action
+    submitSearch = async () => {
+        let query = this._searchString;
+        query = FilterBox.Instance.getFinalQuery(query);
+        this._results = [];
+        this._resultsSet.clear();
+        this._isSearch = [];
+        this._visibleElements = [];
+        FilterBox.Instance.closeFilter();
+
+        //if there is no query there should be no result
+        if (query === "") {
+            return;
+        }
+        else {
+            this._endIndex = 12;
+            this._maxSearchIndex = 0;
+            this._numTotalResults = -1;
+            await this.getResults(query);
+        }
+
+        runInAction(() => {
+            this._resultsOpen = true;
+            this._searchbarOpen = true;
+            this._openNoResults = true;
+            this.resultsScrolled();
+        });
+    }
+
+    getAllResults = async (query: string) => {
+        return SearchUtil.Search(query, true, { fq: this.filterQuery, start: 0, rows: 10000000 });
+    }
+
+    private get filterQuery() {
+        const types = FilterBox.Instance.filterTypes;
+        const includeDeleted = FilterBox.Instance.getDataStatus();
+        return "NOT baseProto_b:true" + (includeDeleted ? "" : " AND NOT deleted_b:true") + (types ? ` AND (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}" OR type_t:"extension"`).join(" ")})` : "");
+    }
+
+
+    private NumResults = 25;
+    private lockPromise?: Promise<void>;
+    getResults = async (query: string) => {
+        if (this.lockPromise) {
+            await this.lockPromise;
+        }
+        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) => {
+
+                    // happens at the beginning
+                    if (res.numFound !== this._numTotalResults && this._numTotalResults === -1) {
+                        this._numTotalResults = res.numFound;
+                    }
+
+                    const highlighting = res.highlighting || {};
+                    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 highlights: typeof res.highlighting = {};
+                    docs.forEach((doc, index) => highlights[doc[Id]] = highlightList[index]);
+                    const filteredDocs = FilterBox.Instance.filterDocsByType(docs);
+                    runInAction(() => {
+                        // this._results.push(...filteredDocs);
+                        filteredDocs.forEach(doc => {
+                            const index = this._resultsSet.get(doc);
+                            const highlight = highlights[doc[Id]];
+                            const line = lines.get(doc[Id]) || [];
+                            const hlights = highlight ? Object.keys(highlight).map(key => key.substring(0, key.length - 2)) : [];
+                            if (index === undefined) {
+                                this._resultsSet.set(doc, this._results.length);
+                                this._results.push([doc, hlights, line]);
+                            } else {
+                                this._results[index][1].push(...hlights);
+                                this._results[index][2].push(...line);
+                            }
+                        });
+                    });
+
+                    this._curRequest = undefined;
+                }));
+                this._maxSearchIndex += this.NumResults;
+
+                await this._curRequest;
+            }
+            this.resultsScrolled();
+            res();
+        });
+        return this.lockPromise;
+    }
+
+    collectionRef = React.createRef<HTMLSpanElement>();
+    startDragCollection = async () => {
+        const res = await this.getAllResults(FilterBox.Instance.getFinalQuery(this._searchString));
+        const filtered = FilterBox.Instance.filterDocsByType(res.docs);
+        // console.log(this._results)
+        const docs = filtered.map(doc => {
+            const isProto = Doc.GetT(doc, "isPrototype", "boolean", true);
+            if (isProto) {
+                return Doc.MakeDelegate(doc);
+            } else {
+                return Doc.MakeAlias(doc);
+            }
+        });
+        let x = 0;
+        let y = 0;
+        for (const doc of docs.map(d => Doc.Layout(d))) {
+            doc.x = x;
+            doc.y = y;
+            const size = 200;
+            const aspect = NumCast(doc._nativeHeight) / NumCast(doc._nativeWidth, 1);
+            if (aspect > 1) {
+                doc._height = size;
+                doc._width = size / aspect;
+            } else if (aspect > 0) {
+                doc._width = size;
+                doc._height = size * aspect;
+            } else {
+                doc._width = size;
+                doc._height = size;
+            }
+            x += 250;
+            if (x > 1000) {
+                x = 0;
+                y += 300;
+            }
+        }
+        //return Docs.Create.TreeDocument(docs, { _width: 200, _height: 400, backgroundColor: "grey", title: `Search Docs: "${this._searchString}"` });
+        return Docs.Create.SearchDocument(docs, { _width: 200, _height: 400, searchText: this._searchString, title: `Search Docs: "${this._searchString}"` });
+    }
+
+    @action.bound
+    openSearch(e: React.SyntheticEvent) {
+        e.stopPropagation();
+        this._openNoResults = false;
+        FilterBox.Instance.closeFilter();
+        this._resultsOpen = true;
+        this._searchbarOpen = true;
+        FilterBox.Instance._pointerTime = e.timeStamp;
+    }
+
+    @action.bound
+    closeSearch = () => {
+        FilterBox.Instance.closeFilter();
+        this.closeResults();
+        this._searchbarOpen = false;
+    }
+
+    @action.bound
+    closeResults() {
+        this._resultsOpen = false;
+        this._results = [];
+        this._resultsSet.clear();
+        this._visibleElements = [];
+        this._numTotalResults = -1;
+        this._endIndex = -1;
+        this._curRequest = undefined;
+    }
+
+    @action
+    resultsScrolled = (e?: React.UIEvent<HTMLDivElement>) => {
+        if (!this.resultsRef.current) return;
+        const scrollY = e ? e.currentTarget.scrollTop : this.resultsRef.current ? this.resultsRef.current.scrollTop : 0;
+        const itemHght = 53;
+        const startIndex = Math.floor(Math.max(0, scrollY / itemHght));
+        const endIndex = Math.ceil(Math.min(this._numTotalResults - 1, startIndex + (this.resultsRef.current.getBoundingClientRect().height / itemHght)));
+
+        this._endIndex = endIndex === -1 ? 12 : endIndex;
+
+        if ((this._numTotalResults === 0 || this._results.length === 0) && this._openNoResults) {
+            this._visibleElements = [<div className="no-result">No Search Results</div>];
+            return;
+        }
+
+        if (this._numTotalResults <= this._maxSearchIndex) {
+            this._numTotalResults = this._results.length;
+        }
+
+        // only hit right at the beginning
+        // visibleElements is all of the elements (even the ones you can't see)
+        else if (this._visibleElements.length !== this._numTotalResults) {
+            // undefined until a searchitem is put in there
+            this._visibleElements = Array<JSX.Element>(this._numTotalResults === -1 ? 0 : this._numTotalResults);
+            // indicates if things are placeholders
+            this._isSearch = Array<undefined>(this._numTotalResults === -1 ? 0 : this._numTotalResults);
+        }
+
+        for (let i = 0; i < this._numTotalResults; i++) {
+            //if the index is out of the window then put a placeholder in
+            //should ones that have already been found get set to placeholders?
+            if (i < startIndex || i > endIndex) {
+                if (this._isSearch[i] !== "placeholder") {
+                    this._isSearch[i] = "placeholder";
+                    this._visibleElements[i] = <div className="searchBox-placeholder" key={`searchBox-placeholder-${i}`}>Loading...</div>;
+                }
+            }
+            else {
+                if (this._isSearch[i] !== "search") {
+                    let result: [Doc, string[], string[]] | undefined = undefined;
+                    if (i >= this._results.length) {
+                        this.getResults(this._searchString);
+                        if (i < this._results.length) result = this._results[i];
+                        if (result) {
+                            const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
+                            this._visibleElements[i] = <SearchItem doc={result[0]} query={this._searchString} key={result[0][Id]} lines={result[2]} highlighting={highlights} />;
+                            this._isSearch[i] = "search";
+                        }
+                    }
+                    else {
+                        result = this._results[i];
+                        if (result) {
+                            const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
+                            this._visibleElements[i] = <SearchItem doc={result[0]} query={this._searchString} key={result[0][Id]} lines={result[2]} highlighting={highlights} />;
+                            this._isSearch[i] = "search";
+                        }
+                    }
+                }
+            }
+        }
+        if (this._maxSearchIndex >= this._numTotalResults) {
+            this._visibleElements.length = this._results.length;
+            this._isSearch.length = this._results.length;
+        }
+    }
+
+    @computed
+    get resFull() { return this._numTotalResults <= 8; }
+
+    @computed
+    get resultHeight() { return this._numTotalResults * 70; }
+
     render() {
         const isEditing = this.editingMetadata;
         console.log(isEditing);
@@ -109,9 +415,9 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
                         zIndex: 99,
                     }}
                     title={"Add Metadata"}
-                    onClick={action(() => this.editingMetadata = !this.editingMetadata)}
+                    onDoubleClick={action(() => {this.editingMetadata = !this.editingMetadata })}
                 />
-                <div className="editableclass" style={{ opacity: isEditing ? 1 : 0, pointerEvents: isEditing ? "auto" : "none", transition: "0.4s opacity ease", }}>
+                <div className="editableclass" onKeyPress={this.enter} style={{ opacity: isEditing ? 1 : 0, pointerEvents: isEditing ? "auto" : "none", transition: "0.4s opacity ease", }}>
                     <EditableView
                         contents={this.query}
                         SetValue={this.updateKey}
diff --git a/src/server/Recommender.ts b/src/server/Recommender.ts
index 1d2cb3858..8684a29f1 100644
--- a/src/server/Recommender.ts
+++ b/src/server/Recommender.ts
@@ -9,7 +9,7 @@ var arxivapi = require('arxiv-api-node');
 import requestPromise = require("request-promise");
 import * as use from '@tensorflow-models/universal-sentence-encoder';
 import { Tensor } from "@tensorflow/tfjs-core/dist/tensor";
-require('@tensorflow/tfjs-node');
+//require('@tensorflow/tfjs-node');
 
 //http://gnuwin32.sourceforge.net/packages/make.htm
 
-- 
cgit v1.2.3-70-g09d2


From 177b5b587ccf53ce0354d2bb2c527bde5785230b Mon Sep 17 00:00:00 2001
From: Andy Rickert <andrew_rickert@brown.edu>
Date: Wed, 26 Feb 2020 17:52:51 -0500
Subject: fixing css and ui

---
 src/client/views/SearchDocBox.tsx | 31 ++++++++++++++++---------------
 1 file changed, 16 insertions(+), 15 deletions(-)

(limited to 'src/client/views/SearchDocBox.tsx')

diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
index 06d434789..5f308ff71 100644
--- a/src/client/views/SearchDocBox.tsx
+++ b/src/client/views/SearchDocBox.tsx
@@ -69,6 +69,8 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
 
     componentDidMount() {
         runInAction(() => {
+            console.log("didit"
+            );
             this.query = StrCast(this.props.Document.searchText);
             this.content = (Docs.Create.TreeDocument(DocListCast(Doc.GetProto(this.props.Document).data), { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query}));
 
@@ -86,16 +88,19 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
 
     @action
     updateKey = async (newKey: string) => {
+        this.query = newKey;
         if (newKey.length >1){
             let newdocs= await this.getAllResults(this.query)
             let things = newdocs.docs
             console.log(things);
-            await runInAction(() => {
-                this.content=Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query });   
-                        });     
+            console.log(this.content);
+            runInAction(() => {
+                this.content= Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query });   
+                        });
+            console.log(this.content);     
                     }
 
-        this.query = newKey;
+
         //this.keyRef.current && this.keyRef.current.setIsFocused(false);
         //this.query.length === 0 && (this.query = keyPlaceholder);
         return true;
@@ -399,9 +404,12 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
 
     render() {
         const isEditing = this.editingMetadata;
-        console.log(isEditing);
         return (
             <div style={{ pointerEvents: "all" }}>
+                <ContentFittingDocumentView {...this.props}
+                        Document={this.content}
+                        getTransform={this.props.ScreenToLocalTransform}>
+                s</ContentFittingDocumentView>
                 <div
                     style={{
                         position: "absolute",
@@ -413,25 +421,18 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
                         opacity: 1,
                         transition: "0.4s opacity ease",
                         zIndex: 99,
+                        top:0,
                     }}
                     title={"Add Metadata"}
-                    onDoubleClick={action(() => {this.editingMetadata = !this.editingMetadata })}
+                    onClick={action(() => {this.editingMetadata = !this.editingMetadata })}
                 />
-                <div className="editableclass" onKeyPress={this.enter} style={{ opacity: isEditing ? 1 : 0, pointerEvents: isEditing ? "auto" : "none", transition: "0.4s opacity ease", }}>
+                <div className="editableclass" onKeyPress={this.enter} style={{ opacity: isEditing ? 1 : 0, pointerEvents: isEditing ? "auto" : "none", transition: "0.4s opacity ease",position:"absolute",top:0,left:0, height:20, width:"-webkit-fill-available" }}>
                     <EditableView
                         contents={this.query}
                         SetValue={this.updateKey}
                         GetValue={() => ""}
                     />
                 </div>
-                <div style={{
-                    pointerEvents: "none",
-                }}>
-                    <ContentFittingDocumentView {...this.props}
-                        Document={this.content}
-                        getTransform={this.props.ScreenToLocalTransform}>
-                    </ContentFittingDocumentView>
-                </div>
             </div >
         );
     }
-- 
cgit v1.2.3-70-g09d2


From 14a2f361c73e468547d48792478e5e7e7e78f4d6 Mon Sep 17 00:00:00 2001
From: vellichora <fangrui_tong@brown.edu>
Date: Sat, 29 Feb 2020 13:52:53 -0500
Subject: filter UI

---
 package-lock.json                          |  41 +--
 src/client/views/SearchDocBox.tsx          |  34 +--
 src/client/views/search/CheckBox.tsx       | 146 +++++-----
 src/client/views/search/SearchBox.tsx      |  47 +++
 src/server/ApiManagers/SessionManager.ts   |  20 +-
 src/server/DashSession/DashSessionAgent.ts | 446 ++++++++++++++---------------
 src/server/index.ts                        |   4 +-
 7 files changed, 384 insertions(+), 354 deletions(-)

(limited to 'src/client/views/SearchDocBox.tsx')

diff --git a/package-lock.json b/package-lock.json
index f6b1e80da..e60950308 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5600,8 +5600,7 @@
                 },
                 "ansi-regex": {
                     "version": "2.1.1",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 },
                 "aproba": {
                     "version": "1.2.0",
@@ -5619,13 +5618,11 @@
                 },
                 "balanced-match": {
                     "version": "1.0.0",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 },
                 "brace-expansion": {
                     "version": "1.1.11",
                     "bundled": true,
-                    "optional": true,
                     "requires": {
                         "balanced-match": "^1.0.0",
                         "concat-map": "0.0.1"
@@ -5638,18 +5635,15 @@
                 },
                 "code-point-at": {
                     "version": "1.1.0",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 },
                 "concat-map": {
                     "version": "0.0.1",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 },
                 "console-control-strings": {
                     "version": "1.1.0",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 },
                 "core-util-is": {
                     "version": "1.0.2",
@@ -5752,8 +5746,7 @@
                 },
                 "inherits": {
                     "version": "2.0.4",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 },
                 "ini": {
                     "version": "1.3.5",
@@ -5763,7 +5756,6 @@
                 "is-fullwidth-code-point": {
                     "version": "1.0.0",
                     "bundled": true,
-                    "optional": true,
                     "requires": {
                         "number-is-nan": "^1.0.0"
                     }
@@ -5776,20 +5768,17 @@
                 "minimatch": {
                     "version": "3.0.4",
                     "bundled": true,
-                    "optional": true,
                     "requires": {
                         "brace-expansion": "^1.1.7"
                     }
                 },
                 "minimist": {
                     "version": "0.0.8",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 },
                 "minipass": {
                     "version": "2.9.0",
                     "bundled": true,
-                    "optional": true,
                     "requires": {
                         "safe-buffer": "^5.1.2",
                         "yallist": "^3.0.0"
@@ -5806,7 +5795,6 @@
                 "mkdirp": {
                     "version": "0.5.1",
                     "bundled": true,
-                    "optional": true,
                     "requires": {
                         "minimist": "0.0.8"
                     }
@@ -5887,8 +5875,7 @@
                 },
                 "number-is-nan": {
                     "version": "1.0.1",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 },
                 "object-assign": {
                     "version": "4.1.1",
@@ -5898,7 +5885,6 @@
                 "once": {
                     "version": "1.4.0",
                     "bundled": true,
-                    "optional": true,
                     "requires": {
                         "wrappy": "1"
                     }
@@ -5974,8 +5960,7 @@
                 },
                 "safe-buffer": {
                     "version": "5.1.2",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 },
                 "safer-buffer": {
                     "version": "2.1.2",
@@ -6005,7 +5990,6 @@
                 "string-width": {
                     "version": "1.0.2",
                     "bundled": true,
-                    "optional": true,
                     "requires": {
                         "code-point-at": "^1.0.0",
                         "is-fullwidth-code-point": "^1.0.0",
@@ -6023,7 +6007,6 @@
                 "strip-ansi": {
                     "version": "3.0.1",
                     "bundled": true,
-                    "optional": true,
                     "requires": {
                         "ansi-regex": "^2.0.0"
                     }
@@ -6062,13 +6045,11 @@
                 },
                 "wrappy": {
                     "version": "1.0.2",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 },
                 "yallist": {
                     "version": "3.1.1",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 }
             }
         },
diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
index 5f308ff71..5a76a882f 100644
--- a/src/client/views/SearchDocBox.tsx
+++ b/src/client/views/SearchDocBox.tsx
@@ -39,6 +39,8 @@ export const keyPlaceholder = "Query";
 @observer
 export class SearchDocBox extends React.Component<FieldViewProps> {
 
+    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SearchDocBox, fieldKey); }
+
     // @observable private _display: boolean = false;
     @observable private _pageX: number = 0;
     @observable private _pageY: number = 0;
@@ -72,7 +74,7 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
             console.log("didit"
             );
             this.query = StrCast(this.props.Document.searchText);
-            this.content = (Docs.Create.TreeDocument(DocListCast(Doc.GetProto(this.props.Document).data), { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query}));
+            this.content = (Docs.Create.TreeDocument(DocListCast(Doc.GetProto(this.props.Document).data), { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query }));
 
         });
         if (this.inputRef.current) {
@@ -89,16 +91,16 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
     @action
     updateKey = async (newKey: string) => {
         this.query = newKey;
-        if (newKey.length >1){
-            let newdocs= await this.getAllResults(this.query)
+        if (newKey.length > 1) {
+            let newdocs = await this.getAllResults(this.query);
             let things = newdocs.docs
             console.log(things);
             console.log(this.content);
             runInAction(() => {
-                this.content= Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query });   
-                        });
-            console.log(this.content);     
-                    }
+                this.content = Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query });
+            });
+            console.log(this.content);
+        }
 
 
         //this.keyRef.current && this.keyRef.current.setIsFocused(false);
@@ -161,11 +163,11 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
     enter = async (e: React.KeyboardEvent) => {
         console.log(e.key);
         if (e.key === "Enter") {
-            let newdocs= await this.getAllResults(this.query)
+            let newdocs = await this.getAllResults(this.query)
             let things = newdocs.docs
             console.log(things);
-            this.content=Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs: "Results"` });
-        
+            this.content = Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs: "Results"` });
+
         }
     }
 
@@ -407,9 +409,9 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
         return (
             <div style={{ pointerEvents: "all" }}>
                 <ContentFittingDocumentView {...this.props}
-                        Document={this.content}
-                        getTransform={this.props.ScreenToLocalTransform}>
-                s</ContentFittingDocumentView>
+                    Document={this.content}
+                    getTransform={this.props.ScreenToLocalTransform}>
+                    s</ContentFittingDocumentView>
                 <div
                     style={{
                         position: "absolute",
@@ -421,12 +423,12 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
                         opacity: 1,
                         transition: "0.4s opacity ease",
                         zIndex: 99,
-                        top:0,
+                        top: 0,
                     }}
                     title={"Add Metadata"}
-                    onClick={action(() => {this.editingMetadata = !this.editingMetadata })}
+                    onClick={action(() => { this.editingMetadata = !this.editingMetadata })}
                 />
-                <div className="editableclass" onKeyPress={this.enter} style={{ opacity: isEditing ? 1 : 0, pointerEvents: isEditing ? "auto" : "none", transition: "0.4s opacity ease",position:"absolute",top:0,left:0, height:20, width:"-webkit-fill-available" }}>
+                <div className="editableclass" onKeyPress={this.enter} style={{ opacity: isEditing ? 1 : 0, pointerEvents: isEditing ? "auto" : "none", transition: "0.4s opacity ease", position: "absolute", top: 0, left: 0, height: 20, width: "-webkit-fill-available" }}>
                     <EditableView
                         contents={this.query}
                         SetValue={this.updateKey}
diff --git a/src/client/views/search/CheckBox.tsx b/src/client/views/search/CheckBox.tsx
index a9d48219a..8c97d5dbc 100644
--- a/src/client/views/search/CheckBox.tsx
+++ b/src/client/views/search/CheckBox.tsx
@@ -17,8 +17,8 @@ interface CheckBoxProps {
 export class CheckBox extends React.Component<CheckBoxProps>{
     // true = checked, false = unchecked
     @observable private _status: boolean;
-    @observable private uncheckTimeline: anime.AnimeTimelineInstance;
-    @observable private checkTimeline: anime.AnimeTimelineInstance;
+    // @observable private uncheckTimeline: anime.AnimeTimelineInstance;
+    // @observable private checkTimeline: anime.AnimeTimelineInstance;
     @observable private checkRef: any;
     @observable private _resetReaction?: IReactionDisposer;
 
@@ -28,87 +28,87 @@ export class CheckBox extends React.Component<CheckBoxProps>{
         this._status = this.props.originalStatus;
         this.checkRef = React.createRef();
 
-        this.checkTimeline = anime.timeline({
-            loop: false,
-            autoplay: false,
-            direction: "normal",
-        }); this.uncheckTimeline = anime.timeline({
-            loop: false,
-            autoplay: false,
-            direction: "normal",
-        });
+        // this.checkTimeline = anime.timeline({
+        //     loop: false,
+        //     autoplay: false,
+        //     direction: "normal",
+        // }); this.uncheckTimeline = anime.timeline({
+        //     loop: false,
+        //     autoplay: false,
+        //     direction: "normal",
+        // });
     }
 
-    componentDidMount = () => {
-        this.uncheckTimeline.add({
-            targets: this.checkRef.current,
-            easing: "easeInOutQuad",
-            duration: 500,
-            opacity: 0,
-        });
-        this.checkTimeline.add({
-            targets: this.checkRef.current,
-            easing: "easeInOutQuad",
-            duration: 500,
-            strokeDashoffset: [anime.setDashoffset, 0],
-            opacity: 1
-        });
+    // componentDidMount = () => {
+    //     this.uncheckTimeline.add({
+    //         targets: this.checkRef.current,
+    //         easing: "easeInOutQuad",
+    //         duration: 500,
+    //         opacity: 0,
+    //     });
+    //     this.checkTimeline.add({
+    //         targets: this.checkRef.current,
+    //         easing: "easeInOutQuad",
+    //         duration: 500,
+    //         strokeDashoffset: [anime.setDashoffset, 0],
+    //         opacity: 1
+    //     });
 
-        if (this.props.originalStatus) {
-            this.checkTimeline.play();
-            this.checkTimeline.restart();
-        }
+    //     if (this.props.originalStatus) {
+    //         this.checkTimeline.play();
+    //         this.checkTimeline.restart();
+    //     }
 
-        this._resetReaction = reaction(
-            () => this.props.parent._resetBoolean,
-            () => {
-                if (this.props.parent._resetBoolean) {
-                    runInAction(() => {
-                        this.reset();
-                        this.props.parent._resetCounter++;
-                        if (this.props.parent._resetCounter === this.props.numCount) {
-                            this.props.parent._resetCounter = 0;
-                            this.props.parent._resetBoolean = false;
-                        }
-                    });
-                }
-            },
-        );
-    }
+    //     this._resetReaction = reaction(
+    //         () => this.props.parent._resetBoolean,
+    //         () => {
+    //             if (this.props.parent._resetBoolean) {
+    //                 runInAction(() => {
+    //                     this.reset();
+    //                     this.props.parent._resetCounter++;
+    //                     if (this.props.parent._resetCounter === this.props.numCount) {
+    //                         this.props.parent._resetCounter = 0;
+    //                         this.props.parent._resetBoolean = false;
+    //                     }
+    //                 });
+    //             }
+    //         },
+    //     );
+    // }
 
-    @action.bound
-    reset() {
-        if (this.props.default) {
-            if (!this._status) {
-                this._status = true;
-                this.checkTimeline.play();
-                this.checkTimeline.restart();
-            }
-        }
-        else {
-            if (this._status) {
-                this._status = false;
-                this.uncheckTimeline.play();
-                this.uncheckTimeline.restart();
-            }
-        }
+    // @action.bound
+    // reset() {
+    //     if (this.props.default) {
+    //         if (!this._status) {
+    //             this._status = true;
+    //             this.checkTimeline.play();
+    //             this.checkTimeline.restart();
+    //         }
+    //     }
+    //     else {
+    //         if (this._status) {
+    //             this._status = false;
+    //             this.uncheckTimeline.play();
+    //             this.uncheckTimeline.restart();
+    //         }
+    //     }
 
-        this.props.updateStatus(this.props.default);
-    }
+    //     this.props.updateStatus(this.props.default);
+    // }
 
     @action.bound
     onClick = () => {
-        if (this._status) {
-            this.uncheckTimeline.play();
-            this.uncheckTimeline.restart();
-        }
-        else {
-            this.checkTimeline.play();
-            this.checkTimeline.restart();
+        // if (this._status) {
+        //     this.uncheckTimeline.play();
+        //     this.uncheckTimeline.restart();
+        // }
+        // else {
+        //     this.checkTimeline.play();
+        //     this.checkTimeline.restart();
 
-        }
-        this._status = !this._status;
-        this.props.updateStatus(this._status);
+        // }
+        // this._status = !this._status;
+        // this.props.updateStatus(this._status);
 
     }
 
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 9af8829fa..02b41bc70 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -17,6 +17,7 @@ import "./FilterBox.scss";
 import "./SearchBox.scss";
 import { SearchItem } from './SearchItem';
 import { IconBar } from './IconBar';
+import { FieldFilters } from './FieldFilters';
 
 library.add(faTimes);
 
@@ -338,6 +339,9 @@ export class SearchBox extends React.Component {
     @computed
     get resultHeight() { return this._numTotalResults * 70; }
 
+    @observable private _filterOpen: boolean = false;
+
+
     render() {
         return (
             <div className="searchBox-container" onPointerDown={e => { e.stopPropagation(); e.preventDefault(); }}>
@@ -353,6 +357,49 @@ export class SearchBox extends React.Component {
                 <div className="searchBox-quickFilter" onPointerDown={this.openSearch}>
                     <div className="filter-panel"><IconBar /></div>
                 </div>
+                <div>
+                    <div style={{ display: "flex", flexDirection: "row-reverse" }}>
+                        <SearchBox />
+                        {/* {this.getActiveFilters()} */}
+                    </div>
+                    <div className="filter-form" onPointerDown={this.stopProp} id="filter-form" style={this._filterOpen ? { display: "flex" } : { display: "none" }}>
+                        <div className="top-filter-header" style={{ display: "flex", width: "100%" }}>
+                            <div id="header">Filter Search Results</div>
+                            <div style={{ marginLeft: "auto" }}></div>
+                            <div className="close-icon" >
+                                <span className="line line-1"></span>
+                                <span className="line line-2"></span></div>
+                        </div>
+                        <div className="filter-options">
+                            <div className="filter-div">
+                                <div className="filter-header">
+                                    <div className='filter-title words'>Required words</div>
+                                </div>
+                                <div className="filter-panel" >
+                                    <button className="all-filter">Include All Keywords</button>
+                                </div>
+                            </div>
+                            <div className="filter-div">
+                                <div className="filter-header">
+                                    <div className="filter-title icon">Filter by type of node</div>
+                                </div>
+                                <div className="filter-panel"><IconBar /></div>
+                            </div>
+                            <div className="filter-div">
+                                <div className="filter-header">
+                                    <div className="filter-title field">Filter by Basic Keys</div>
+                                </div>
+                                <div className="filter-panel"><FieldFilters
+                                    titleFieldStatus={this._titleFieldStatus} dataFieldStatus={this._deletedDocsStatus} authorFieldStatus={this._authorFieldStatus}
+                                    updateAuthorStatus={this.updateAuthorStatus} updateDataStatus={this.updateDataStatus} updateTitleStatus={this.updateTitleStatus} /> </div>
+                            </div>
+                        </div>
+                        <div className="filter-buttons" style={{ display: "flex", justifyContent: "space-around" }}>
+                            <button className="save-filter" >Save Filters</button>
+                            <button className="reset-filter" >Reset Filters</button>
+                        </div>
+                    </div>
+                </div>
                 <div className="searchBox-results" onScroll={this.resultsScrolled} style={{
                     display: this._resultsOpen ? "flex" : "none",
                     height: this.resFull ? "auto" : this.resultHeight,
diff --git a/src/server/ApiManagers/SessionManager.ts b/src/server/ApiManagers/SessionManager.ts
index f1629b8f0..8ebd684bb 100644
--- a/src/server/ApiManagers/SessionManager.ts
+++ b/src/server/ApiManagers/SessionManager.ts
@@ -2,7 +2,7 @@ import ApiManager, { Registration } from "./ApiManager";
 import { Method, _permission_denied, AuthorizedCore, SecureHandler } from "../RouteManager";
 import RouteSubscriber from "../RouteSubscriber";
 import { sessionAgent } from "..";
-import { DashSessionAgent } from "../DashSession/DashSessionAgent";
+// import { DashSessionAgent } from "../DashSession/DashSessionAgent";
 
 const permissionError = "You are not authorized!";
 
@@ -25,15 +25,15 @@ export default class SessionManager extends ApiManager {
 
     protected initialize(register: Registration): void {
 
-        register({
-            method: Method.GET,
-            subscription: this.secureSubscriber("debug", "to?"),
-            secureHandler: this.authorizedAction(async ({ req: { params }, res }) => {
-                const to = params.to || DashSessionAgent.notificationRecipient;
-                const { error } = await sessionAgent.serverWorker.emit("debug", { to });
-                res.send(error ? error.message : `Your request was successful: the server captured and compressed (but did not save) a new back up. It was sent to ${to}.`);
-            })
-        });
+        // register({
+        //     method: Method.GET,
+        //     subscription: this.secureSubscriber("debug", "to?"),
+        //     secureHandler: this.authorizedAction(async ({ req: { params }, res }) => {
+        //         const to = params.to || DashSessionAgent.notificationRecipient;
+        //         const { error } = await sessionAgent.serverWorker.emit("debug", { to });
+        //         res.send(error ? error.message : `Your request was successful: the server captured and compressed (but did not save) a new back up. It was sent to ${to}.`);
+        //     })
+        // });
 
         register({
             method: Method.GET,
diff --git a/src/server/DashSession/DashSessionAgent.ts b/src/server/DashSession/DashSessionAgent.ts
index c55e01243..f22d1cbbc 100644
--- a/src/server/DashSession/DashSessionAgent.ts
+++ b/src/server/DashSession/DashSessionAgent.ts
@@ -1,223 +1,223 @@
-import { Email, pathFromRoot } from "../ActionUtilities";
-import { red, yellow, green, cyan } from "colors";
-import { get } from "request-promise";
-import { Utils } from "../../Utils";
-import { WebSocket } from "../Websocket/Websocket";
-import { MessageStore } from "../Message";
-import { launchServer, onWindows } from "..";
-import { readdirSync, statSync, createWriteStream, readFileSync, unlinkSync } from "fs";
-import * as Archiver from "archiver";
-import { resolve } from "path";
-import { AppliedSessionAgent, MessageHandler, ExitHandler, Monitor, ServerWorker } from "resilient-server-session";
-import rimraf = require("rimraf");
-
-/**
- * If we're the monitor (master) thread, we should launch the monitor logic for the session.
- * Otherwise, we must be on a worker thread that was spawned *by* the monitor (master) thread, and thus
- * our job should be to run the server.
- */
-export class DashSessionAgent extends AppliedSessionAgent {
-
-    private readonly signature = "-Dash Server Session Manager";
-    private readonly releaseDesktop = pathFromRoot("../../Desktop");
-
-    /**
-     * The core method invoked when the single master thread is initialized.
-     * Installs event hooks, repl commands and additional IPC listeners.
-     */
-    protected async initializeMonitor(monitor: Monitor, sessionKey: string): Promise<void> {
-        await this.dispatchSessionPassword(sessionKey);
-        monitor.addReplCommand("pull", [], () => monitor.exec("git pull"));
-        monitor.addReplCommand("solr", [/start|stop|index/], this.executeSolrCommand);
-        monitor.addReplCommand("backup", [], this.backup);
-        monitor.addReplCommand("debug", [/\S+\@\S+/], async ([to]) => this.dispatchZippedDebugBackup(to));
-        monitor.on("backup", this.backup);
-        monitor.on("debug", async ({ to }) => this.dispatchZippedDebugBackup(to));
-        monitor.coreHooks.onCrashDetected(this.dispatchCrashReport);
-    }
-
-    /**
-     * The core method invoked when a server worker thread is initialized.
-     * Installs logic to be executed when the server worker dies.
-     */
-    protected async initializeServerWorker(): Promise<ServerWorker> {
-        const worker = ServerWorker.Create(launchServer); // server initialization delegated to worker
-        worker.addExitHandler(this.notifyClient);
-        return worker;
-    }
-
-    /**
-     * Prepares the body of the email with instructions on restoring the transmitted remote database backup locally.
-     */
-    private _remoteDebugInstructions: string | undefined;
-    private generateDebugInstructions = (zipName: string, target: string): string => {
-        if (!this._remoteDebugInstructions) {
-            this._remoteDebugInstructions = readFileSync(resolve(__dirname, "./templates/remote_debug_instructions.txt"), { encoding: "utf8" });
-        }
-        return this._remoteDebugInstructions
-            .replace(/__zipname__/, zipName)
-            .replace(/__target__/, target)
-            .replace(/__signature__/, this.signature);
-    }
-
-    /**
-     * Prepares the body of the email with information regarding a crash event.
-     */
-    private _crashInstructions: string | undefined;
-    private generateCrashInstructions({ name, message, stack }: Error): string {
-        if (!this._crashInstructions) {
-            this._crashInstructions = readFileSync(resolve(__dirname, "./templates/crash_instructions.txt"), { encoding: "utf8" });
-        }
-        return this._crashInstructions
-            .replace(/__name__/, name || "[no error name found]")
-            .replace(/__message__/, message || "[no error message found]")
-            .replace(/__stack__/, stack || "[no error stack found]")
-            .replace(/__signature__/, this.signature);
-    }
-
-    /**
-     * This sends a pseudorandomly generated guid to the configuration's recipients, allowing them alone
-     * to kill the server via the /kill/:key route.
-     */
-    private dispatchSessionPassword = async (sessionKey: string): Promise<void> => {
-        const { mainLog } = this.sessionMonitor;
-        const { notificationRecipient } = DashSessionAgent;
-        mainLog(green("dispatching session key..."));
-        const error = await Email.dispatch({
-            to: notificationRecipient,
-            subject: "Dash Release Session Admin Authentication Key",
-            content: [
-                `Here's the key for this session (started @ ${new Date().toUTCString()}):`,
-                sessionKey,
-                this.signature
-            ].join("\n\n")
-        });
-        if (error) {
-            this.sessionMonitor.mainLog(red(`dispatch failure @ ${notificationRecipient} (${yellow(error.message)})`));
-            mainLog(red("distribution of session key experienced errors"));
-        } else {
-            mainLog(green("successfully distributed session key to recipients"));
-        }
-    }
-
-    /**
-     * This sends an email with the generated crash report.
-     */
-    private dispatchCrashReport: MessageHandler<{ error: Error }> = async ({ error: crashCause }) => {
-        const { mainLog } = this.sessionMonitor;
-        const { notificationRecipient } = DashSessionAgent;
-        const error = await Email.dispatch({
-            to: notificationRecipient,
-            subject: "Dash Web Server Crash",
-            content: this.generateCrashInstructions(crashCause)
-        });
-        if (error) {
-            this.sessionMonitor.mainLog(red(`dispatch failure @ ${notificationRecipient} ${yellow(`(${error.message})`)}`));
-            mainLog(red("distribution of crash notification experienced errors"));
-        } else {
-            mainLog(green("successfully distributed crash notification to recipients"));
-        }
-    }
-
-    /**
-     * Logic for interfacing with Solr. Either starts it, 
-     * stops it, or rebuilds its indicies.
-     */
-    private executeSolrCommand = async (args: string[]): Promise<void> => {
-        const { exec, mainLog } = this.sessionMonitor;
-        const action = args[0];
-        if (action === "index") {
-            exec("npx ts-node ./updateSearch.ts", { cwd: pathFromRoot("./src/server") });
-        } else {
-            const command = `${onWindows ? "solr.cmd" : "solr"} ${args[0] === "start" ? "start" : "stop -p 8983"}`;
-            await exec(command, { cwd: "./solr-8.3.1/bin" });
-            try {
-                await get("http://localhost:8983");
-                mainLog(green("successfully connected to 8983 after running solr initialization"));
-            } catch {
-                mainLog(red("unable to connect at 8983 after running solr initialization"));
-            }
-        }
-    }
-
-    /**
-     * Broadcast to all clients that their connection
-     * is no longer valid, and explain why / what to expect.
-     */
-    private notifyClient: ExitHandler = reason => {
-        const { _socket } = WebSocket;
-        if (_socket) {
-            const message = typeof reason === "boolean" ? (reason ? "exit" : "temporary") : "crash";
-            Utils.Emit(_socket, MessageStore.ConnectionTerminated, message);
-        }
-    }
-
-    /**
-     * Performs a backup of the database, saved to the desktop subdirectory.
-     * This should work as is only on our specific release server.
-     */
-    private backup = async (): Promise<void> => this.sessionMonitor.exec("backup.bat", { cwd: this.releaseDesktop });
-
-    /**
-     * Compress either a brand new backup or the most recent backup and send it
-     * as an attachment to an email, dispatched to the requested recipient.
-     * @param mode specifies whether or not to make a new backup before exporting
-     * @param to the recipient of the email
-     */
-    private async dispatchZippedDebugBackup(to: string): Promise<void> {
-        const { mainLog } = this.sessionMonitor;
-        try {
-            // if desired, complete an immediate backup to send
-            await this.backup();
-            mainLog("backup complete");
-
-            const backupsDirectory = `${this.releaseDesktop}/backups`;
-
-            // sort all backups by their modified time, and choose the most recent one
-            const target = readdirSync(backupsDirectory).map(filename => ({
-                modifiedTime: statSync(`${backupsDirectory}/${filename}`).mtimeMs,
-                filename
-            })).sort((a, b) => b.modifiedTime - a.modifiedTime)[0].filename;
-            mainLog(`targeting ${target}...`);
-
-            // create a zip file and to it, write the contents of the backup directory
-            const zipName = `${target}.zip`;
-            const zipPath = `${this.releaseDesktop}/${zipName}`;
-            const targetPath = `${backupsDirectory}/${target}`;
-            const output = createWriteStream(zipPath);
-            const zip = Archiver('zip');
-            zip.pipe(output);
-            zip.directory(`${targetPath}/Dash`, false);
-            await zip.finalize();
-            mainLog(`zip finalized with size ${statSync(zipPath).size} bytes, saved to ${zipPath}`);
-
-            // dispatch the email to the recipient, containing the finalized zip file
-            const error = await Email.dispatch({
-                to,
-                subject: `Remote debug: compressed backup of ${target}...`,
-                content: this.generateDebugInstructions(zipName, target),
-                attachments: [{ filename: zipName, path: zipPath }]
-            });
-
-            // since this is intended to be a zero-footprint operation, clean up 
-            // by unlinking both the backup generated earlier in the function and the compressed zip file.
-            // to generate a persistent backup, just run backup.
-            unlinkSync(zipPath);
-            rimraf.sync(targetPath);
-
-            // indicate success or failure
-            mainLog(`${error === null ? green("successfully dispatched") : red("failed to dispatch")} ${zipName} to ${cyan(to)}`);
-            error && mainLog(red(error.message));
-        } catch (error) {
-            mainLog(red("unable to dispatch zipped backup..."));
-            mainLog(red(error.message));
-        }
-    }
-
-}
-
-export namespace DashSessionAgent {
-
-    export const notificationRecipient = "brownptcdash@gmail.com";
-
-}
\ No newline at end of file
+// import { Email, pathFromRoot } from "../ActionUtilities";
+// import { red, yellow, green, cyan } from "colors";
+// import { get } from "request-promise";
+// import { Utils } from "../../Utils";
+// import { WebSocket } from "../Websocket/Websocket";
+// import { MessageStore } from "../Message";
+// import { launchServer, onWindows } from "..";
+// import { readdirSync, statSync, createWriteStream, readFileSync, unlinkSync } from "fs";
+// import * as Archiver from "archiver";
+// import { resolve } from "path";
+// import { AppliedSessionAgent, MessageHandler, ExitHandler, Monitor, ServerWorker } from "resilient-server-session";
+// import rimraf = require("rimraf");
+
+// /**
+//  * If we're the monitor (master) thread, we should launch the monitor logic for the session.
+//  * Otherwise, we must be on a worker thread that was spawned *by* the monitor (master) thread, and thus
+//  * our job should be to run the server.
+//  */
+// export class DashSessionAgent extends AppliedSessionAgent {
+
+//     private readonly signature = "-Dash Server Session Manager";
+//     private readonly releaseDesktop = pathFromRoot("../../Desktop");
+
+//     /**
+//      * The core method invoked when the single master thread is initialized.
+//      * Installs event hooks, repl commands and additional IPC listeners.
+//      */
+//     protected async initializeMonitor(monitor: Monitor, sessionKey: string): Promise<void> {
+//         await this.dispatchSessionPassword(sessionKey);
+//         monitor.addReplCommand("pull", [], () => monitor.exec("git pull"));
+//         monitor.addReplCommand("solr", [/start|stop|index/], this.executeSolrCommand);
+//         monitor.addReplCommand("backup", [], this.backup);
+//         monitor.addReplCommand("debug", [/\S+\@\S+/], async ([to]) => this.dispatchZippedDebugBackup(to));
+//         monitor.on("backup", this.backup);
+//         monitor.on("debug", async ({ to }) => this.dispatchZippedDebugBackup(to));
+//         monitor.coreHooks.onCrashDetected(this.dispatchCrashReport);
+//     }
+
+//     /**
+//      * The core method invoked when a server worker thread is initialized.
+//      * Installs logic to be executed when the server worker dies.
+//      */
+//     protected async initializeServerWorker(): Promise<ServerWorker> {
+//         const worker = ServerWorker.Create(launchServer); // server initialization delegated to worker
+//         worker.addExitHandler(this.notifyClient);
+//         return worker;
+//     }
+
+//     /**
+//      * Prepares the body of the email with instructions on restoring the transmitted remote database backup locally.
+//      */
+//     private _remoteDebugInstructions: string | undefined;
+//     private generateDebugInstructions = (zipName: string, target: string): string => {
+//         if (!this._remoteDebugInstructions) {
+//             this._remoteDebugInstructions = readFileSync(resolve(__dirname, "./templates/remote_debug_instructions.txt"), { encoding: "utf8" });
+//         }
+//         return this._remoteDebugInstructions
+//             .replace(/__zipname__/, zipName)
+//             .replace(/__target__/, target)
+//             .replace(/__signature__/, this.signature);
+//     }
+
+//     /**
+//      * Prepares the body of the email with information regarding a crash event.
+//      */
+//     private _crashInstructions: string | undefined;
+//     private generateCrashInstructions({ name, message, stack }: Error): string {
+//         if (!this._crashInstructions) {
+//             this._crashInstructions = readFileSync(resolve(__dirname, "./templates/crash_instructions.txt"), { encoding: "utf8" });
+//         }
+//         return this._crashInstructions
+//             .replace(/__name__/, name || "[no error name found]")
+//             .replace(/__message__/, message || "[no error message found]")
+//             .replace(/__stack__/, stack || "[no error stack found]")
+//             .replace(/__signature__/, this.signature);
+//     }
+
+//     /**
+//      * This sends a pseudorandomly generated guid to the configuration's recipients, allowing them alone
+//      * to kill the server via the /kill/:key route.
+//      */
+//     private dispatchSessionPassword = async (sessionKey: string): Promise<void> => {
+//         const { mainLog } = this.sessionMonitor;
+//         const { notificationRecipient } = DashSessionAgent;
+//         mainLog(green("dispatching session key..."));
+//         const error = await Email.dispatch({
+//             to: notificationRecipient,
+//             subject: "Dash Release Session Admin Authentication Key",
+//             content: [
+//                 `Here's the key for this session (started @ ${new Date().toUTCString()}):`,
+//                 sessionKey,
+//                 this.signature
+//             ].join("\n\n")
+//         });
+//         if (error) {
+//             this.sessionMonitor.mainLog(red(`dispatch failure @ ${notificationRecipient} (${yellow(error.message)})`));
+//             mainLog(red("distribution of session key experienced errors"));
+//         } else {
+//             mainLog(green("successfully distributed session key to recipients"));
+//         }
+//     }
+
+//     /**
+//      * This sends an email with the generated crash report.
+//      */
+//     private dispatchCrashReport: MessageHandler<{ error: Error }> = async ({ error: crashCause }) => {
+//         const { mainLog } = this.sessionMonitor;
+//         const { notificationRecipient } = DashSessionAgent;
+//         const error = await Email.dispatch({
+//             to: notificationRecipient,
+//             subject: "Dash Web Server Crash",
+//             content: this.generateCrashInstructions(crashCause)
+//         });
+//         if (error) {
+//             this.sessionMonitor.mainLog(red(`dispatch failure @ ${notificationRecipient} ${yellow(`(${error.message})`)}`));
+//             mainLog(red("distribution of crash notification experienced errors"));
+//         } else {
+//             mainLog(green("successfully distributed crash notification to recipients"));
+//         }
+//     }
+
+//     /**
+//      * Logic for interfacing with Solr. Either starts it, 
+//      * stops it, or rebuilds its indicies.
+//      */
+//     private executeSolrCommand = async (args: string[]): Promise<void> => {
+//         const { exec, mainLog } = this.sessionMonitor;
+//         const action = args[0];
+//         if (action === "index") {
+//             exec("npx ts-node ./updateSearch.ts", { cwd: pathFromRoot("./src/server") });
+//         } else {
+//             const command = `${onWindows ? "solr.cmd" : "solr"} ${args[0] === "start" ? "start" : "stop -p 8983"}`;
+//             await exec(command, { cwd: "./solr-8.3.1/bin" });
+//             try {
+//                 await get("http://localhost:8983");
+//                 mainLog(green("successfully connected to 8983 after running solr initialization"));
+//             } catch {
+//                 mainLog(red("unable to connect at 8983 after running solr initialization"));
+//             }
+//         }
+//     }
+
+//     /**
+//      * Broadcast to all clients that their connection
+//      * is no longer valid, and explain why / what to expect.
+//      */
+//     private notifyClient: ExitHandler = reason => {
+//         const { _socket } = WebSocket;
+//         if (_socket) {
+//             const message = typeof reason === "boolean" ? (reason ? "exit" : "temporary") : "crash";
+//             Utils.Emit(_socket, MessageStore.ConnectionTerminated, message);
+//         }
+//     }
+
+//     /**
+//      * Performs a backup of the database, saved to the desktop subdirectory.
+//      * This should work as is only on our specific release server.
+//      */
+//     private backup = async (): Promise<void> => this.sessionMonitor.exec("backup.bat", { cwd: this.releaseDesktop });
+
+//     /**
+//      * Compress either a brand new backup or the most recent backup and send it
+//      * as an attachment to an email, dispatched to the requested recipient.
+//      * @param mode specifies whether or not to make a new backup before exporting
+//      * @param to the recipient of the email
+//      */
+//     private async dispatchZippedDebugBackup(to: string): Promise<void> {
+//         const { mainLog } = this.sessionMonitor;
+//         try {
+//             // if desired, complete an immediate backup to send
+//             await this.backup();
+//             mainLog("backup complete");
+
+//             const backupsDirectory = `${this.releaseDesktop}/backups`;
+
+//             // sort all backups by their modified time, and choose the most recent one
+//             const target = readdirSync(backupsDirectory).map(filename => ({
+//                 modifiedTime: statSync(`${backupsDirectory}/${filename}`).mtimeMs,
+//                 filename
+//             })).sort((a, b) => b.modifiedTime - a.modifiedTime)[0].filename;
+//             mainLog(`targeting ${target}...`);
+
+//             // create a zip file and to it, write the contents of the backup directory
+//             const zipName = `${target}.zip`;
+//             const zipPath = `${this.releaseDesktop}/${zipName}`;
+//             const targetPath = `${backupsDirectory}/${target}`;
+//             const output = createWriteStream(zipPath);
+//             const zip = Archiver('zip');
+//             zip.pipe(output);
+//             zip.directory(`${targetPath}/Dash`, false);
+//             await zip.finalize();
+//             mainLog(`zip finalized with size ${statSync(zipPath).size} bytes, saved to ${zipPath}`);
+
+//             // dispatch the email to the recipient, containing the finalized zip file
+//             const error = await Email.dispatch({
+//                 to,
+//                 subject: `Remote debug: compressed backup of ${target}...`,
+//                 content: this.generateDebugInstructions(zipName, target),
+//                 attachments: [{ filename: zipName, path: zipPath }]
+//             });
+
+//             // since this is intended to be a zero-footprint operation, clean up 
+//             // by unlinking both the backup generated earlier in the function and the compressed zip file.
+//             // to generate a persistent backup, just run backup.
+//             unlinkSync(zipPath);
+//             rimraf.sync(targetPath);
+
+//             // indicate success or failure
+//             mainLog(`${error === null ? green("successfully dispatched") : red("failed to dispatch")} ${zipName} to ${cyan(to)}`);
+//             error && mainLog(red(error.message));
+//         } catch (error) {
+//             mainLog(red("unable to dispatch zipped backup..."));
+//             mainLog(red(error.message));
+//         }
+//     }
+
+// }
+
+// export namespace DashSessionAgent {
+
+//     export const notificationRecipient = "brownptcdash@gmail.com";
+
+// }
\ No newline at end of file
diff --git a/src/server/index.ts b/src/server/index.ts
index 313a2f0e2..454d99305 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -22,7 +22,7 @@ import GeneralGoogleManager from "./ApiManagers/GeneralGoogleManager";
 import GooglePhotosManager from "./ApiManagers/GooglePhotosManager";
 import { Logger } from "./ProcessFactory";
 import { yellow } from "colors";
-import { DashSessionAgent } from "./DashSession/DashSessionAgent";
+// import { DashSessionAgent } from "./DashSession/DashSessionAgent";
 import SessionManager from "./ApiManagers/SessionManager";
 import { AppliedSessionAgent } from "resilient-server-session";
 
@@ -141,7 +141,7 @@ export async function launchServer() {
  * So, the 'else' clause is exactly what we've always run when executing npm start.
  */
 if (process.env.RELEASE) {
-    (sessionAgent = new DashSessionAgent()).launch();
+    // (sessionAgent = new DashSessionAgent()).launch();
 } else {
     launchServer();
 }
-- 
cgit v1.2.3-70-g09d2


From 13e6b075154001ce33845a72454e3cd039a92670 Mon Sep 17 00:00:00 2001
From: Andy Rickert <andrew_rickert@brown.edu>
Date: Tue, 24 Mar 2020 19:03:19 -0700
Subject: reaally  pretty  drop down menu functionality : )

---
 src/client/views/SearchDocBox.tsx      |   2 +-
 src/client/views/search/IconBar.scss   |   3 +-
 src/client/views/search/SearchBox.scss |  14 ++++-
 src/client/views/search/SearchBox.tsx  | 109 +++++++++++++++++++++++++++++++--
 4 files changed, 118 insertions(+), 10 deletions(-)

(limited to 'src/client/views/SearchDocBox.tsx')

diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
index 5a76a882f..c57f9e737 100644
--- a/src/client/views/SearchDocBox.tsx
+++ b/src/client/views/SearchDocBox.tsx
@@ -411,7 +411,7 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
                 <ContentFittingDocumentView {...this.props}
                     Document={this.content}
                     getTransform={this.props.ScreenToLocalTransform}>
-                    s</ContentFittingDocumentView>
+                    </ContentFittingDocumentView>
                 <div
                     style={{
                         position: "absolute",
diff --git a/src/client/views/search/IconBar.scss b/src/client/views/search/IconBar.scss
index c6dc2a6cd..013dcd57e 100644
--- a/src/client/views/search/IconBar.scss
+++ b/src/client/views/search/IconBar.scss
@@ -2,8 +2,9 @@
 
 .icon-bar {
     display: flex;
+    flex-wrap: wrap;
     justify-content: space-evenly;
-    height: 35px;
+    height: auto;
     width: 100%;
     flex-direction: row-reverse;
 }
\ No newline at end of file
diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss
index 176ed646d..1b36912d1 100644
--- a/src/client/views/search/SearchBox.scss
+++ b/src/client/views/search/SearchBox.scss
@@ -91,9 +91,10 @@
     background: black;
     flex-direction: column;
     transform-origin: top;
-    border-bottom: solid grey 1px;
-    padding: 5px;
-    transition: height 0.5s ease, display 0.5s ease;
+    transition: height 0.3s ease, display 0.6s ease;
+    height:0px;
+    overflow:hidden;
+
 
     .filter-header {
         display: flex;
@@ -104,6 +105,9 @@
         transform-origin: top;
         justify-content: space-evenly;
         margin-bottom: 5px;
+        overflow:hidden;
+        transition:height 0.3s ease-out;
+
 
 
         .filter-item {
@@ -121,6 +125,10 @@
         padding-top: 5px;
         margin-left: 10px;
         margin-right: 10px;
+        overflow:hidden;
+        transition:height 0.3s ease-out;
+        height:0px;
+
     }
 }
 
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 4f0ca5709..2e7e95b60 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -1,7 +1,7 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faTimes } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, runInAction } from 'mobx';
+import { action, computed, observable, runInAction, IReactionDisposer, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import * as rp from 'request-promise';
@@ -59,17 +59,23 @@ export class SearchBox extends React.Component {
 
         SearchBox.Instance = this;
         this.resultsScrolled = this.resultsScrolled.bind(this);
+        //reaction(()=>document.getElementById("node")?.scrollHeight,()=>{console.log("longer")})
+
     }
 
+    private _reactionDisposer?: IReactionDisposer;
+
     componentDidMount = () => {
         if (this.inputRef.current) {
             this.inputRef.current.focus();
             runInAction(() => {
                 this._searchbarOpen = true;
             });
+
         }
     }
 
+
     @action
     getViews = async (doc: Doc) => {
         const results = await SearchUtil.GetViewsOfDocument(doc);
@@ -369,6 +375,12 @@ export class SearchBox extends React.Component {
     @action.bound
     handleNodeChange = () => {
         this._nodeStatus = !this._nodeStatus;
+        if (this._nodeStatus){
+            this.expandSection("node")
+        }
+        else{
+            this.collapseSection("node")
+        }
     }
 
     @action.bound
@@ -376,8 +388,95 @@ export class SearchBox extends React.Component {
         this._keyStatus = !this._keyStatus;
     }
 
+    @action.bound  
+    handleFilterChange=() =>{
+        this._filterOpen=!this._filterOpen;
+        if (this._filterOpen){
+            this.expandSection("filterhead");
+            document.getElementById("filterhead")!.style.padding="5";        
+        }
+        else{
+            this.collapseSection("filterhead");
+                    
+
+        }
+    }
+    // @observable
+    // private menuHeight= 0;
+
+    @computed
+    get menuHeight(){
+        return document.getElementById("hi")?.clientHeight;
+    }
+
+
+    collapseSection(thing:string) {
+        let element= document.getElementById(thing)!;
+        // get the height of the element's inner content, regardless of its actual size
+        var sectionHeight = element.scrollHeight;
+        
+        // temporarily disable all css transitions
+        var elementTransition = element.style.transition;
+        element.style.transition = '';
+        
+        // on the next frame (as soon as the previous style change has taken effect),
+        // explicitly set the element's height to its current pixel height, so we 
+        // aren't transitioning out of 'auto'
+        requestAnimationFrame(function() {
+          element.style.height = sectionHeight + 'px';
+          element.style.transition = elementTransition;
+          
+          // on the next frame (as soon as the previous style change has taken effect),
+          // have the element transition to height: 0
+          requestAnimationFrame(function() {
+            element.style.height = 0 + 'px';
+            thing == "filterhead"? document.getElementById("filterhead")!.style.padding="0" : null;
+          });
+        });
+        
+        // mark the section as "currently collapsed"
+        element.setAttribute('data-collapsed', 'true');
+      }
+      
+      expandSection(thing:string) {
+        console.log("expand");
+        let element= document.getElementById(thing)!;
+        // get the height of the element's inner content, regardless of its actual size
+        var sectionHeight = element.scrollHeight;
+        
+        // have the element transition to the height of its inner content
+        let  temp = element.style.height;
+        element.style.height = sectionHeight + 'px';
+      
+        // when the next css transition finishes (which should be the one we just triggered)
+        element.addEventListener('transitionend', function handler(e) {
+          // remove this event listener so it only gets triggered once
+          console.log("autoset");
+          element.removeEventListener('transitionend', handler);
+          
+          // remove "height" from the element's inline styles, so it can return to its initial value
+          element.style.height="auto";
+          //element.style.height = undefined;
+        });
+        
+        // mark the section as "currently not collapsed"
+        element.setAttribute('data-collapsed', 'false');
+        
+      }
+
+      autoset(thing: string){
+        let element= document.getElementById(thing)!;
+        console.log("autoset");
+        element.removeEventListener('transitionend', function(e){});
+        
+        // remove "height" from the element's inline styles, so it can return to its initial value
+        element.style.height="auto";
+        //element.style.height = undefined;
+
+      }
 
     render() {
+
         return (
             <div className="searchBox-container" onPointerDown={e => { e.stopPropagation(); e.preventDefault(); }}>
                 <div className="searchBox-bar">
@@ -387,16 +486,16 @@ export class SearchBox extends React.Component {
                     <input value={this._searchString} 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={{ width: this._searchbarOpen ? "500px" : "100px" }} />
-                    <button className="searchBox-barChild searchBox-filter" title="Advanced Filtering Options" onClick={() => runInAction(() => this._filterOpen = !this._filterOpen)}><FontAwesomeIcon icon="ellipsis-v" color="white" /></button>
+                    <button className="searchBox-barChild searchBox-filter" title="Advanced Filtering Options" onClick={() => this.handleFilterChange()}><FontAwesomeIcon icon="ellipsis-v" color="white" /></button>
                 </div>
 
-                <div className="filter-form" style={this._filterOpen ? { display: "flex" } : { display: "none" }}>
-                    <div className="filter-header" style={this._filterOpen ? {} : { display: "none" }}>
+                <div id="filterhead" className="filter-form" >
+                    <div id="filterhead2" className="filter-header" style={this._filterOpen ? { } : { }}>
                         <button className="filter-item" style={this._basicWordStatus ? { background: "#aaaaa3", } : {}} onClick={this.handleWordQueryChange}>Keywords</button>
                         <button className="filter-item" style={this._keyStatus ? { background: "#aaaaa3" } : {}} onClick={this.handleKeyChange}>Keys</button>
                         <button className="filter-item" style={this._nodeStatus ? { background: "#aaaaa3" } : {}} onClick={this.handleNodeChange}>Nodes</button>
                     </div>
-                    <div className="filter-body" style={this._nodeStatus ? { display: "flex" } : { display: "none" }}>
+                    <div id="node" className="filter-body" style={this._nodeStatus ? {  } : { }}>
                         <IconBar />
                     </div>
                     <div style={this._keyStatus ? { display: "flex" } : { display: "none" }}>
-- 
cgit v1.2.3-70-g09d2


From adabfbea2b034beb310530aef9cc8b206e260b67 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 3 Apr 2020 20:23:15 -0400
Subject: added rootSelected() to make forceActive work better

---
 src/client/documents/Documents.ts                  |  2 +-
 src/client/util/RichTextSchema.tsx                 |  1 +
 src/client/views/DocComponent.tsx                  |  6 +++--
 src/client/views/GestureOverlay.tsx                |  1 +
 src/client/views/MainView.tsx                      |  4 ++++
 src/client/views/OverlayView.tsx                   |  1 +
 src/client/views/Palette.tsx                       | 26 +++++++---------------
 src/client/views/RecommendationsBox.tsx            |  1 +
 src/client/views/SearchDocBox.tsx                  |  3 ++-
 .../views/collections/CollectionDockingView.tsx    |  1 +
 .../views/collections/CollectionLinearView.tsx     |  3 ++-
 .../views/collections/CollectionSchemaView.tsx     |  1 +
 .../views/collections/CollectionStackingView.tsx   |  1 +
 src/client/views/collections/CollectionSubView.tsx |  5 +++++
 .../views/collections/CollectionTreeView.tsx       |  2 ++
 src/client/views/collections/CollectionView.tsx    |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  1 +
 .../collections/collectionFreeForm/MarqueeView.tsx |  1 -
 src/client/views/nodes/AudioBox.tsx                | 12 +++++++---
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  7 +++---
 .../views/nodes/ContentFittingDocumentView.tsx     |  1 +
 src/client/views/nodes/DocumentBox.tsx             |  1 +
 src/client/views/nodes/DocumentContentsView.tsx    |  4 ++--
 src/client/views/nodes/DocumentView.tsx            | 24 +++++++++++++++-----
 src/client/views/nodes/FieldView.tsx               |  1 +
 src/client/views/nodes/FormattedTextBoxComment.tsx |  1 +
 src/client/views/pdf/PDFViewer.tsx                 |  3 +--
 .../views/presentationview/PresElementBox.tsx      |  3 ++-
 src/client/views/search/SearchItem.tsx             |  3 ++-
 src/mobile/MobileInterface.tsx                     |  2 ++
 .../authentication/models/current_user_utils.ts    |  2 +-
 31 files changed, 83 insertions(+), 43 deletions(-)

(limited to 'src/client/views/SearchDocBox.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index a69bfae01..0a2269bac 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -435,7 +435,7 @@ export namespace Docs {
         Scripting.addGlobal(Buxton);
 
         const delegateKeys = ["x", "y", "layoutKey", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "dropAction", "childDropAction", "_annotationOn",
-            "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "_showTitle", "_showCaption", "_showTitleHover", "_backgroundColor",
+            "_chromeStatus", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "_showTitle", "_showCaption", "_showTitleHover", "_backgroundColor",
             "_xMargin", "_yMargin", "_xPadding", "_yPadding", "_singleLine", "_scrollTop",
             "_color", "isButton", "isBackground", "removeDropProperties", "treeViewOpen"];
 
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 094cd58f3..4a930177d 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -818,6 +818,7 @@ export class DashDocView {
                     LibraryPath={this._textBox.props.LibraryPath}
                     fitToBox={BoolCast(dashDoc._fitToBox)}
                     addDocument={returnFalse}
+                    rootSelected={this._textBox.props.isSelected}
                     removeDocument={removeDoc}
                     ScreenToLocalTransform={this.getDocTransform}
                     addDocTab={this._textBox.props.addDocTab}
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index f4e830a48..454c245cc 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -29,6 +29,7 @@ interface DocExtendableProps {
     fieldKey: string;
     isSelected: (outsideReaction?: boolean) => boolean;
     renderDepth: number;
+    rootSelected: () => boolean;
 }
 export function DocExtendableComponent<P extends DocExtendableProps, T>(schemaCtor: (doc: Doc) => T) {
     class Component extends Touchable<P> {
@@ -36,7 +37,7 @@ export function DocExtendableComponent<P extends DocExtendableProps, T>(schemaCt
         @computed get Document(): T { return schemaCtor(this.props.Document); }
         @computed get layoutDoc() { return Doc.Layout(this.props.Document); }
         @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Cast(this.props.Document.resolvedDataDoc, Doc, null) || Doc.GetProto(this.props.Document)) as Doc; }
-        active = (outsideReaction?: boolean) => !this.props.Document.isBackground && (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);//  && !InkingControl.Instance.selectedTool;  // bcz: inking state shouldn't affect static tools 
+        active = (outsideReaction?: boolean) => !this.props.Document.isBackground && ((this.props.Document.forceActive && this.props.rootSelected()) || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);//  && !InkingControl.Instance.selectedTool;  // bcz: inking state shouldn't affect static tools 
     }
     return Component;
 }
@@ -50,6 +51,7 @@ export interface DocAnnotatableProps {
     active: () => boolean;
     whenActiveChanged: (isActive: boolean) => void;
     isSelected: (outsideReaction?: boolean) => boolean;
+    rootSelected: () => boolean;
     renderDepth: number;
 }
 export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schemaCtor: (doc: Doc) => T) {
@@ -86,7 +88,7 @@ export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schema
 
         whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive));
         active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.props.Document.isBackground) &&
-            (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
+            ((this.props.Document.forceActive && this.props.rootSelected()) || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
         annotationsActive = (outsideReaction?: boolean) => (InkingControl.Instance.selectedTool !== InkTool.None ||
             (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
     }
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index ea60907f6..26bee9a6f 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -705,6 +705,7 @@ export default class GestureOverlay extends Touchable {
                 LibraryPath={emptyPath}
                 addDocument={undefined}
                 addDocTab={returnFalse}
+                rootSelected={returnTrue}
                 pinToPres={emptyFunction}
                 onClick={undefined}
                 removeDocument={undefined}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 8d9be5980..fae520e40 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -309,6 +309,7 @@ export class MainView extends React.Component {
             addDocument={undefined}
             addDocTab={this.addDocTabFunc}
             pinToPres={emptyFunction}
+            rootSelected={returnTrue}
             onClick={undefined}
             backgroundColor={this.defaultBackgroundColors}
             removeDocument={undefined}
@@ -407,6 +408,7 @@ export class MainView extends React.Component {
                     DataDoc={undefined}
                     LibraryPath={emptyPath}
                     addDocument={undefined}
+                    rootSelected={returnTrue}
                     addDocTab={this.addDocTabFunc}
                     pinToPres={emptyFunction}
                     removeDocument={undefined}
@@ -435,6 +437,7 @@ export class MainView extends React.Component {
                     addDocument={undefined}
                     addDocTab={this.addDocTabFunc}
                     pinToPres={emptyFunction}
+                    rootSelected={returnTrue}
                     removeDocument={returnFalse}
                     onClick={undefined}
                     ScreenToLocalTransform={this.mainContainerXf}
@@ -523,6 +526,7 @@ export class MainView extends React.Component {
                     fieldKey={"data"}
                     dropAction={"alias"}
                     annotationsKey={""}
+                    rootSelected={returnTrue}
                     bringToFront={emptyFunction}
                     select={emptyFunction}
                     active={returnFalse}
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 220efd4a8..7587071db 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -174,6 +174,7 @@ export class OverlayView extends React.Component {
                     Document={d}
                     LibraryPath={emptyPath}
                     ChromeHeight={returnZero}
+                    rootSelected={returnTrue}
                     // isSelected={returnFalse}
                     // select={emptyFunction}
                     // layoutKey={"layout"}
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index e04f814d1..674b27918 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -1,23 +1,12 @@
+import { IReactionDisposer, observable, reaction } from "mobx";
+import { observer } from "mobx-react";
 import * as React from "react";
-import "./Palette.scss";
-import { PointData } from "../../new_fields/InkField";
 import { Doc } from "../../new_fields/Doc";
-import { Docs } from "../documents/Documents";
-import { ScriptField, ComputedField } from "../../new_fields/ScriptField";
-import { List } from "../../new_fields/List";
-import { DocumentView } from "./nodes/DocumentView";
-import { emptyPath, returnFalse, emptyFunction, returnOne, returnEmptyString, returnTrue } from "../../Utils";
-import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
+import { NumCast } from "../../new_fields/Types";
+import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue } from "../../Utils";
 import { Transform } from "../util/Transform";
-import { computed, action, IReactionDisposer, reaction, observable } from "mobx";
-import { FieldValue, Cast, NumCast } from "../../new_fields/Types";
-import { observer } from "mobx-react";
-import { DocumentContentsView } from "./nodes/DocumentContentsView";
-import { CollectionStackingView } from "./collections/CollectionStackingView";
-import { CollectionView } from "./collections/CollectionView";
-import { CollectionSubView, SubCollectionViewProps } from "./collections/CollectionSubView";
-import { makeInterface } from "../../new_fields/Schema";
-import { documentSchema } from "../../new_fields/documentSchemas";
+import { DocumentView } from "./nodes/DocumentView";
+import "./Palette.scss";
 
 export interface PaletteProps {
     x: number;
@@ -40,7 +29,7 @@ export default class Palette extends React.Component<PaletteProps> {
     }
 
     componentWillUnmount = () => {
-        this._selectedDisposer && this._selectedDisposer();
+        this._selectedDisposer?.();
     }
 
     render() {
@@ -54,6 +43,7 @@ export default class Palette extends React.Component<PaletteProps> {
                             LibraryPath={emptyPath}
                             addDocument={undefined}
                             addDocTab={returnFalse}
+                            rootSelected={returnTrue}
                             pinToPres={emptyFunction}
                             removeDocument={undefined}
                             onClick={undefined}
diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
index 5ebba0abb..bf8de36b4 100644
--- a/src/client/views/RecommendationsBox.tsx
+++ b/src/client/views/RecommendationsBox.tsx
@@ -68,6 +68,7 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
                 addDocument={returnFalse}
                 LibraryPath={emptyPath}
                 removeDocument={returnFalse}
+                rootSelected={returnFalse}
                 ScreenToLocalTransform={Transform.Identity}
                 addDocTab={returnFalse}
                 pinToPres={returnFalse}
diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
index c57f9e737..e66de39d4 100644
--- a/src/client/views/SearchDocBox.tsx
+++ b/src/client/views/SearchDocBox.tsx
@@ -410,8 +410,9 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
             <div style={{ pointerEvents: "all" }}>
                 <ContentFittingDocumentView {...this.props}
                     Document={this.content}
+                    rootSelected={returnFalse}
                     getTransform={this.props.ScreenToLocalTransform}>
-                    </ContentFittingDocumentView>
+                </ContentFittingDocumentView>
                 <div
                     style={{
                         position: "absolute",
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 4e1e76f39..4209bd574 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -788,6 +788,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             Document={document}
             DataDoc={resolvedDataDoc}
             bringToFront={emptyFunction}
+            rootSelected={returnTrue}
             addDocument={undefined}
             removeDocument={undefined}
             ContentScaling={this.contentScaling}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 344605412..a6ada75b2 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -4,7 +4,7 @@ import * as React from 'react';
 import { Doc, HeightSym, WidthSym } from '../../../new_fields/Doc';
 import { makeInterface } from '../../../new_fields/Schema';
 import { BoolCast, NumCast, StrCast, Cast } from '../../../new_fields/Types';
-import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils } from '../../../Utils';
+import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils, returnFalse } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { Transform } from '../../util/Transform';
 import "./CollectionLinearView.scss";
@@ -110,6 +110,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                                 moveDocument={this.props.moveDocument}
                                 addDocTab={this.props.addDocTab}
                                 pinToPres={emptyFunction}
+                                rootSelected={this.props.isSelected}
                                 removeDocument={this.props.removeDocument}
                                 onClick={undefined}
                                 ScreenToLocalTransform={this.getTransform(dref)}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 981438513..a1b541f74 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -124,6 +124,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
                 LibraryPath={this.props.LibraryPath}
                 childDocs={this.childDocs}
                 renderDepth={this.props.renderDepth}
+                rootSelected={this.rootSelected}
                 PanelWidth={this.previewWidth}
                 PanelHeight={this.previewHeight}
                 getTransform={this.getPreviewTransform}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 076dd3629..d21e17bbc 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -176,6 +176,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             LibraryPath={this.props.LibraryPath}
             renderDepth={this.props.renderDepth + 1}
             fitToBox={this.props.fitToBox}
+            rootSelected={this.rootSelected}
             dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             onClick={layoutDoc.isTemplateDoc ? this.onClickHandler : this.onChildClickHandler}
             PanelWidth={width}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 70927cf22..d1d6ae3c1 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -34,6 +34,7 @@ export interface CollectionViewProps extends FieldViewProps {
     PanelHeight: () => number;
     VisibleHeight?: () => number;
     setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
+    rootSelected: () => boolean;
     fieldKey: string;
 }
 
@@ -95,6 +96,10 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                 this.props.Document.resolvedDataDoc ? this.props.Document : Doc.GetProto(this.props.Document)); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template
         }
 
+        rootSelected = () => {
+            return this.props.isSelected() || (this.props.Document.rootDocument || this.props.Document.forceActive ? this.props.rootSelected() : false);
+        }
+
         // The data field for rendering this collection will be on the this.props.Document unless we're rendering a template in which case we try to use props.DataDoc.
         // When a document has a DataDoc but it's not a template, then it contains its own rendering data, but needs to pass the DataDoc through
         // to its children which may be templates.
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 6ee48f11b..fc612c66d 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -373,6 +373,7 @@ class TreeView extends React.Component<TreeViewProps> {
                     DataDocument={this.templateDataDoc}
                     LibraryPath={emptyPath}
                     renderDepth={this.props.renderDepth + 1}
+                    rootSelected={returnTrue}
                     backgroundColor={this.props.backgroundColor}
                     fitToBox={this.boundsOfCollectionDocument !== undefined}
                     PanelWidth={this.docWidth}
@@ -454,6 +455,7 @@ class TreeView extends React.Component<TreeViewProps> {
                         LibraryPath={this.props.libraryPath || []}
                         addDocument={undefined}
                         addDocTab={this.props.addDocTab}
+                        rootSelected={returnTrue}
                         pinToPres={emptyFunction}
                         onClick={this.props.onChildClick || editTitle}
                         dropAction={this.props.dropAction}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index df1770ffe..3913ccd88 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -117,7 +117,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
         return viewField;
     }
 
-    active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || BoolCast(this.props.Document.forceActive) || this._isChildActive || this.props.renderDepth === 0;
+    active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || (this.props.rootSelected() && BoolCast(this.props.Document.forceActive)) || this._isChildActive || this.props.renderDepth === 0;
 
     whenActiveChanged = (isActive: boolean) => { this.props.whenActiveChanged(this._isChildActive = isActive); };
 
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 2871fe192..a164e1794 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -832,6 +832,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             Document: childLayout,
             LibraryPath: this.libraryPath,
             layoutKey: undefined,
+            rootSelected: this.rootSelected,
             dropAction: StrCast(this.props.Document.childDropAction) as dropActionType,
             //onClick: undefined, // this.props.onClick,  // bcz: check this out -- I don't think we want to inherit click handlers, or we at least need a way to ignore them
             onClick: this.onChildClickHandler,
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 276a49570..503df10c2 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -5,7 +5,6 @@ import { InkField, InkData } from "../../../../new_fields/InkField";
 import { List } from "../../../../new_fields/List";
 import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField";
 import { Cast, NumCast, FieldValue, StrCast } from "../../../../new_fields/Types";
-import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils";
 import { Utils } from "../../../../Utils";
 import { Docs, DocUtils } from "../../../documents/Documents";
 import { SelectionManager } from "../../../util/SelectionManager";
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 03b2a2297..bd54d64ff 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -7,7 +7,7 @@ import { AudioField, nullAudio } from "../../../new_fields/URLField";
 import { DocExtendableComponent } from "../DocComponent";
 import { makeInterface, createSchema } from "../../../new_fields/Schema";
 import { documentSchema } from "../../../new_fields/documentSchemas";
-import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent } from "../../../Utils";
+import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse } from "../../../Utils";
 import { runInAction, observable, reaction, IReactionDisposer, computed, action } from "mobx";
 import { DateField } from "../../../new_fields/DateField";
 import { SelectionManager } from "../../util/SelectionManager";
@@ -258,9 +258,15 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
                                 return !linkTime ? (null) :
                                     <div className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container"} key={l[Id]} style={{ left: `${linkTime / NumCast(this.dataDoc.duration, 1) * 100}%` }}>
                                         <div className={this.props.PanelHeight() < 32 ? "audioBox-linker-mini" : "audioBox-linker"} key={"linker" + i}>
-                                            <DocumentView {...this.props} Document={l} layoutKey={Doc.LinkEndpoint(l, la2)}
+                                            <DocumentView {...this.props}
+                                                Document={l}
+                                                rootSelected={returnFalse}
+                                                layoutKey={Doc.LinkEndpoint(l, la2)}
                                                 ContainingCollectionDoc={this.props.Document}
-                                                parentActive={returnTrue} bringToFront={emptyFunction} zoomToScale={emptyFunction} getScale={returnOne}
+                                                parentActive={returnTrue}
+                                                bringToFront={emptyFunction}
+                                                zoomToScale={emptyFunction}
+                                                getScale={returnOne}
                                                 backgroundColor={returnTransparent} />
                                         </div>
                                         <div key={i} className="audiobox-marker" onPointerEnter={() => Doc.linkFollowHighlight(la1)}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index eaab4086c..356192797 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -89,14 +89,15 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 pointerEvents: this.props.Document.isBackground ? "none" : undefined
             }} >
 
-            {!this.props.fitToBox ? <DocumentView {...this.props}
+            {!this.props.fitToBox ? 
+            <DocumentView {...this.props}
                 dragDivName={"collectionFreeFormDocumentView-container"}
                 ContentScaling={this.contentScaling}
                 ScreenToLocalTransform={this.getTransform}
                 backgroundColor={this.props.backgroundColor}
                 PanelWidth={this.panelWidth}
-                PanelHeight={this.panelHeight}
-            /> : <ContentFittingDocumentView {...this.props}
+                PanelHeight={this.panelHeight} /> 
+            : <ContentFittingDocumentView {...this.props}
                 CollectionDoc={this.props.ContainingCollectionDoc}
                 DataDocument={this.props.DataDoc}
                 getTransform={this.getTransform}
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 9494a4bc4..fdf2a9551 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -40,6 +40,7 @@ interface ContentFittingDocumentViewProps {
     addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     dontRegisterView?: boolean;
+    rootSelected: () => boolean;
 }
 
 @observer
diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx
index debe104d7..47118e758 100644
--- a/src/client/views/nodes/DocumentBox.tsx
+++ b/src/client/views/nodes/DocumentBox.tsx
@@ -122,6 +122,7 @@ export class DocumentBox extends DocAnnotatableComponent<FieldViewProps, DocBoxS
             CollectionView={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
             fitToBox={this.props.fitToBox}
             layoutKey={"layout_" + childTemplateName}
+            rootSelected={this.props.isSelected}
             addDocument={this.props.addDocument}
             moveDocument={this.props.moveDocument}
             removeDocument={this.props.removeDocument}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index fc61487e5..687137adc 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -1,6 +1,6 @@
 import { computed } from "mobx";
 import { observer } from "mobx-react";
-import { Doc } from "../../../new_fields/Doc";
+import { Doc, Opt } from "../../../new_fields/Doc";
 import { Cast, StrCast } from "../../../new_fields/Types";
 import { OmitKeys, Without } from "../../../Utils";
 import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox";
@@ -62,7 +62,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
     forceLayout?: string,
     forceFieldKey?: string,
     hideOnLeave?: boolean,
-    makeLink?: () => Opt<Doc>;
+    makeLink?: () => Opt<Doc>,  // function to call when a link is made
 }> {
     @computed get layout(): string {
         TraceMobx();
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 1e02ab44e..42f5fb946 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -60,6 +60,7 @@ export interface DocumentViewProps {
     LayoutDoc?: () => Opt<Doc>;
     LibraryPath: Doc[];
     fitToBox?: boolean;
+    rootSelected: () => boolean; // whether the root of a template has been selected
     onClick?: ScriptField;
     onPointerDown?: ScriptField;
     onPointerUp?: ScriptField;
@@ -277,7 +278,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         this.dontDecorateSelection = this.props.Document.dontDecorateSelection && (!e.ctrlKey || e.button < 2);
         if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick &&
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
-            e.stopPropagation();
+            let stopPropagate = true;
             let preventDefault = true;
             this.props.bringToFront(this.props.Document);
             if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
@@ -301,9 +302,14 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 SelectionManager.SelectDoc(this, e.ctrlKey); // don't think this should happen if a button action is actually triggered.
                 UndoManager.RunInBatch(() => this.buttonClick(e.altKey, e.ctrlKey), "on link button follow");
             } else {
-                SelectionManager.SelectDoc(this, e.ctrlKey);
+                if (this.props.Document.isTemplateForField && !(e.ctrlKey || e.button > 0)) {
+                    stopPropagate = false;
+                } else {
+                    SelectionManager.SelectDoc(this, e.ctrlKey);
+                }
                 preventDefault = false;
             }
+            stopPropagate && e.stopPropagation();
             preventDefault && e.preventDefault();
         }
     }
@@ -928,6 +934,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const fallback = Cast(this.props.Document.layoutKey, "string");
         return typeof fallback === "string" ? fallback : "layout";
     }
+    rootSelected = () => {
+        return this.isSelected(false) || (this.props.Document.forceActive && this.props.rootSelected?.() ? true : false);
+    }
     childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
     @computed get contents() {
         TraceMobx();
@@ -937,6 +946,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             DataDoc={this.props.DataDoc}
             LayoutDoc={this.props.LayoutDoc}
             makeLink={this.makeLink}
+            rootSelected={this.rootSelected}
             fitToBox={this.props.fitToBox}
             LibraryPath={this.props.LibraryPath}
             addDocument={this.props.addDocument}
@@ -985,9 +995,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 {StrCast(this.props.Document.title)}
                 {this.Document.links && DocListCast(this.Document.links).filter(d => !d.hidden).filter(this.isNonTemporalLink).map((d, i) =>
                     <div className="documentView-docuLinkWrapper" style={{ position: "absolute", top: 0, left: 0 }} key={`${d[Id]}`}>
-                        <DocumentView {...this.props} Document={d} ContainingCollectionDoc={this.props.Document}
-                            PanelWidth={returnOne} PanelHeight={returnOne} layoutKey={this.linkEndpoint(d)} ContentScaling={returnOne}
-                            backgroundColor={returnTransparent} removeDocument={undoBatch(doc => doc.hidden = true)} />
+                        <DocumentView {...this.props}
+                            Document={d}
+                            ContainingCollectionDoc={this.props.Document}
+                            PanelWidth={returnOne} PanelHeight={returnOne}
+                            layoutKey={this.linkEndpoint(d)} ContentScaling={returnOne}
+                            backgroundColor={returnTransparent}
+                            removeDocument={undoBatch(doc => doc.hidden = true)} />
                     </div>)}
             </div>;
         }
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 0305f43d5..13a1becf7 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -29,6 +29,7 @@ export interface FieldViewProps {
     dropAction: dropActionType;
     isSelected: (outsideReaction?: boolean) => boolean;
     select: (isCtrlPressed: boolean) => void;
+    rootSelected: () => boolean;
     renderDepth: number;
     addDocument?: (document: Doc) => boolean;
     addDocTab: (document: Doc, where: string) => boolean;
diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx
index 61df188f8..d1a563494 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/FormattedTextBoxComment.tsx
@@ -181,6 +181,7 @@ export class FormattedTextBoxComment {
                                     LibraryPath={emptyPath}
                                     fitToBox={true}
                                     moveDocument={returnFalse}
+                                    rootSelected={returnFalse}
                                     getTransform={Transform.Identity}
                                     active={returnFalse}
                                     addDocument={returnFalse}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 71495d95f..c032f019d 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -31,8 +31,6 @@ import { InkingControl } from "../InkingControl";
 import { InkTool } from "../../../new_fields/InkField";
 import { TraceMobx } from "../../../new_fields/util";
 import { PdfField } from "../../../new_fields/URLField";
-import { PDFBox } from "../nodes/PDFBox";
-import { FormattedTextBox } from "../nodes/FormattedTextBox";
 import { DocumentView } from "../nodes/DocumentView";
 const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer");
 const pdfjsLib = require("pdfjs-dist");
@@ -61,6 +59,7 @@ interface IViewerProps {
     PanelHeight: () => number;
     ContentScaling: () => number;
     select: (isCtrlPressed: boolean) => void;
+    rootSelected: () => boolean;
     startupLive: boolean;
     renderDepth: number;
     focus: (doc: Doc) => void;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 758795ed5..7ad3474e8 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -9,7 +9,7 @@ import { documentSchema } from '../../../new_fields/documentSchemas';
 import { Id } from "../../../new_fields/FieldSymbols";
 import { createSchema, makeInterface } from '../../../new_fields/Schema';
 import { Cast, NumCast } from "../../../new_fields/Types";
-import { emptyFunction, emptyPath, returnFalse } from "../../../Utils";
+import { emptyFunction, emptyPath, returnFalse, returnTrue } from "../../../Utils";
 import { Transform } from "../../util/Transform";
 import { CollectionViewType } from '../collections/CollectionView';
 import { DocExtendableComponent } from '../DocComponent';
@@ -175,6 +175,7 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
                     DataDocument={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
                     LibraryPath={emptyPath}
                     fitToBox={true}
+                    rootSelected={returnTrue}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
                     addDocTab={returnFalse}
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 63cef5101..0d77026ad 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -7,7 +7,7 @@ import { observer } from "mobx-react";
 import { Doc } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { emptyFunction, emptyPath, returnFalse, Utils } from "../../../Utils";
+import { emptyFunction, emptyPath, returnFalse, Utils, returnTrue } from "../../../Utils";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { DocumentManager } from "../../util/DocumentManager";
 import { DragManager, SetupDrag } from "../../util/DragManager";
@@ -158,6 +158,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
                 <ContentFittingDocumentView
                     Document={this.props.doc}
                     LibraryPath={emptyPath}
+                    rootSelected={returnFalse}
                     fitToBox={StrCast(this.props.doc.type).indexOf(DocumentType.COL) !== -1}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 1d2d57b96..98a6d384e 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -124,6 +124,7 @@ export default class MobileInterface extends React.Component {
                 addDocument={returnFalse}
                 addDocTab={returnFalse}
                 pinToPres={emptyFunction}
+                rootSelected={returnFalse}
                 removeDocument={undefined}
                 onClick={undefined}
                 ScreenToLocalTransform={Transform.Identity}
@@ -285,6 +286,7 @@ export default class MobileInterface extends React.Component {
                         addDocument={returnFalse}
                         addDocTab={returnFalse}
                         pinToPres={emptyFunction}
+                        rootSelected={returnFalse}
                         removeDocument={undefined}
                         onClick={undefined}
                         ScreenToLocalTransform={Transform.Identity}
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 9a90ce17f..7fe623f18 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -213,7 +213,7 @@ export class CurrentUserUtils {
             _width: 35, _height: 25, title: "Tools", fontSize: 10, targetContainer: sidebarContainer, dontDecorateSelection: true,
             letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
             sourcePanel: Docs.Create.StackingDocument([dragCreators, color], {
-                _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack"
+                _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true
             }),
             onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"),
         });
-- 
cgit v1.2.3-70-g09d2


From fac740378a9eeaeb0af4567f6402120aba8bd62e Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 3 Apr 2020 22:04:19 -0400
Subject: cleaning up .. removing Docs.Create.SearchDocument

---
 src/client/documents/DocumentTypes.ts              |  2 +-
 src/client/documents/Documents.ts                  |  4 ---
 src/client/views/SearchDocBox.tsx                  | 37 ++++++++--------------
 src/client/views/nodes/DocumentContentsView.tsx    |  1 -
 src/client/views/search/SearchBox.tsx              |  3 --
 .../authentication/models/current_user_utils.ts    |  2 +-
 6 files changed, 15 insertions(+), 34 deletions(-)

(limited to 'src/client/views/SearchDocBox.tsx')

diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index 5ec1cfdb4..b98e4d581 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -22,7 +22,7 @@ export enum DocumentType {
     RECOMMENDATION = "recommendation",
     LINKFOLLOW = "linkfollow",
     PRESELEMENT = "preselement",
-    QUERY = "search",
+    QUERY = "query",
     COLOR = "color",
     DOCULINK = "doculink",
     PDFANNO = "pdfanno",
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index c5b080ffb..1a2969cf5 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -708,10 +708,6 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.RECOMMENDATION), new List<Doc>(data), options);
         }
 
-        export function SearchDocument(documents: Array<Doc>, options: DocumentOptions = {}) {
-            return InstanceFromProto(Prototypes.get(DocumentType.SEARCHBOX), new List(documents), options);
-        }
-
         export type DocConfig = {
             doc: Doc,
             initialWidth?: number,
diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
index e66de39d4..cd9666af8 100644
--- a/src/client/views/SearchDocBox.tsx
+++ b/src/client/views/SearchDocBox.tsx
@@ -1,31 +1,20 @@
+import { library } from "@fortawesome/fontawesome-svg-core";
+import { faBullseye, faLink } from "@fortawesome/free-solid-svg-icons";
+import { action, computed, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
-import React = require("react");
-import { observable, action, computed, runInAction } from "mobx";
-import Measure from "react-measure";
 //import "./SearchBoxDoc.scss";
-import { Doc, DocListCast, WidthSym, HeightSym } from "../../new_fields/Doc";
-import { DocumentIcon } from "./nodes/DocumentIcon";
-import { StrCast, NumCast, BoolCast, Cast } from "../../new_fields/Types";
-import { returnFalse, emptyFunction, returnEmptyString, returnOne } from "../../Utils";
-import { Transform } from "../util/Transform";
-import { ObjectField } from "../../new_fields/ObjectField";
-import { DocumentView } from "./nodes/DocumentView";
-import { DocumentType } from '../documents/DocumentTypes';
-import { ClientRecommender } from "../ClientRecommender";
-import { DocServer } from "../DocServer";
+import { Doc, DocListCast } from "../../new_fields/Doc";
 import { Id } from "../../new_fields/FieldSymbols";
-import { FieldView, FieldViewProps } from "./nodes/FieldView";
-import { DocumentManager } from "../util/DocumentManager";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { library } from "@fortawesome/fontawesome-svg-core";
-import { faBullseye, faLink } from "@fortawesome/free-solid-svg-icons";
-import { DocUtils, Docs } from "../documents/Documents";
-import { ContentFittingDocumentView } from "./nodes/ContentFittingDocumentView";
-import { EditableView } from "./EditableView";
+import { BoolCast, Cast, NumCast, StrCast } from "../../new_fields/Types";
+import { returnFalse } from "../../Utils";
+import { Docs } from "../documents/Documents";
 import { SearchUtil } from "../util/SearchUtil";
-import { SearchItem } from "./search/SearchItem";
+import { EditableView } from "./EditableView";
+import { ContentFittingDocumentView } from "./nodes/ContentFittingDocumentView";
+import { FieldView, FieldViewProps } from "./nodes/FieldView";
 import { FilterBox } from "./search/FilterBox";
-import { SearchBox } from "./search/SearchBox";
+import { SearchItem } from "./search/SearchItem";
+import React = require("react");
 
 export interface RecProps {
     documents: { preview: Doc, similarity: number }[];
@@ -301,7 +290,7 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
             }
         }
         //return Docs.Create.TreeDocument(docs, { _width: 200, _height: 400, backgroundColor: "grey", title: `Search Docs: "${this._searchString}"` });
-        return Docs.Create.SearchDocument(docs, { _width: 200, _height: 400, searchText: this._searchString, title: `Search Docs: "${this._searchString}"` });
+        return Docs.Create.QueryDocument(docs, { _width: 200, _height: 400, searchText: this._searchString, title: `Query Docs: "${this._searchString}"` });
     }
 
     @action.bound
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 687137adc..dc71ba280 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -35,7 +35,6 @@ import { WebBox } from "./WebBox";
 import { InkingStroke } from "../InkingStroke";
 import React = require("react");
 import { RecommendationsBox } from "../RecommendationsBox";
-import { SearchBox } from "../search/SearchBox";
 
 import { TraceMobx } from "../../../new_fields/util";
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index e7941a9ba..49b6b18ca 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -416,9 +416,6 @@ export class SearchBox extends React.Component<SearchProps> {
                 y += 300;
             }
         }
-        console.log("create");
-        //return Docs.Create.TreeDocument(docs, { _width: 200, _height: 400, backgroundColor: "grey", title: `Search Docs: "${this._searchString}"` });
-        //return Docs.Create.SearchDocument(docs, { _width: 200, _height: 400, searchText: this._searchString, title: `Search Docs: "${this._searchString}"` });
         return Docs.Create.QueryDocument({ _autoHeight: true, title: this._searchString, filterQuery: this.filterQuery, searchQuery: this._searchString });
     }
 
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index e34a9b958..fc6e36485 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -89,7 +89,7 @@ export class CurrentUserUtils {
             { title: "use stamp", icon: "stamp", click: 'activateStamp(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc },
             { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc },
             { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc },
-            { title: "search", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.SearchDocument({ _width: 200, title: "an image of a cat" })' },
+            { title: "query", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' },
 
 
         ];
-- 
cgit v1.2.3-70-g09d2


From 50552174123eb5622821de5f848e6e70c7346214 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 3 Apr 2020 23:45:34 -0400
Subject: fixed a bunch of warnings

---
 src/client/documents/Documents.ts                  |  7 ++--
 src/client/util/SelectionManager.ts                |  6 +---
 src/client/views/DocumentDecorations.tsx           |  1 -
 src/client/views/MainView.tsx                      | 40 +++++++++------------
 src/client/views/SearchDocBox.tsx                  | 15 ++++----
 src/client/views/TemplateMenu.tsx                  |  1 +
 .../views/collections/CollectionLinearView.scss    |  2 ++
 .../views/collections/CollectionLinearView.tsx     | 27 +++++++-------
 .../views/collections/CollectionSchemaCells.tsx    |  1 +
 src/client/views/nodes/DocumentBox.tsx             |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  4 +--
 src/client/views/nodes/FormattedTextBox.tsx        |  2 +-
 src/client/views/nodes/KeyValuePair.tsx            |  1 +
 src/client/views/pdf/PDFMenu.tsx                   |  2 +-
 src/client/views/search/SearchBox.tsx              | 38 ++++++++------------
 src/new_fields/documentSchemas.ts                  |  1 -
 .../authentication/models/current_user_utils.ts    | 42 +++++++++++++---------
 17 files changed, 90 insertions(+), 102 deletions(-)

(limited to 'src/client/views/SearchDocBox.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 1a2969cf5..514200d95 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -118,7 +118,6 @@ export interface DocumentOptions {
     lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed
     opacity?: number;
     defaultBackgroundColor?: string;
-    dontDecorateSelection?: boolean; // whether document decorations should be displayed when the document is selected
     isBackground?: boolean;
     isButton?: boolean;
     columnWidth?: number;
@@ -164,9 +163,9 @@ export interface DocumentOptions {
     flexDirection?: "unset" | "row" | "column" | "row-reverse" | "column-reverse";
     selectedIndex?: number;
     syntaxColor?: string; // can be applied to text for syntax highlighting all matches in the text
-    searchText?: string, //for searchbox
-    searchQuery?: string, // for queryBox
-    filterQuery?: string,
+    searchText?: string; //for searchbox
+    searchQuery?: string; // for queryBox
+    filterQuery?: string;
     linearViewIsExpanded?: boolean; // is linear view expanded
 }
 
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 7221fbbf9..2a6e3bf8a 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -33,7 +33,6 @@ export namespace SelectionManager {
         @action
         DeselectDoc(docView: DocumentView): void {
             if (manager.SelectedDocuments.get(docView)) {
-                docView.dontDecorateSelection = false;
                 manager.SelectedDocuments.delete(docView);
                 docView.props.whenActiveChanged(false);
                 Doc.UserDoc().SelectedDocs = new List(SelectionManager.SelectedDocuments().map(dv => dv.props.Document));
@@ -41,10 +40,7 @@ export namespace SelectionManager {
         }
         @action
         DeselectAll(): void {
-            Array.from(manager.SelectedDocuments.keys()).map(dv => {
-                dv.dontDecorateSelection = false;
-                dv.props.whenActiveChanged(false);
-            });
+            Array.from(manager.SelectedDocuments.keys()).map(dv => dv.props.whenActiveChanged(false));
             manager.SelectedDocuments.clear();
             Doc.UserDoc().SelectedDocs = new List<Doc>([]);
         }
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index c35263237..e313b117f 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -69,7 +69,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     get Bounds(): { x: number, y: number, b: number, r: number } {
         return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => {
             if (documentView.props.renderDepth === 0 ||
-                documentView.dontDecorateSelection ||
                 Doc.AreProtosEqual(documentView.props.Document, CurrentUserUtils.UserDocument)) {
                 return bounds;
             }
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index fae520e40..558bc1a4a 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,54 +1,46 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
-import {
-    faFileAlt, faStickyNote, faArrowDown, faBullseye, faFilter, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faChevronRight, faClone, faCloudUploadAlt, faCommentAlt, faCut, faEllipsisV, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight,
-    faMusic, faObjectGroup, faPause, faMousePointer, faPenNib, faFileAudio, faPen, faEraser, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faTv, faUndoAlt, faHighlighter, faMicrophone, faCompressArrowsAlt, faPhone, faStamp, faClipboard, faVideo,
-} from '@fortawesome/free-solid-svg-icons';
+import { faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import "normalize.css";
 import * as React from 'react';
 import Measure from 'react-measure';
-import { Doc, DocListCast, Field, FieldResult, Opt } from '../../new_fields/Doc';
+import { Doc, DocListCast, Field, Opt } from '../../new_fields/Doc';
 import { Id } from '../../new_fields/FieldSymbols';
 import { List } from '../../new_fields/List';
 import { listSpec } from '../../new_fields/Schema';
-import { Cast, FieldValue, StrCast, BoolCast } from '../../new_fields/Types';
+import { BoolCast, Cast, FieldValue, StrCast } from '../../new_fields/Types';
+import { TraceMobx } from '../../new_fields/util';
 import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
-import { emptyFunction, returnEmptyString, returnFalse, returnOne, returnTrue, Utils, emptyPath } from '../../Utils';
+import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, Utils } from '../../Utils';
 import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
 import { DocServer } from '../DocServer';
 import { Docs, DocumentOptions } from '../documents/Documents';
+import { DocumentType } from '../documents/DocumentTypes';
 import { HistoryUtil } from '../util/History';
+import RichTextMenu from '../util/RichTextMenu';
+import { Scripting } from '../util/Scripting';
+import SettingsManager from '../util/SettingsManager';
 import SharingManager from '../util/SharingManager';
 import { Transform } from '../util/Transform';
-import { CollectionLinearView } from './collections/CollectionLinearView';
-import { CollectionViewType, CollectionView } from './collections/CollectionView';
 import { CollectionDockingView } from './collections/CollectionDockingView';
+import MarqueeOptionsMenu from './collections/collectionFreeForm/MarqueeOptionsMenu';
+import { CollectionLinearView } from './collections/CollectionLinearView';
+import { CollectionView, CollectionViewType } from './collections/CollectionView';
 import { ContextMenu } from './ContextMenu';
 import { DictationOverlay } from './DictationOverlay';
 import { DocumentDecorations } from './DocumentDecorations';
+import GestureOverlay from './GestureOverlay';
 import KeyManager from './GlobalKeyHandler';
 import "./MainView.scss";
 import { MainViewNotifs } from './MainViewNotifs';
+import { AudioBox } from './nodes/AudioBox';
 import { DocumentView } from './nodes/DocumentView';
+import { RadialMenu } from './nodes/RadialMenu';
+import { OverlayView } from './OverlayView';
 import PDFMenu from './pdf/PDFMenu';
 import { PreviewCursor } from './PreviewCursor';
-import { FilterBox } from './search/FilterBox';
-import { SchemaHeaderField, RandomPastel } from '../../new_fields/SchemaHeaderField';
-//import { DocumentManager } from '../util/DocumentManager';
-import { RecommendationsBox } from './RecommendationsBox';
-import { PresBox } from './nodes/PresBox';
-import { OverlayView } from './OverlayView';
-import MarqueeOptionsMenu from './collections/collectionFreeForm/MarqueeOptionsMenu';
-import GestureOverlay from './GestureOverlay';
-import { Scripting } from '../util/Scripting';
-import { AudioBox } from './nodes/AudioBox';
-import SettingsManager from '../util/SettingsManager';
-import { TraceMobx } from '../../new_fields/util';
-import { RadialMenu } from './nodes/RadialMenu';
-import RichTextMenu from '../util/RichTextMenu';
-import { DocumentType } from '../documents/DocumentTypes';
 
 @observer
 export class MainView extends React.Component {
diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
index cd9666af8..4790a2ad7 100644
--- a/src/client/views/SearchDocBox.tsx
+++ b/src/client/views/SearchDocBox.tsx
@@ -81,8 +81,8 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
     updateKey = async (newKey: string) => {
         this.query = newKey;
         if (newKey.length > 1) {
-            let newdocs = await this.getAllResults(this.query);
-            let things = newdocs.docs
+            const newdocs = await this.getAllResults(this.query);
+            const things = newdocs.docs;
             console.log(things);
             console.log(this.content);
             runInAction(() => {
@@ -152,10 +152,9 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
     enter = async (e: React.KeyboardEvent) => {
         console.log(e.key);
         if (e.key === "Enter") {
-            let newdocs = await this.getAllResults(this.query)
-            let things = newdocs.docs
-            console.log(things);
-            this.content = Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs: "Results"` });
+            const newdocs = await this.getAllResults(this.query);
+            console.log(newdocs.docs);
+            this.content = Docs.Create.TreeDocument(newdocs.docs, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs: "Results"` });
 
         }
     }
@@ -290,7 +289,7 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
             }
         }
         //return Docs.Create.TreeDocument(docs, { _width: 200, _height: 400, backgroundColor: "grey", title: `Search Docs: "${this._searchString}"` });
-        return Docs.Create.QueryDocument(docs, { _width: 200, _height: 400, searchText: this._searchString, title: `Query Docs: "${this._searchString}"` });
+        return Docs.Create.QueryDocument({ _width: 200, _height: 400, searchText: this._searchString, title: `Query Docs: "${this._searchString}"` });
     }
 
     @action.bound
@@ -416,7 +415,7 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
                         top: 0,
                     }}
                     title={"Add Metadata"}
-                    onClick={action(() => { this.editingMetadata = !this.editingMetadata })}
+                    onClick={action(() => this.editingMetadata = !this.editingMetadata)}
                 />
                 <div className="editableclass" onKeyPress={this.enter} style={{ opacity: isEditing ? 1 : 0, pointerEvents: isEditing ? "auto" : "none", transition: "0.4s opacity ease", position: "absolute", top: 0, left: 0, height: 20, width: "-webkit-fill-available" }}>
                     <EditableView
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index e61f90db8..3fb330840 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -133,6 +133,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                     CollectionView={undefined}
                     ContainingCollectionDoc={undefined}
                     ContainingCollectionView={undefined}
+                    rootSelected={returnFalse}
                     onCheckedClick={this.scriptField!}
                     onChildClick={this.scriptField!}
                     LibraryPath={emptyPath}
diff --git a/src/client/views/collections/CollectionLinearView.scss b/src/client/views/collections/CollectionLinearView.scss
index eae9e0220..123a27deb 100644
--- a/src/client/views/collections/CollectionLinearView.scss
+++ b/src/client/views/collections/CollectionLinearView.scss
@@ -8,6 +8,8 @@
         display:flex;
         height: 100%;
         >label {
+            margin-top: "auto";
+            margin-bottom: "auto";
             background: $dark-color;
             color: $light-color;
             display: inline-block;
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index a6ada75b2..728b3066d 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -3,7 +3,7 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, HeightSym, WidthSym } from '../../../new_fields/Doc';
 import { makeInterface } from '../../../new_fields/Schema';
-import { BoolCast, NumCast, StrCast, Cast } from '../../../new_fields/Types';
+import { BoolCast, NumCast, StrCast, Cast, ScriptCast } from '../../../new_fields/Types';
 import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils, returnFalse } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { Transform } from '../../util/Transform';
@@ -13,7 +13,6 @@ import { CollectionSubView } from './CollectionSubView';
 import { DocumentView } from '../nodes/DocumentView';
 import { documentSchema } from '../../../new_fields/documentSchemas';
 import { Id } from '../../../new_fields/FieldSymbols';
-import { ScriptField } from '../../../new_fields/ScriptField';
 
 
 type LinearDocument = makeInterface<[typeof documentSchema,]>;
@@ -28,12 +27,10 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
     private _selectedDisposer?: IReactionDisposer;
 
     componentWillUnmount() {
-        this._dropDisposer && this._dropDisposer();
-        this._widthDisposer && this._widthDisposer();
-        this._selectedDisposer && this._selectedDisposer();
-        this.childLayoutPairs.map((pair, ind) => {
-            Cast(pair.layout.proto?.onPointerUp, ScriptField)?.script.run({ this: pair.layout.proto }, console.log);
-        });
+        this._dropDisposer?.();
+        this._widthDisposer?.();
+        this._selectedDisposer?.();
+        this.childLayoutPairs.map((pair, ind) => ScriptCast(pair.layout.proto?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log));
     }
 
     componentDidMount() {
@@ -54,11 +51,11 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                         selected = pair;
                     }
                     else {
-                        Cast(pair.layout.proto?.onPointerUp, ScriptField)?.script.run({ this: pair.layout.proto }, console.log);
+                        ScriptCast(pair.layout.proto?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log);
                     }
                 });
                 if (selected && selected.layout) {
-                    Cast(selected.layout.proto?.onPointerDown, ScriptField)?.script.run({ this: selected.layout.proto }, console.log);
+                    ScriptCast(selected.layout.proto?.onPointerDown)?.script.run({ this: selected.layout.proto }, console.log);
                 }
             }),
             { fireImmediately: true }
@@ -81,14 +78,16 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
     render() {
         const guid = Utils.GenerateGuid();
         const flexDir: any = StrCast(this.Document.flexDirection);
+        const backgroundColor = StrCast(this.props.Document.backgroundColor, "black");
+        const color = StrCast(this.props.Document.color, "white");
         return <div className="collectionLinearView-outer">
             <div className="collectionLinearView" ref={this.createDashEventsTarget} >
-                <input id={`${guid}`} type="checkbox" checked={BoolCast(this.props.Document.linearViewIsExpanded)} ref={this.addMenuToggle}
-                    onChange={action((e: any) => this.props.Document.linearViewIsExpanded = this.addMenuToggle.current!.checked)} />
-                <label htmlFor={`${guid}`} title="Close Menu" style={{ marginTop: "auto", marginBottom: "auto", 
-                background: StrCast(this.props.Document.backgroundColor, "black") === StrCast(this.props.Document.color, "white") ? "black" : StrCast(this.props.Document.backgroundColor, "black") }} >
+                <label htmlFor={`${guid}`} title="Close Menu" style={{ background: backgroundColor === color ? "black" : backgroundColor }}
+                    onPointerDown={e => e.stopPropagation()} >
                     <p>+</p>
                 </label>
+                <input id={`${guid}`} type="checkbox" checked={BoolCast(this.props.Document.linearViewIsExpanded)} ref={this.addMenuToggle}
+                    onChange={action((e: any) => this.props.Document.linearViewIsExpanded = this.addMenuToggle.current!.checked)} />
 
                 <div className="collectionLinearView-content" style={{ height: this.dimension(), flexDirection: flexDir }}>
                     {this.childLayoutPairs.map((pair, ind) => {
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index f124fe21b..7b16ff546 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -159,6 +159,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             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,
diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx
index 47118e758..0e2685d41 100644
--- a/src/client/views/nodes/DocumentBox.tsx
+++ b/src/client/views/nodes/DocumentBox.tsx
@@ -112,7 +112,7 @@ export class DocumentBox extends DocAnnotatableComponent<FieldViewProps, DocBoxS
         if (containedDoc && childTemplateName && !containedDoc["layout_" + childTemplateName]) {
             setTimeout(() => {
                 DocumentView.createCustomView(containedDoc, Docs.Create.StackingDocument, childTemplateName);
-                Doc.expandTemplateLayout(Cast(containedDoc["layout_" + childTemplateName], Doc, null)!, containedDoc, undefined);
+                Doc.expandTemplateLayout(Cast(containedDoc["layout_" + childTemplateName], Doc, null), containedDoc, undefined);
             }, 0);
         }
         const contents = !(containedDoc instanceof Doc) ? (null) : <ContentFittingDocumentView
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 42f5fb946..9cccc9765 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -273,9 +273,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
     }
 
-    dontDecorateSelection: any = false;
     onClick = (e: React.MouseEvent | React.PointerEvent) => {
-        this.dontDecorateSelection = this.props.Document.dontDecorateSelection && (!e.ctrlKey || e.button < 2);
         if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick &&
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
             let stopPropagate = true;
@@ -295,7 +293,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                     this: this.props.Document,
                     self: Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document,
                     containingCollection: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey
-                }, console.log) && !this.props.Document.dontDecorateSelection && !this.props.Document.isButton && this.select(false), "on click");
+                }, console.log) && !this.props.Document.isButton && this.select(false), "on click");
             } else if (this.Document.type === DocumentType.BUTTON) {
                 UndoManager.RunInBatch(() => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY), "on button click");
             } else if (this.Document.isButton) {
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 241345f3e..94195fbd6 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -292,7 +292,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
         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, "onRight", anchor1Id);
     }
 
     getNodeEndpoints(context: Node, node: Node): { from: number, to: number } | null {
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 3d59ea61a..ef039c857 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -59,6 +59,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             ContainingCollectionView: undefined,
             ContainingCollectionDoc: undefined,
             fieldKey: this.props.keyName,
+            rootSelected: returnFalse,
             isSelected: returnFalse,
             select: emptyFunction,
             dropAction:"alias",
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index 5913c5a82..2a6eff7ff 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -64,7 +64,7 @@ export default class PDFMenu extends AntimodeMenu {
     togglePin = action((e: React.MouseEvent) => {
         this.Pinned = !this.Pinned;
         !this.Pinned && (this.Highlighting = false);
-    })
+    });
 
     @action
     highlightClicked = (e: React.MouseEvent) => {
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 49b6b18ca..a5b24addc 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -89,9 +89,7 @@ export class SearchBox extends React.Component<SearchProps> {
 
 
     @action
-    getViews = async (doc: Doc) => {
-        return await SearchUtil.GetViewsOfDocument(doc);
-    }
+    getViews = (doc: Doc) => SearchUtil.GetViewsOfDocument(doc);
 
     @action.bound
     onChange(e: React.ChangeEvent<HTMLInputElement>) {
@@ -130,23 +128,18 @@ export class SearchBox extends React.Component<SearchProps> {
         }
     }
 
-    public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB, DocumentType.TEMPLATE];
+    public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB];
     //if true, any keywords can be used. if false, all keywords are required.
     //this also serves as an indicator if the word status filter is applied
     @observable private _filterOpen: boolean = false;
     //if icons = all icons, then no icon filter is applied
     @observable private _icons: string[] = this._allIcons;
     //if all of these are true, no key filter is applied
-    @observable private _anyKeywordStatus: boolean = true;
-    @observable private _allKeywordStatus: boolean = true;
     @observable private _titleFieldStatus: boolean = true;
     @observable private _authorFieldStatus: boolean = true;
-    @observable private _dataFieldStatus: boolean = true;
     //this also serves as an indicator if the collection status filter is applied
     @observable public _deletedDocsStatus: boolean = false;
     @observable private _collectionStatus = false;
-    @observable private _collectionSelfStatus = true;
-    @observable private _collectionParentStatus = true;
 
 
     getFinalQuery(query: string): string {
@@ -187,7 +180,7 @@ export class SearchBox extends React.Component<SearchProps> {
 
     @action
     filterDocsByType(docs: Doc[]) {
-        if (this._icons.length === 9) {
+        if (this._icons.length === this._allIcons.length) {
             return docs;
         }
         const finalDocs: Doc[] = [];
@@ -218,7 +211,7 @@ export class SearchBox extends React.Component<SearchProps> {
     }
 
     get filterTypes() {
-        return this._icons.length === 9 ? undefined : this._icons;
+        return this._icons.length === this._allIcons.length ? undefined : this._icons;
     }
 
     @action.bound
@@ -296,7 +289,7 @@ export class SearchBox extends React.Component<SearchProps> {
 
     @action
     submitSearch = async () => {
-        let query = this._searchString;
+        const query = this._searchString;
         this.getFinalQuery(query);
         this._results = [];
         this._resultsSet.clear();
@@ -526,10 +519,10 @@ export class SearchBox extends React.Component<SearchProps> {
     handleNodeChange = () => {
         this._nodeStatus = !this._nodeStatus;
         if (this._nodeStatus) {
-            this.expandSection(`node${this.props.id}`)
+            this.expandSection(`node${this.props.id}`);
         }
         else {
-            this.collapseSection(`node${this.props.id}`)
+            this.collapseSection(`node${this.props.id}`);
         }
     }
 
@@ -565,13 +558,13 @@ export class SearchBox extends React.Component<SearchProps> {
 
 
     collapseSection(thing: string) {
-        let id = this.props.id;
-        let element = document.getElementById(thing)!;
+        const id = this.props.id;
+        const element = document.getElementById(thing)!;
         // get the height of the element's inner content, regardless of its actual size
-        var sectionHeight = element.scrollHeight;
+        const sectionHeight = element.scrollHeight;
 
         // temporarily disable all css transitions
-        var elementTransition = element.style.transition;
+        const elementTransition = element.style.transition;
         element.style.transition = '';
 
         // on the next frame (as soon as the previous style change has taken effect),
@@ -585,7 +578,7 @@ export class SearchBox extends React.Component<SearchProps> {
             // have the element transition to height: 0
             requestAnimationFrame(function () {
                 element.style.height = 0 + 'px';
-                thing == `filterhead${id}` ? document.getElementById(`filterhead${id}`)!.style.padding = "0" : null;
+                thing ===`filterhead${id}` ? document.getElementById(`filterhead${id}`)!.style.padding = "0" : null;
             });
         });
 
@@ -595,12 +588,11 @@ export class SearchBox extends React.Component<SearchProps> {
 
     expandSection(thing: string) {
         console.log("expand");
-        let element = document.getElementById(thing)!;
+        const element = document.getElementById(thing)!;
         // get the height of the element's inner content, regardless of its actual size
-        var sectionHeight = element.scrollHeight;
+        const sectionHeight = element.scrollHeight;
 
         // have the element transition to the height of its inner content
-        let temp = element.style.height;
         element.style.height = sectionHeight + 'px';
 
         // when the next css transition finishes (which should be the one we just triggered)
@@ -620,7 +612,7 @@ export class SearchBox extends React.Component<SearchProps> {
     }
 
     autoset(thing: string) {
-        let element = document.getElementById(thing)!;
+        const element = document.getElementById(thing)!;
         console.log("autoset");
         element.removeEventListener('transitionend', function (e) { });
 
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index 4bf871d97..3ac46362a 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -42,7 +42,6 @@ export const documentSchema = createSchema({
     removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped
     isTemplateForField: "string",// when specifies a field key, then the containing document is a template that renders the specified field
     isBackground: "boolean",    // whether document is a background element and ignores input events (can only selet with marquee)
-    dontDecorateSelection: "boolean",      // whether document should be selected when clicked (usually set to false for buttons)
     treeViewOpen: "boolean",    //  flag denoting whether the documents sub-tree (contents) is visible or hidden
     treeViewExpandedView: "string", // name of field whose contents are being displayed as the document's subtree
     treeViewPreventOpen: "boolean", // ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document)
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index eeb19b034..da33e3050 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -97,11 +97,15 @@ export class CurrentUserUtils {
             _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100,
             icon: data.icon,
             title: data.title,
+            isButton: true,
             ignoreClick: data.ignoreClick,
             dropAction: data.click ? "copy" : undefined,
-            onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined, onClick: data.click ? ScriptField.MakeScript(data.click) : undefined,
-            ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, activePen: data.activePen, dontDecorateSelection: true,
-            backgroundColor: data.backgroundColor, removeDropProperties: new List<string>(["dropAction"]), dragFactory: data.dragFactory,
+            onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined,
+            onClick: data.click ? ScriptField.MakeScript(data.click) : undefined,
+            ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined,
+            activePen: data.activePen,
+            backgroundColor: data.backgroundColor, removeDropProperties: new List<string>(["dropAction"]),
+            dragFactory: data.dragFactory,
         }));
     }
 
@@ -166,9 +170,12 @@ export class CurrentUserUtils {
     static setupThumbDoc(userDoc: Doc) {
         if (!userDoc.thumbDoc) {
             const thumbDoc = Docs.Create.LinearDocument(CurrentUserUtils.setupThumbButtons(userDoc), {
-                _width: 100, _height: 50, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", _autoHeight: true, _yMargin: 5, linearViewIsExpanded: true, backgroundColor: "white"
+                _width: 100, _height: 50, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons",
+                _autoHeight: true, _yMargin: 5, linearViewIsExpanded: true, backgroundColor: "white"
+            });
+            thumbDoc.inkToTextDoc = Docs.Create.LinearDocument([], {
+                _width: 300, _height: 25, _autoHeight: true, _chromeStatus: "disabled", linearViewIsExpanded: true, flexDirection: "column"
             });
-            thumbDoc.inkToTextDoc = Docs.Create.LinearDocument([], { _width: 300, _height: 25, _autoHeight: true, _chromeStatus: "disabled", linearViewIsExpanded: true, flexDirection: "column" });
             userDoc.thumbDoc = thumbDoc;
         }
         return Cast(userDoc.thumbDoc, Doc);
@@ -210,11 +217,12 @@ export class CurrentUserUtils {
         });
 
         return Docs.Create.ButtonDocument({
-            _width: 35, _height: 25, title: "Tools", fontSize: 10, targetContainer: sidebarContainer, dontDecorateSelection: true,
+            _width: 35, _height: 25, title: "Tools", fontSize: 10, targetContainer: sidebarContainer,
             letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
             sourcePanel: Docs.Create.StackingDocument([dragCreators, color], {
                 _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true
             }),
+            isButton: true,
             onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"),
         });
     }
@@ -236,11 +244,12 @@ export class CurrentUserUtils {
         });
 
         return Docs.Create.ButtonDocument({
-            _width: 50, _height: 25, title: "Library", fontSize: 10, dontDecorateSelection: true,
+            _width: 50, _height: 25, title: "Library", fontSize: 10,
             letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
             sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, Docs.Prototypes.MainLinkDocument(), doc, doc.recentlyClosed as Doc], {
                 title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "place", lockedPosition: true, boxShadow: "0 0", dontRegisterChildren: true
             }),
+            isButton: true,
             targetContainer: sidebarContainer,
             onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;")
         });
@@ -249,11 +258,12 @@ export class CurrentUserUtils {
     // setup the Search button which will display the search panel.  
     static setupSearchPanel(sidebarContainer: Doc) {
         return Docs.Create.ButtonDocument({
-            _width: 50, _height: 25, title: "Search", fontSize: 10, dontDecorateSelection: true,
+            _width: 50, _height: 25, title: "Search", fontSize: 10,
             letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
             sourcePanel: Docs.Create.QueryDocument({ title: "search stack", }),
             targetContainer: sidebarContainer,
             lockedPosition: true,
+            isButton: true,
             onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel")
         });
     }
@@ -280,26 +290,26 @@ export class CurrentUserUtils {
     static setupExpandingButtons(doc: Doc) {
         const queryTemplate = Docs.Create.MulticolumnDocument(
             [
-                Docs.Create.QueryDocument({ title: "query", _height: 200, forceActive: true  }),
+                Docs.Create.QueryDocument({ title: "query", _height: 200, forceActive: true }),
                 Docs.Create.FreeformDocument([], { title: "data", _height: 100, _LODdisable: true, forceActive: true })
             ],
             { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true });
         queryTemplate.isTemplateDoc = makeTemplate(queryTemplate);
         const slideTemplate = Docs.Create.MultirowDocument(
             [
-                Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, forceActive: true  }),
-                Docs.Create.TextDocument("", { title: "text", _height: 100, forceActive: true})
+                Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, forceActive: true }),
+                Docs.Create.TextDocument("", { title: "text", _height: 100, forceActive: true })
             ],
-            { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true});
+            { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true });
         slideTemplate.isTemplateDoc = makeTemplate(slideTemplate);
         const descriptionTemplate = Docs.Create.TextDocument("", { title: "text", _height: 100, _showTitle: "title" });
         Doc.GetProto(descriptionTemplate).layout = FormattedTextBox.LayoutString("description");
         descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView");
 
-        const ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ ...opts, dontDecorateSelection: true, dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100 })) as any as Doc;
+        const ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ ...opts, isButton: true, dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100 })) as any as Doc;
         const blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, {
             ...opts,
-            _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", dontDecorateSelection: true, forceActive: true,
+            _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", isButton: true, forceActive: true,
             dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
             backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true
         })) as any as Doc;
@@ -309,8 +319,8 @@ export class CurrentUserUtils {
         doc.slidesBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "presentation slide", icon: "sticky-note" });
         doc.descriptionBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: descriptionTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "description view", icon: "sticky-note" });
         doc.queryBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: queryTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "query view", icon: "sticky-note" });
-        doc.templateButtons = blist({ title: "template buttons" }, [doc.slidesBtn as Doc, doc.descriptionBtn as Doc, doc.queryBtn as Doc]);
-        doc.expandingButtons = blist({ title: "expanding buttons" }, [doc.undoBtn as Doc, doc.redoBtn as Doc, doc.templateButtons as Doc]);
+        doc.templateButtons = blist({ title: "template buttons", ignoreClick: true }, [doc.slidesBtn as Doc, doc.descriptionBtn as Doc, doc.queryBtn as Doc]);
+        doc.expandingButtons = blist({ title: "expanding buttons", ignoreClick: true }, [doc.undoBtn as Doc, doc.redoBtn as Doc, doc.templateButtons as Doc]);
         doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([doc.noteTypes as Doc, doc.templateButtons as Doc], {
             title: "template layouts", _xPadding: 0,
             dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name })
-- 
cgit v1.2.3-70-g09d2

