From 78227f09b30db57c6f500bd2e2d02f43d133d1da Mon Sep 17 00:00:00 2001
From: Andy Rickert <andrew_rickert@brown.edu>
Date: Wed, 10 Jun 2020 18:23:27 -0400
Subject: highlights

---
 src/client/views/nodes/formattedText/FormattedTextBox.tsx | 3 +++
 1 file changed, 3 insertions(+)

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

diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index fc131cd38..cb84921f8 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -253,10 +253,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
             const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true });
             const res = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
+            console.log(res);
             let tr = this._editorView.state.tr;
             const flattened: TextSelection[] = [];
             res.map(r => r.map(h => flattened.push(h)));
+            console.log(flattened);
             const lastSel = Math.min(flattened.length - 1, this._searchIndex);
+            console.log(lastSel)
             flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark));
             this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
             this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
-- 
cgit v1.2.3-70-g09d2


From db97843dccf820231bec0f9a2f8d9de0b64bb71f Mon Sep 17 00:00:00 2001
From: Andy Rickert <andrew_rickert@brown.edu>
Date: Thu, 11 Jun 2020 20:56:48 -0400
Subject: ability to parse back and forth through internal seaarch results

---
 .../views/nodes/formattedText/FormattedTextBox.tsx |  48 ++++++++-
 src/client/views/pdf/PDFViewer.tsx                 |  11 ++
 src/client/views/search/SearchItem.tsx             | 115 ++++++++++++++-------
 3 files changed, 130 insertions(+), 44 deletions(-)

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

diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index cb84921f8..aad4e82b5 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -248,24 +248,61 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             this._editorView.dispatch(tr.addMark(flattened[lastSel].from, flattened[lastSel].to, link));
         }
     }
-    public highlightSearchTerms = (terms: string[]) => {
+    public highlightSearchTerms = (terms: string[])=> {
         if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
+
             const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
             const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true });
             const res = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
-            console.log(res);
+            let length = res[0].length;
             let tr = this._editorView.state.tr;
             const flattened: TextSelection[] = [];
             res.map(r => r.map(h => flattened.push(h)));
-            console.log(flattened);
+            if (this._searchIndex>1){
+                this._searchIndex+=-2;
+            }
+            else if (this._searchIndex===1){
+                this._searchIndex=length-1;
+            }
+            else if (this._searchIndex===0){
+                this._searchIndex=length-2;
+            }
+            
+            const lastSel = Math.min(flattened.length - 1, this._searchIndex);
+            flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark));
+            this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
+            this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
+            let index = this._searchIndex;
+            console.log(index);
+
+            Doc.GetProto(this.dataDoc).searchIndex = index;
+            Doc.GetProto(this.dataDoc).length=length;
+        }
+    }
+
+    public highlightSearchTerms2 = (terms: string[])=> {
+        if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
+
+            const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
+            const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true });
+            const res = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
+            let length = res[0].length;
+            let tr = this._editorView.state.tr;
+            const flattened: TextSelection[] = [];
+            res.map(r => r.map(h => flattened.push(h)));       
             const lastSel = Math.min(flattened.length - 1, this._searchIndex);
-            console.log(lastSel)
             flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark));
             this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
             this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
+            let index = this._searchIndex;
+            console.log(index);
+
+            Doc.GetProto(this.dataDoc).searchIndex = index;
+            Doc.GetProto(this.dataDoc).length=length;
         }
     }
 
+
     public unhighlightSearchTerms = () => {
         if (this._editorView && (this._editorView as any).docView) {
             const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
@@ -668,6 +705,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         this._disposers.search = reaction(() => this.rootDoc.searchMatch,
             search => search ? this.highlightSearchTerms([Doc.SearchQuery()]) : this.unhighlightSearchTerms(),
             { fireImmediately: true });
+        this._disposers.search2 = reaction(() => this.rootDoc.searchMatch2,
+            search => search ? this.highlightSearchTerms2([Doc.SearchQuery()]) : this.unhighlightSearchTerms(),
+            { fireImmediately: true });
 
         this._disposers.record = reaction(() => this._recording,
             () => {
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 5bad248be..882e48de7 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -333,6 +333,10 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
     nextAnnotation = () => {
         this.Index = Math.min(this.Index + 1, this.allAnnotations.length - 1);
         this.scrollToAnnotation(this.allAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y))[this.Index]);
+        this.Document.searchIndex = this.Index;
+        this.Document.length=this.allAnnotations.length;
+        console.log(this.Index);
+
     }
 
     @action
@@ -399,6 +403,9 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
                 phraseSearch: true,
                 query: searchString
             });
+            console.log(this.Index);
+            this.Document.searchIndex = this.Index;
+            this.Document.length=this.allAnnotations.length;
         }
         else if (this._mainCont.current) {
             const executeFind = () => {
@@ -412,7 +419,11 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
             };
             this._mainCont.current.addEventListener("pagesloaded", executeFind);
             this._mainCont.current.addEventListener("pagerendered", executeFind);
+            console.log(this.Index);
+            this.Document.searchIndex = this.Index;
+            this.Document.length=this.allAnnotations.length;
         }
+
     }
 
     @action
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 35fc211af..d6589f265 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -2,7 +2,7 @@ import React = require("react");
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faCaretUp, faChartBar, faFile, faFilePdf, faFilm, faFingerprint, faGlobeAsia, faImage, faLink, faMusic, faObjectGroup, faStickyNote } 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 { Doc, DocCastAsync } from "../../../fields/Doc";
 import { Id } from "../../../fields/FieldSymbols";
@@ -149,7 +149,7 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
 
     constructor(props:any){
         super(props);
-        this.targetDoc._viewType= CollectionViewType.Stacking;
+        this.rootDoc._viewType= CollectionViewType.Stacking;
         this.rootDoc._viewType = CollectionViewType.Stacking;
         if (!this.searchItemTemplate) { // create exactly one presElmentBox template to use by any and all presentations.
             Doc.UserDoc().searchItemTemplate = new PrefetchProxy(Docs.Create.SearchItemBoxDocument({ title: "search item template", backgroundColor: "transparent", _xMargin: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data" }));
@@ -166,7 +166,7 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
     @observable _selected: boolean = false;
 
     onClick = () => {
-        DocumentManager.Instance.jumpToDocument(this.targetDoc, false);
+        DocumentManager.Instance.jumpToDocument(this.rootDoc, false);
     }
     @observable _useIcons = true;
     @observable _displayDim = 50;
@@ -175,17 +175,29 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
 
     componentDidMount() {
 
-        console.log(this.query);
+        this._reactionDisposer = reaction(
+            () => this.rootDoc.searchIndex,
+            search => {console.log(NumCast(search));this.searchPos=NumCast(search) },{ fireImmediately: true }
+        );
+
         Doc.SetSearchQuery(this.query);
-        this.targetDoc.searchMatch = true;
+        this.rootDoc.searchMatch = true;
     }
     componentWillUnmount() {
-        this.targetDoc.searchMatch = undefined;
+        this.rootDoc.searchMatch = undefined;
+        this._reactionDisposer && this._reactionDisposer();
     }
 
+    
+    @observable searchPos: number|undefined =0;
+
+    private _reactionDisposer?: IReactionDisposer;
+    
+    @computed get highlightPos(){return NumCast(this.rootDoc.searchIndex)}
+
     @action
     public DocumentIcon() {
-        const layoutresult = StrCast(this.targetDoc.type);
+        const layoutresult = StrCast(this.rootDoc.type);
         if (!this._useIcons) {
             const returnXDimension = () => this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE);
             const returnYDimension = () => this._displayDim;
@@ -196,10 +208,10 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
                 })}
                 onPointerEnter={action(() => this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE))} >
                 <ContentFittingDocumentView
-                    Document={this.targetDoc}
+                    Document={this.rootDoc}
                     LibraryPath={emptyPath}
                     rootSelected={returnFalse}
-                    fitToBox={StrCast(this.targetDoc.type).indexOf(DocumentType.COL) !== -1}
+                    fitToBox={StrCast(this.rootDoc.type).indexOf(DocumentType.COL) !== -1}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
                     addDocTab={returnFalse}
@@ -241,40 +253,60 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
     @action
     pointerDown = (e: React.PointerEvent) => { e.preventDefault(); e.button === 0 && SearchBox.Instance.openSearch(e); }
 
-    nextHighlight = (e: React.PointerEvent) => {
+    @action
+    nextHighlight = (e: React.MouseEvent) => {
         e.preventDefault();
-        e.button === 0 && SearchBox.Instance.openSearch(e);
-        this.targetDoc!.searchMatch = false;
-        setTimeout(() => this.targetDoc!.searchMatch = true, 0);
+        //e.button === 0 && SearchBox.Instance.openSearch(e);
+
+        this.rootDoc!.searchMatch = false;
+        setTimeout(() => this.rootDoc!.searchMatch = true, 0);
+        this.rootDoc.searchIndex=NumCast(this.rootDoc.searchIndex);
+
+        this.searchPos=NumCast(this.rootDoc!.searchIndex);
+        this.length=NumCast(this.rootDoc!.length);
     }
-    highlightDoc = (e: React.PointerEvent) => {
-        console.log(Cast(this.targetDoc.lines, listSpec("string"))!.length);
 
-        if (this.targetDoc!.type === DocumentType.LINK) {
-            if (this.targetDoc!.anchor1 && this.targetDoc!.anchor2) {
+    @action
+    nextHighlight2 = (e: React.MouseEvent) => {
+        e.preventDefault();
+        //e.button === 0 && SearchBox.Instance.openSearch(e);
+
+        this.rootDoc!.searchMatch2 = false;
+        setTimeout(() => this.rootDoc!.searchMatch2 = true, 0);
+        this.rootDoc.searchIndex=NumCast(this.rootDoc.searchIndex);
+
+        this.searchPos=NumCast(this.rootDoc!.searchIndex);
+        this.length=NumCast(this.rootDoc!.length);
+    }
 
-                const doc1 = Cast(this.targetDoc!.anchor1, Doc, null);
-                const doc2 = Cast(this.targetDoc!.anchor2, Doc, null);
+    @observable length:number|undefined = 0;
+
+    highlightDoc = (e: React.PointerEvent) => {
+        if (this.rootDoc!.type === DocumentType.LINK) {
+            if (this.rootDoc!.anchor1 && this.rootDoc!.anchor2) {
+
+                const doc1 = Cast(this.rootDoc!.anchor1, Doc, null);
+                const doc2 = Cast(this.rootDoc!.anchor2, Doc, null);
                 Doc.BrushDoc(doc1);
                 Doc.BrushDoc(doc2);
             }
         } else {
-            Doc.BrushDoc(this.targetDoc!);
+            Doc.BrushDoc(this.rootDoc!);
         }
         e.stopPropagation();
     }
 
     unHighlightDoc = (e: React.PointerEvent) => {
-        if (this.targetDoc!.type === DocumentType.LINK) {
-            if (this.targetDoc!.anchor1 && this.targetDoc!.anchor2) {
+        if (this.rootDoc!.type === DocumentType.LINK) {
+            if (this.rootDoc!.anchor1 && this.rootDoc!.anchor2) {
 
-                const doc1 = Cast(this.targetDoc!.anchor1, Doc, null);
-                const doc2 = Cast(this.targetDoc!.anchor2, Doc, null);
+                const doc1 = Cast(this.rootDoc!.anchor1, Doc, null);
+                const doc2 = Cast(this.rootDoc!.anchor2, Doc, null);
                 Doc.UnBrushDoc(doc1);
                 Doc.UnBrushDoc(doc2);
             }
         } else {
-            Doc.UnBrushDoc(this.targetDoc!);
+            Doc.UnBrushDoc(this.rootDoc!);
         }
     }
 
@@ -284,7 +316,7 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
         ContextMenu.Instance.clearItems();
         ContextMenu.Instance.addItem({
             description: "Copy ID", event: () => {
-                Utils.CopyText(StrCast(this.targetDoc[Id]));
+                Utils.CopyText(StrCast(this.rootDoc[Id]));
             },
             icon: "fingerprint"
         });
@@ -309,7 +341,7 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
             Math.abs(e.clientY - this._downY) > Utils.DRAG_THRESHOLD) {
             document.removeEventListener("pointermove", this.onPointerMoved);
             document.removeEventListener("pointerup", this.onPointerUp);
-            const doc = Doc.IsPrototype(this.targetDoc) ? Doc.MakeDelegate(this.targetDoc) : this.targetDoc;
+            const doc = Doc.IsPrototype(this.rootDoc) ? Doc.MakeDelegate(this.rootDoc) : this.rootDoc;
             DragManager.StartDocumentDrag([this._target], new DragManager.DocumentDragData([doc]), e.clientX, e.clientY);
         }
     }
@@ -320,7 +352,7 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
 
     @computed
     get contextButton() {
-        return <ParentDocSelector Document={this.targetDoc} addDocTab={(doc, where) => CollectionDockingView.AddRightSplit(doc)} />;
+        return <ParentDocSelector Document={this.rootDoc} addDocTab={(doc, where) => CollectionDockingView.AddRightSplit(doc)} />;
     }
 
     @computed get searchElementDoc() { return this.rootDoc; }
@@ -350,12 +382,12 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
     }
 
     render() {
-        const doc1 = Cast(this.targetDoc!.anchor1, Doc);
-        const doc2 = Cast(this.targetDoc!.anchor2, Doc);
-        if (this.targetDoc.isBucket === true){
+        const doc1 = Cast(this.rootDoc!.anchor1, Doc);
+        const doc2 = Cast(this.rootDoc!.anchor2, Doc);
+        if (this.rootDoc.isBucket === true){
             this.props.Document._viewType=CollectionViewType.Stacking;  
             this.props.Document._chromeStatus='disabled';
-            this.props.Document._height=this.targetDoc._height;
+            this.props.Document._height=this.rootDoc._height;
 
             return <div>
             <CollectionView {...this.props}
@@ -373,7 +405,7 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
             </button>
             </div>
         }
-        else if (this.targetDoc.isBucket === false){
+        else if (this.rootDoc.isBucket === false){
             this.props.Document._chromeStatus='disabled';
             return      <div className="searchItem">
                 <div className="searchItem-body" >
@@ -385,23 +417,26 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
         }
         else {
         return <div className="searchItem-overview" onPointerDown={this.pointerDown} onContextMenu={this.onContextMenu}>
-            <div className="searchItem" onPointerDown={this.nextHighlight} onPointerEnter={this.highlightDoc} onPointerLeave={this.unHighlightDoc}>
+            <div className="searchItem"  onPointerEnter={this.highlightDoc} onPointerLeave={this.unHighlightDoc}>
                 <div className="searchItem-body" onClick={this.onClick}>
                     <div className="searchItem-title-container">
-                        <div className="searchItem-title" style={{height:"10px", overflow:"hidden", textOverflow:"ellipsis"}}>{StrCast(this.targetDoc.title)}</div>
+                        <div className="searchItem-title" style={{height:"10px", overflow:"hidden", textOverflow:"ellipsis"}}>{StrCast(this.rootDoc.title)}</div>
                         <div className="searchItem-highlighting">
-                        {StrCast(this.targetDoc.highlighting).length ? "Matched fields:" + StrCast(this.targetDoc.highlighting) : Cast(this.targetDoc.lines, listSpec("string"))!.length ? Cast(this.targetDoc.lines, listSpec("string"))![0] : ""}</div>
-                        {/* {Cast(this.targetDoc.lines, listSpec("string"))!.filter((m, i) => i).map((l, i) => <div id={i.toString()} className="searchItem-highlighting">{l}</div>)} */}
-                    </div>
+                        {this.rootDoc.highlighting? StrCast(this.rootDoc.highlighting).length ? "Matched fields:" + StrCast(this.rootDoc.highlighting) : Cast(this.rootDoc.lines, listSpec("string"))!.length ? Cast(this.rootDoc.lines, listSpec("string"))![0] : "":null}</div>
+                        {/* {Cast(this.rootDoc.lines, listSpec("string"))!.filter((m, i) => i).map((l, i) => <div id={i.toString()} className="searchItem-highlighting">{l}</div>)} */}
+                        <button onClick={this.nextHighlight} style={{height:3, width:5}}/>
+                        {NumCast(this.rootDoc.length) > 1? `${NumCast(this.rootDoc.searchIndex)===0? NumCast(this.rootDoc.length):NumCast(this.rootDoc.searchIndex)} of ${NumCast(this.rootDoc.length)}`: null} 
+                        <button onClick={this.nextHighlight2}style={{height:3, width:5}}/>
+                        </div>
                 </div>
                 <div className="searchItem-info" style={{ width: this._useIcons ? "30px" : "100%" }}>
                     <div className={`icon-${this._useIcons ? "icons" : "live"}`}>
                         <div className="searchItem-type" title="Click to Preview" onPointerDown={this.onPointerDown}>{this.DocumentIcon()}</div>
-                        <div className="searchItem-label">{this.targetDoc.type ? this.targetDoc.type : "Other"}</div>
+                        <div className="searchItem-label">{this.rootDoc.type ? this.rootDoc.type : "Other"}</div>
                     </div>
                 </div>
                 <div className="searchItem-context" title="Drag as document">
-                    {(doc1 instanceof Doc && doc2 instanceof Doc) && this.targetDoc!.type === DocumentType.LINK ? <LinkContextMenu doc1={doc1} doc2={doc2} /> :
+                    {(doc1 instanceof Doc && doc2 instanceof Doc) && this.rootDoc!.type === DocumentType.LINK ? <LinkContextMenu doc1={doc1} doc2={doc2} /> :
                         this.contextButton}
                 </div>
             </div>
-- 
cgit v1.2.3-70-g09d2


From fb5291760d908fe54ec0134cbe3868d666b02b19 Mon Sep 17 00:00:00 2001
From: Andy Rickert <andrew_rickert@brown.edu>
Date: Mon, 15 Jun 2020 20:49:10 -0400
Subject: bugfixing with expading search terms within a bucket

---
 .../views/nodes/formattedText/FormattedTextBox.tsx | 10 ++--
 src/client/views/pdf/PDFViewer.tsx                 | 18 +++++--
 src/client/views/search/SearchBox.tsx              | 32 +++++-------
 src/client/views/search/SearchItem.tsx             | 60 +++++++++++++++++-----
 4 files changed, 77 insertions(+), 43 deletions(-)

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

diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index aad4e82b5..dff42bcb1 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -273,7 +273,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
             this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
             let index = this._searchIndex;
-            console.log(index);
 
             Doc.GetProto(this.dataDoc).searchIndex = index;
             Doc.GetProto(this.dataDoc).length=length;
@@ -295,7 +294,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
             this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
             let index = this._searchIndex;
-            console.log(index);
 
             Doc.GetProto(this.dataDoc).searchIndex = index;
             Doc.GetProto(this.dataDoc).length=length;
@@ -702,12 +700,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
 
         this.setupEditor(this.config, this.props.fieldKey);
 
-        this._disposers.search = reaction(() => this.rootDoc.searchMatch,
-            search => search ? this.highlightSearchTerms([Doc.SearchQuery()]) : this.unhighlightSearchTerms(),
-            { fireImmediately: true });
-        this._disposers.search2 = reaction(() => this.rootDoc.searchMatch2,
+        this._disposers.search = reaction(() => this.rootDoc.searchMatch2,
             search => search ? this.highlightSearchTerms2([Doc.SearchQuery()]) : this.unhighlightSearchTerms(),
             { fireImmediately: true });
+        this._disposers.search2 = reaction(() => this.rootDoc.searchMatch,
+            search => search ? this.highlightSearchTerms([Doc.SearchQuery()]) : this.unhighlightSearchTerms(),
+            { fireImmediately: true });
 
         this._disposers.record = reaction(() => this._recording,
             () => {
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 882e48de7..f23923279 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -107,6 +107,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
     private _scrollTopReactionDisposer?: IReactionDisposer;
     private _filterReactionDisposer?: IReactionDisposer;
     private _searchReactionDisposer?: IReactionDisposer;
+    private _searchReactionDisposer2?: IReactionDisposer;
     private _viewer: React.RefObject<HTMLDivElement> = React.createRef();
     private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
     private _selectionText: string = "";
@@ -144,6 +145,17 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
         runInAction(() => this._showWaiting = this._showCover = true);
         this.props.startupLive && this.setupPdfJsViewer();
         this._searchReactionDisposer = reaction(() => this.Document.searchMatch, search => {
+            if (search) {
+                this.search(Doc.SearchQuery(), false);
+                this._lastSearch = Doc.SearchQuery();
+            }
+            else {
+                setTimeout(() => this._lastSearch === "mxytzlaf" && this.search("mxytzlaf", true), 200); // bcz: how do we clear search highlights?
+                this._lastSearch && (this._lastSearch = "mxytzlaf");
+            }
+        }, { fireImmediately: true });
+
+        this._searchReactionDisposer2 = reaction(() => this.Document.searchMatch2, search => {
             if (search) {
                 this.search(Doc.SearchQuery(), true);
                 this._lastSearch = Doc.SearchQuery();
@@ -325,7 +337,10 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
     }
     @action
     prevAnnotation = () => {
+        console.log(this.Index);
         this.Index = Math.max(this.Index - 1, 0);
+        console.log(this.Index);
+        console.log(this.allAnnotations);
         this.scrollToAnnotation(this.allAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y))[this.Index]);
     }
 
@@ -335,7 +350,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
         this.scrollToAnnotation(this.allAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y))[this.Index]);
         this.Document.searchIndex = this.Index;
         this.Document.length=this.allAnnotations.length;
-        console.log(this.Index);
 
     }
 
@@ -403,7 +417,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
                 phraseSearch: true,
                 query: searchString
             });
-            console.log(this.Index);
             this.Document.searchIndex = this.Index;
             this.Document.length=this.allAnnotations.length;
         }
@@ -419,7 +432,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
             };
             this._mainCont.current.addEventListener("pagesloaded", executeFind);
             this._mainCont.current.addEventListener("pagerendered", executeFind);
-            console.log(this.Index);
             this.Document.searchIndex = this.Index;
             this.Document.length=this.allAnnotations.length;
         }
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 5ec911221..596a0cac7 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -376,7 +376,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         if (reset){
             this.layoutDoc._searchString="";
         }
-        console.log(this.layoutDoc._searchString);  
         this.dataDoc[this.fieldKey] = new List<Doc>([]);
         this.buckets=[];
         this.new_buckets={};
@@ -430,7 +429,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         }
 
         let bucket = Docs.Create.StackingDocument([],{ _viewType:CollectionViewType.Stacking,title: `default bucket`});
-        bucket.targetDoc = bucket;      
         bucket._viewType === CollectionViewType.Stacking;
         bucket._height=185;
         bucket.bucketfield = "results";
@@ -443,7 +441,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         let firstbucket = Docs.Create.StackingDocument([],{ _viewType:CollectionViewType.Stacking,title: this.firststring });
         firstbucket._height=185;
 
-        firstbucket.targetDoc = firstbucket;      
         firstbucket._viewType === CollectionViewType.Stacking;
         firstbucket.bucketfield = this.firststring;
         firstbucket.isBucket=true;
@@ -456,7 +453,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         if (this.secondstring!==""){
         let secondbucket = Docs.Create.StackingDocument([],{ _viewType:CollectionViewType.Stacking,title: this.secondstring });
         secondbucket._height=185;
-        secondbucket.targetDoc = secondbucket;      
         secondbucket._viewType === CollectionViewType.Stacking;
         secondbucket.bucketfield = this.secondstring;
         secondbucket.isBucket=true;
@@ -622,7 +618,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             this._visibleElements = [<div className="no-result">No Search Results</div>];
             //this._visibleDocuments= Docs.Create.
             let noResult= Docs.Create.TextDocument("",{title:"noResult"})
-            noResult.targetDoc=noResult;
             noResult.isBucket =false;
             Doc.AddDocToList(this.dataDoc, this.props.fieldKey, noResult);
             return;
@@ -673,10 +668,9 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                             }
                             const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
                             let lines = new List<string>(result[2]);
-                            result[0].lines=lines
+                            result[0].lines=lines;
                             result[0].highlighting=highlights.join(", ");
                             this._visibleDocuments[i] = result[0];
-                            result[0].targetDoc=result[0];
 
                             this._isSearch[i] = "search";
                         }
@@ -694,11 +688,13 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                                 this.new_buckets[StrCast(result[0].type)]=this.new_buckets[StrCast(result[0].type)]+1;
                             }
                             const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
-                            result[0].lines=new List<string>(result[2]);
+
+                            let lines = new List<string>(result[2]);
+
+                            result[0].lines= lines;
                             result[0].highlighting=highlights.join(", ");
                             if(i<this._visibleDocuments.length){
                             this._visibleDocuments[i]=result[0];
-                            result[0].targetDoc=result[0];
                             this._isSearch[i] = "search";
                             }
                             }
@@ -713,33 +709,30 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             let result = this._results[i];
             if (!this.blockedTypes.includes(StrCast(result[0].type))){
             if (this._isSearch[i] === "search" && (this._isSorted[i]===undefined ||this._isSorted[i]==="placeholder" )) {
-                console.log(StrCast(result[0].type));
                 if (StrCast(result[0].type)=== this.firststring && this.bucketcount[1]<3){
+                    result[0].parent= this.buckets![1];
                     Doc.AddDocToList(this.buckets![1], this.props.fieldKey, result[0]);
                     this.bucketcount[1]+=1;
-                    console.log("1 count")
                 }
                 else if (StrCast(result[0].type)=== this.secondstring && this.bucketcount[2]<3){
+                    result[0].parent= this.buckets![2];
                     Doc.AddDocToList(this.buckets![2], this.props.fieldKey, result[0]);
                     this.bucketcount[2]+=1;
-                    console.log("2 count")
                 }
                 else if (this.bucketcount[0]<3){
                     //Doc.AddDocToList(this.buckets![0], this.props.fieldKey, result[0]);
                     //this.bucketcount[0]+=1;
                     const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
-                    result[0].lines=new List<string>(result[2]);
+                    let lines = new List<string>(result[2]);
+                    result[0].lines= lines;
                     result[0].highlighting=highlights.join(", ");
-                    result[0].targetDoc=result[0];
                     Doc.AddDocToList(this.dataDoc, this.props.fieldKey, result[0]);
                 }
                 this._isSorted[i]="sorted"; 
             }
         }
         }
-        console.log(this.bucketcount[0]);
-        console.log(this.bucketcount[1]);
-        console.log(this.bucketcount[2]);
+
         if (this.buckets![0]){
         this.buckets![0]._height = this.bucketcount[0]*55 + 25;
         }
@@ -760,11 +753,10 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                     if ((this._isSorted[i]===undefined ||this._isSorted[i]==="placeholder" )) {
                         let result = this._results[i];
                         if (!this.blockedTypes.includes(StrCast(result[0].type))){
-
                         const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
-                        result[0].lines=new List<string>(result[2]);
+                        let lines = new List<string>(result[2]);
+                        result[0].lines= lines;
                         result[0].highlighting=highlights.join(", ");
-                        result[0].targetDoc=result[0];
                         Doc.AddDocToList(this.dataDoc, this.props.fieldKey, result[0]);
                     }
                 }
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 63baf625e..c1fd2d0b8 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -174,16 +174,40 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
 
     @computed get query() { return StrCast(this.lookupField("query")); }
 
+    private _oldHeight: number = 46;
+
     componentDidMount() {
+        let parent: Doc |undefined = undefined;
+        let height = 0;
+        if (this.rootDoc.parent){
+            parent = Cast(this.rootDoc.parent, Doc, null) as Doc;
+            height=(NumCast(parent._height));
+        }
 
         this._reactionDisposer = reaction(
             () => this.rootDoc.searchIndex,
             search => {console.log(NumCast(search));this.searchPos=NumCast(search) },{ fireImmediately: true }
         );
-
         this._reactionDisposer2 = reaction(
             () => this._useIcons,
-            el=> {console.log("YUH"); 
+            el=> { 
+                if (this.rootDoc.parent){
+                    parent = Cast(this.rootDoc.parent, Doc, null) as Doc;
+                    height=(NumCast(parent._height));
+                };
+                console.log(height);
+                console.log(this._oldHeight);
+            setTimeout(() =>{this._mainRef.current?.getBoundingClientRect()? this.props.Document._height= this._mainRef.current?.getBoundingClientRect().height : null;
+                parent!==undefined? this._mainRef.current?.getBoundingClientRect()? parent._height= -this._oldHeight + height +this._mainRef.current?.getBoundingClientRect().height : null: null;
+                this._mainRef.current?.getBoundingClientRect()?  this._oldHeight= this._mainRef.current?.getBoundingClientRect().height : null;
+                // this._oldHeight 55? this._oldHeight =55:null;
+            }, 1);
+        }
+        );
+
+        this._reactionDisposer3 = reaction(
+            () => this._displayLines,
+            el=> { 
             setTimeout(() =>(this._mainRef.current?.getBoundingClientRect()? this.props.Document._height= this._mainRef.current?.getBoundingClientRect().height : null), 1);
         }
         );
@@ -195,6 +219,7 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
         this.rootDoc.searchMatch = undefined;
         this._reactionDisposer && this._reactionDisposer();
         this._reactionDisposer2 && this._reactionDisposer2();
+        this._reactionDisposer3 && this._reactionDisposer3();
 
     }
 
@@ -203,6 +228,8 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
 
     private _reactionDisposer?: IReactionDisposer;
     private _reactionDisposer2?: IReactionDisposer;
+    private _reactionDisposer3?: IReactionDisposer;
+
 
     
     @computed get highlightPos(){return NumCast(this.rootDoc.searchIndex)}
@@ -371,7 +398,7 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
     }
 
     @computed get searchElementDoc() { return this.rootDoc; }
-    @computed get targetDoc() { return this.searchElementDoc?.targetDoc as Doc; }
+    // @computed get targetDoc() { return this.searchElementDoc?.targetDoc as Doc; }
 
     @computed get searchItemTemplate() { return Cast(Doc.UserDoc().searchItemTemplate, Doc, null); }
     childLayoutTemplate = () => this.layoutDoc._viewType === CollectionViewType.Stacking ? this.searchItemTemplate: undefined;
@@ -398,23 +425,20 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
     
     @action
     returnLines(){
+        if ((Cast(this.rootDoc.lines, listSpec("string")))!.length>1){
         if (!this._displayLines) {
-            return <div style={{height:50, width: 10}}
+            console.log(Cast(this.rootDoc.lines, listSpec("string")));
+            return <div style={{width: 10}}
             onPointerDown={action(() => {
                 this._displayLines = !this._displayLines;
                 //this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE);
             })}
             //onPointerEnter={action(() => this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE))}
              >
-            {Cast(this.rootDoc.lines, listSpec("string"))!.filter((m, i) => i).map((l, i) => <div id={i.toString()} className="searchItem-highlighting">`${l}`</div>)}
+            {Cast(this.rootDoc.lines, listSpec("string"))!.filter((m, i) => i).map((l, i) => <div style={{overflow:"visible"}}id={i.toString()} className="searchItem-highlighting">{l}</div>)}
             </div>;;
         }
-        else {
-        return <button style={{padding:2}} onClick={action(() => { this._displayLines = false; 
-        })} >
-            <FontAwesomeIcon icon="arrow-up" size="sm" />
-        </button>;
-        }
+    }
     }
     
     //this._displayDim = Number(SEARCH_THUMBNAIL_SIZE); 
@@ -423,14 +447,21 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
 
     returnButtons(){
         return <div>
-            {this.returnLines()}
+        <div> 
+        {this.rootDoc!.type === DocumentType.PDF? <button style={{padding:2}} onClick={action(() => { this._displayLines = false; 
+        })} >
+            <FontAwesomeIcon icon="arrow-up" size="sm" />
+        </button>: null}
             {`Instance ${NumCast(this.rootDoc.searchIndex)===0? NumCast(this.rootDoc.length):NumCast(this.rootDoc.searchIndex) } of ${NumCast(this.rootDoc.length)}`}
              <button onClick={this.nextHighlight} style={{padding:2}}>
                         <FontAwesomeIcon icon="arrow-up" size="sm"  /> 
                         </button>
                         <button onClick={this.nextHighlight2} style={{padding:2}}>                    
                         <FontAwesomeIcon icon="arrow-down" size="sm"  />
-                        </button>
+                        </button></div>
+                        <div style={{background: "lightgrey"}}>
+            {this.returnLines()}
+        </div>
         </div>
     }
 
@@ -472,6 +503,7 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
             </div>
         }
         else {
+            console.log(this.rootDoc.highlighting); 
         return <div className="searchItem-overview" onPointerDown={this.pointerDown} onContextMenu={this.onContextMenu}>
             <div ref={this._mainRef} className="searchItem"  onPointerEnter={this.highlightDoc} onPointerLeave={this.unHighlightDoc}>
                 <div className="searchItem-body" onClick={this.onClick}>
@@ -480,7 +512,7 @@ export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchem
                         <div className="searchItem-highlighting">
                         {this.rootDoc.highlighting? StrCast(this.rootDoc.highlighting).length ? "Matched fields:" + StrCast(this.rootDoc.highlighting) : Cast(this.rootDoc.lines, listSpec("string"))!.length ? Cast(this.rootDoc.lines, listSpec("string"))![0] : "":null}</div>
                         <div className={`icon-${this._displayLines ? "q" : "a"}`}>
-                        {NumCast(this.rootDoc.length) > 1? this.returnButtons(): null} 
+                        {NumCast(this.rootDoc.length) > 1 ?this.returnButtons(): null} 
                         </div>
                         </div>
                 </div>
-- 
cgit v1.2.3-70-g09d2


From 7a291cbffb9e609633759cfff8b459e1a32b4fc3 Mon Sep 17 00:00:00 2001
From: Andy Rickert <andrew_rickert@brown.edu>
Date: Thu, 25 Jun 2020 17:23:43 -0400
Subject: bugfixing search, refreshing docs, ghost buckets, etc.

---
 src/client/documents/Documents.ts                  |  1 -
 src/client/util/CurrentUserUtils.ts                |  6 ++--
 .../views/nodes/formattedText/FormattedTextBox.tsx | 15 ++++++----
 src/client/views/search/SearchBox.tsx              | 35 ++++++++++++++--------
 4 files changed, 35 insertions(+), 22 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index c32d187a0..ebdae1ce5 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -181,7 +181,6 @@ 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 quersyBox
     filterQuery?: filterData,
     linearViewIsExpanded?: boolean; // is linear view expanded
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index a7cb29815..0e0942496 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -42,10 +42,10 @@ export class CurrentUserUtils {
         if (doc["template-button-query"] === undefined) {
             const queryTemplate = Docs.Create.MulticolumnDocument(
                 [
-                    Docs.Create.SearchDocument({ _viewType: CollectionViewType.Stacking, title: "query", _height: 200 }),
+                    Docs.Create.SearchDocument({ _viewType: CollectionViewType.Stacking, ignoreClick: true, forceActive: true, lockedPosition: true, title: "query", _height: 200 }),
                     Docs.Create.FreeformDocument([], { title: "data", _height: 100, _LODdisable: true })
                 ],
-                { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true }
+                { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3,  _yMargin: 3, hideFilterView: true }
             );
             queryTemplate.isTemplateDoc = makeTemplate(queryTemplate);
             doc["template-button-query"] = CurrentUserUtils.ficon({
@@ -628,7 +628,7 @@ export class CurrentUserUtils {
             doc["tabs-button-search"] = new PrefetchProxy(Docs.Create.ButtonDocument({
                 _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: new PrefetchProxy(Docs.Create.SearchDocument({_viewType: CollectionViewType.Stacking, title: "sidebar search stack", })) as any as Doc,
+                sourcePanel: new PrefetchProxy(Docs.Create.SearchDocument({ignoreClick: true, childDropAction: "alias", lockedPosition: true, _viewType: CollectionViewType.Stacking, title: "sidebar search stack", })) as any as Doc,
                 searchFileTypes: new List<string>([DocumentType.RTF, DocumentType.IMG, DocumentType.PDF, DocumentType.VID, DocumentType.WEB, DocumentType.SCRIPTING]),
                 targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc,
                 lockedPosition: true,
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 6b522f6d1..ca7db2cd4 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -261,20 +261,23 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             let tr = this._editorView.state.tr;
             const flattened: TextSelection[] = [];
             res.map(r => r.map(h => flattened.push(h)));
+
+            
+            const lastSel = Math.min(flattened.length - 1, this._searchIndex);
+            flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark));
+            this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
+            this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
+            
+            console.log(this._searchIndex, length);
             if (this._searchIndex>1){
                 this._searchIndex+=-2;
             }
             else if (this._searchIndex===1){
                 this._searchIndex=length-1;
             }
-            else if (this._searchIndex===0){
+            else if (this._searchIndex===0 && length!==1){
                 this._searchIndex=length-2;
             }
-            
-            const lastSel = Math.min(flattened.length - 1, this._searchIndex);
-            flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark));
-            this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
-            this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
             let index = this._searchIndex;
 
             Doc.GetProto(this.dataDoc).searchIndex = index;
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 37d358b02..d1e1818c2 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -315,6 +315,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         console.log(selectedDocs);
         selectedDocs.forEach(async element => {
             const layout: string = StrCast(element.props.Document.layout);
+            console.log(layout);
             //checks if selected view (element) is a collection. if it is, adds to list to search through
             if (layout.indexOf("Collection") > -1) {
                 //makes sure collections aren't added more than once
@@ -391,13 +392,13 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         this._isSorted=[];
         this._visibleElements = [];
         this._visibleDocuments = [];
-        console.log(this._timeout);
-        
-        if (this._timeout){clearTimeout(this._timeout); this._timeout=undefined};
-        this._timeout= setTimeout(()=>{
-            console.log("Resubmitting search");
-            this.submitSearch();
-        }, 10000);
+        if (StrCast(this.props.Document.searchQuery)){
+            if (this._timeout){clearTimeout(this._timeout); this._timeout=undefined};
+            this._timeout= setTimeout(()=>{
+                console.log("Resubmitting search");
+                this.submitSearch();
+            }, 60000);
+            }
 
         if (query !== "") {
             this._endIndex = 12;
@@ -442,7 +443,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             }
         }
 
-        let bucket = Docs.Create.StackingDocument([],{ _viewType:CollectionViewType.Stacking,title: `default bucket`});
+        let bucket = Docs.Create.StackingDocument([],{ _viewType:CollectionViewType.Stacking, ignoreClick: true, forceActive: true, lockedPosition: true,title: `default bucket`});
         bucket._viewType === CollectionViewType.Stacking;
         bucket._height=185;
         bucket.bucketfield = "results";
@@ -452,7 +453,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         this.bucketcount[0]=0;
         
         if (this.firststring!==""){
-        let firstbucket = Docs.Create.StackingDocument([],{ _viewType:CollectionViewType.Stacking,title: this.firststring });
+        let firstbucket = Docs.Create.StackingDocument([],{ _viewType:CollectionViewType.Stacking, ignoreClick: true, forceActive: true, lockedPosition: true, title: this.firststring });
         firstbucket._height=185;
 
         firstbucket._viewType === CollectionViewType.Stacking;
@@ -465,7 +466,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         }
 
         if (this.secondstring!==""){
-        let secondbucket = Docs.Create.StackingDocument([],{ _viewType:CollectionViewType.Stacking,title: this.secondstring });
+        let secondbucket = Docs.Create.StackingDocument([],{ _viewType:CollectionViewType.Stacking, ignoreClick: true, forceActive: true, lockedPosition: true, title: this.secondstring });
         secondbucket._height=185;
         secondbucket._viewType === CollectionViewType.Stacking;
         secondbucket.bucketfield = this.secondstring;
@@ -475,21 +476,30 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         this.bucketcount[2]=0;
         }
 
-        let webbucket = Docs.Create.StackingDocument([],{ _viewType:CollectionViewType.Stacking,title: this.secondstring });
+        let webbucket = Docs.Create.StackingDocument([],{ _viewType:CollectionViewType.Stacking, childDropAction: "alias", ignoreClick: true, lockedPosition: true, title: this.secondstring });
         webbucket._height=185;
         webbucket._viewType === CollectionViewType.Stacking;
         webbucket.bucketfield = "webs";
         webbucket.isBucket=true;
+        let old = Cast(this.props.Document.webbucket,Doc) as Doc;
+        let old2=Cast(this.props.Document.bing,Doc) as Doc;
+        if (old){
+            console.log("Cleanup");
+            Doc.RemoveDocFromList(old, this.props.fieldKey,old2);
+        }
         const textDoc = Docs.Create.WebDocument(`https://bing.com/search?q=${this.layoutDoc._searchString}`, {
                     _width: 200,  _nativeHeight: 962, _nativeWidth: 800, isAnnotating: false,
                     title: "bing", UseCors: true
                 });
+        this.props.Document.bing=textDoc;
+        this.props.Document.webbucket = webbucket;
         Doc.AddDocToList(this.dataDoc, this.props.fieldKey, webbucket);
         Doc.AddDocToList(webbucket, this.props.fieldKey, textDoc);
 
 
     }
 
+
     @observable buckets:Doc[]|undefined;
 
     getAllResults = async (query: string) => {
@@ -539,6 +549,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                             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)) : [];
+                            doc? console.log(Cast(doc.context, Doc)) : null;
                             if (this.findCommonElements(hlights)){
                             }
                             else{
@@ -619,7 +630,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             basicWordStatus: this._basicWordStatus,
             icons: this._icons,
         }
-        return Docs.Create.SearchDocument({ _autoHeight: true, _viewType: CollectionViewType.Stacking , title: StrCast(this.layoutDoc._searchString), filterQuery: filter, searchQuery: StrCast(this.layoutDoc._searchString) });
+        return Docs.Create.SearchDocument({ _autoHeight: true, _viewType: CollectionViewType.Stacking , title: StrCast(this.layoutDoc._searchString), searchQuery: StrCast(this.layoutDoc._searchString) });
     }
 
     @action.bound
-- 
cgit v1.2.3-70-g09d2


From 502981833ef7f9e8179bf9c487b1e35404c6d4e1 Mon Sep 17 00:00:00 2001
From: Lionel Han <47760119+IGoByJoe@users.noreply.github.com>
Date: Tue, 28 Jul 2020 15:08:56 -0700
Subject: fix recursion bug and make link turn blue

---
 src/client/views/nodes/AudioBox.scss               |  2 +-
 src/client/views/nodes/AudioBox.tsx                | 34 ++++++++++++++++++----
 .../views/nodes/formattedText/FormattedTextBox.tsx | 24 +++++++++++++++
 3 files changed, 54 insertions(+), 6 deletions(-)

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

diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss
index 7b0e50e60..6d52988bb 100644
--- a/src/client/views/nodes/AudioBox.scss
+++ b/src/client/views/nodes/AudioBox.scss
@@ -194,7 +194,7 @@
                     background: gray;
                     border-radius: 50%;
                     box-shadow: black 2px 2px 1px;
-                    overflow: auto;
+                    overflow: visible;
                     cursor: pointer;
 
                     .audiobox-marker {
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 0cab0fc61..02932baac 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -72,6 +72,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     _left: boolean = false;
     _amount: number = 1;
     _markers: Array<any> = [];
+    _first: boolean = false;
 
     private _isPointerDown = false;
     private _currMarker: any;
@@ -128,6 +129,22 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         this._reactionDisposer = reaction(() => SelectionManager.SelectedDocuments(),
             selected => {
                 const sel = selected.length ? selected[0].props.Document : undefined;
+                // if (sel) {
+                //     DocListCast(sel.links).map((l, i) => {
+                //         let la1 = l.anchor1 as Doc;
+                //         let la2 = l.anchor2 as Doc;
+                //         let linkTime = NumCast(l.anchor2_timecode);
+                //         if (Doc.AreProtosEqual(la1, this.dataDoc)) {
+                //             la1 = l.anchor2 as Doc;
+                //             la2 = l.anchor1 as Doc;
+                //             linkTime = NumCast(l.anchor1_timecode);
+                //         }
+                //         console.log(linkTime);
+                //         if (linkTime) {
+                //             this.layoutDoc.playOnSelect && this.recordingStart && sel && sel.creationDate && !Doc.AreProtosEqual(sel, this.props.Document) && this.playFrom(linkTime);
+                //         }
+                //     });
+                // }
                 this.layoutDoc.playOnSelect && this.recordingStart && sel && sel.creationDate && !Doc.AreProtosEqual(sel, this.props.Document) && this.playFromTime(DateCast(sel.creationDate).date.getTime());
                 this.layoutDoc.playOnSelect && this.recordingStart && !sel && this.pause();
             });
@@ -186,7 +203,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                 if (endTime !== this.dataDoc.duration) {
                     play = setTimeout(() => this.pause(), (this._duration) * 1000);
                 }
-            } else {
+            } else { // this is getting called because time is greater than duration
                 this.pause();
             }
         }
@@ -226,9 +243,9 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     specificContextMenu = (e: React.MouseEvent): void => {
         const funcs: ContextMenuProps[] = [];
         funcs.push({ description: (this.layoutDoc.playOnSelect ? "Don't play" : "Play") + " when document selected", event: () => this.layoutDoc.playOnSelect = !this.layoutDoc.playOnSelect, icon: "expand-arrows-alt" });
-        funcs.push({ description: (this.layoutDoc.hideMarkers ? "Don't hide" : "Hide") + " markers", event: () => this.layoutDoc.hideMarkers = !this.layoutDoc.hideMarkers, icon: "expand-arrows-alt" })
-        funcs.push({ description: (this.layoutDoc.hideLabels ? "Don't hide" : "Hide") + " labels", event: () => this.layoutDoc.hideLabels = !this.layoutDoc.hideLabels, icon: "expand-arrows-alt" })
-        funcs.push({ description: (this.layoutDoc.playOnClick ? "Don't play" : "Play") + " onClick", event: () => this.layoutDoc.playOnClick = !this.layoutDoc.playOnClick, icon: "expand-arrows-alt" })
+        funcs.push({ description: (this.layoutDoc.hideMarkers ? "Don't hide" : "Hide") + " markers", event: () => this.layoutDoc.hideMarkers = !this.layoutDoc.hideMarkers, icon: "expand-arrows-alt" });
+        funcs.push({ description: (this.layoutDoc.hideLabels ? "Don't hide" : "Hide") + " labels", event: () => this.layoutDoc.hideLabels = !this.layoutDoc.hideLabels, icon: "expand-arrows-alt" });
+        funcs.push({ description: (this.layoutDoc.playOnClick ? "Don't play" : "Play") + " onClick", event: () => this.layoutDoc.playOnClick = !this.layoutDoc.playOnClick, icon: "expand-arrows-alt" });
         ContextMenu.Instance?.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
     }
 
@@ -421,12 +438,14 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         return false;
     }
 
+    // Probably need a better way to format
     isOverlap = (m: any, i: number) => {
         console.log("called");
         let counter = 0;
 
-        if (i == 0) {
+        if (this._first) {
             this._markers = [];
+            this._first = false;
         }
         for (let i = 0; i < this._markers.length; i++) {
             if ((m.audioEnd > this._markers[i].audioStart && m.audioStart < this._markers[i].audioEnd)) {
@@ -508,9 +527,14 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         }
     }
 
+    reset = () => {
+        this._first = true;
+    }
+
     render() {
         //trace();
         const interactive = this.active() ? "-interactive" : "";
+        this.reset();
         return <div className={`audiobox-container`} onContextMenu={this.specificContextMenu} onClick={!this.path ? this.recordClick : undefined}>
             {!this.path ?
                 <div className="audiobox-buttons">
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 6b6fc5da2..b1d9be73b 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1295,6 +1295,30 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         }
         e.stopPropagation();
         if (e.key === "Tab" || e.key === "Enter") {
+            // console.log(this._recording);
+            // if (this._editorView) {
+            //     const state = this._editorView.state;
+            //     const now = Date.now();
+            //     let mark = schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(now / 1000) });
+            //     if (!this._break && state.selection.to !== state.selection.from) {
+            //         for (let i = state.selection.from; i <= state.selection.to; i++) {
+            //             const pos = state.doc.resolve(i);
+            //             const um = Array.from(pos.marks()).find(m => m.type === schema.marks.user_mark);
+            //             if (um) {
+            //                 mark = um;
+            //                 break;
+            //             }
+            //         }
+            //     }
+            //     const recordingStart = DateCast(this.props.Document.recordingStart).date.getTime();
+            //     this._break = false;
+            //     let value = "" + (mark.attrs.modified * 1000 - recordingStart) / 1000;
+            //     //let value = "[0:02]";
+            //     const from = state.selection.from;
+            //     const inserted = state.tr.insertText(value).addMark(from, from + value.length + 1, mark);
+
+            //     this._editorView.dispatch(inserted.setSelection(TextSelection.create(inserted.doc, from, from + value.length + 1)));
+            // }
             e.preventDefault();
         }
         if (e.key === " " || this._lastTimedMark?.attrs.userid !== Doc.CurrentUserEmail) {
-- 
cgit v1.2.3-70-g09d2


From a1950ec49c56f5f9e2612da7e60a1e2615209386 Mon Sep 17 00:00:00 2001
From: Andy Rickert <andrew_rickert@brown.edu>
Date: Fri, 31 Jul 2020 18:25:39 -0400
Subject: bugfix

---
 src/client/views/DocComponent.tsx                  |  2 +
 src/client/views/GlobalKeyHandler.ts               |  2 +
 src/client/views/collections/CollectionView.tsx    |  4 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx | 28 ++++-----
 src/client/views/search/SearchBox.tsx              | 69 ++++++++++++++++------
 5 files changed, 71 insertions(+), 34 deletions(-)

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

diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 9b9a28f0f..106250af4 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -146,6 +146,8 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
                     added.map(doc => doc.context = this.props.Document);
                     targetDataDoc[this.annotationKey] = new List<Doc>([...docList, ...added]);
                     targetDataDoc[this.annotationKey + "-lastModified"] = new DateField(new Date(Date.now()));
+                    targetDataDoc["lastModified"] = new DateField(new Date(Date.now()));
+
                 }
             }
             return true;
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index c85849adb..2e5c018ba 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -307,6 +307,8 @@ export default class KeyManager {
                             undoBatch(() => {
                                 targetDataDoc[fieldKey] = new List<Doc>([...docList, ...added]);
                                 targetDataDoc[fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+                                targetDataDoc["lastModified"] = new DateField(new Date(Date.now()));
+
                             })();
                         }
                     }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 0178cc2e9..f9dc666d6 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -159,6 +159,8 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 added.map(add => Doc.AddDocToList(Cast(Doc.UserDoc().myCatalog, Doc, null), "data", add));
                 targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]);
                 targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+                targetDataDoc["lastModified"] = new DateField(new Date(Date.now()));
+
             }
         }
         return true;
@@ -554,7 +556,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
         return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
             style={{ pointerEvents: this.props.Document.isBackground ? "none" : undefined, boxShadow }}>
             {this.showIsTagged()}
-            <div className="collectionView-facetCont" style={{ display: this.props.PanelPosition==="absolute"? "flex" : "", justifyContent: this.props.PanelPosition==="absolute"? "center" : "", width: `calc(100% - ${this.facetWidth()}px)` }}>
+            <div className="collectionView-facetCont" style={{ display: this.props.PanelPosition === "absolute" ? "flex" : "", justifyContent: this.props.PanelPosition === "absolute" ? "center" : "", width: `calc(100% - ${this.facetWidth()}px)` }}>
                 {this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
             </div>
             {this.lightbox(DocListCast(this.props.Document[this.props.fieldKey]).filter(d => d.type === DocumentType.IMG).map(d =>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 11f25a208..71ba51039 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -228,7 +228,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             if (!this.dataDoc[AclSym]) {
                 if (!this._applyingChange && json.replace(/"selection":.*/, "") !== curProto?.Data.replace(/"selection":.*/, "")) {
                     this._applyingChange = true;
-                    (curText !== Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text) && (this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())));
+                    (curText !== Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text) && (this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()))) && (this.dataDoc["lastModified"] = new DateField(new Date(Date.now())));
                     if ((!curTemp && !curProto) || curText || curLayout?.Data.includes("dash")) { // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
                         if (json !== curLayout?.Data) {
                             !curText && tx.storedMarks?.map(m => m.type.name === "pFontSize" && (Doc.UserDoc().fontSize = this.layoutDoc._fontSize = m.attrs.fontSize));
@@ -280,7 +280,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             this._editorView.dispatch(tr.addMark(flattened[lastSel].from, flattened[lastSel].to, link));
         }
     }
-    public highlightSearchTerms = (terms: string[])=> {
+    public highlightSearchTerms = (terms: string[]) => {
         if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
 
             const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
@@ -291,30 +291,30 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             const flattened: TextSelection[] = [];
             res.map(r => r.map(h => flattened.push(h)));
 
-            
+
             const lastSel = Math.min(flattened.length - 1, this._searchIndex);
             flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark));
             this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
             this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
-            
+
             console.log(this._searchIndex, length);
-            if (this._searchIndex>1){
-                this._searchIndex+=-2;
+            if (this._searchIndex > 1) {
+                this._searchIndex += -2;
             }
-            else if (this._searchIndex===1){
-                this._searchIndex=length-1;
+            else if (this._searchIndex === 1) {
+                this._searchIndex = length - 1;
             }
-            else if (this._searchIndex===0 && length!==1){
-                this._searchIndex=length-2;
+            else if (this._searchIndex === 0 && length !== 1) {
+                this._searchIndex = length - 2;
             }
             let index = this._searchIndex;
 
             Doc.GetProto(this.dataDoc).searchIndex = index;
-            Doc.GetProto(this.dataDoc).length=length;
+            Doc.GetProto(this.dataDoc).length = length;
         }
     }
 
-    public highlightSearchTerms2 = (terms: string[])=> {
+    public highlightSearchTerms2 = (terms: string[]) => {
         if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
 
             const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
@@ -323,7 +323,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             let length = res[0].length;
             let tr = this._editorView.state.tr;
             const flattened: TextSelection[] = [];
-            res.map(r => r.map(h => flattened.push(h)));       
+            res.map(r => r.map(h => flattened.push(h)));
             const lastSel = Math.min(flattened.length - 1, this._searchIndex);
             flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark));
             this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
@@ -331,7 +331,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             let index = this._searchIndex;
 
             Doc.GetProto(this.dataDoc).searchIndex = index;
-            Doc.GetProto(this.dataDoc).length=length;
+            Doc.GetProto(this.dataDoc).length = length;
         }
     }
 
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index b17751d44..005f7d1af 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -40,6 +40,7 @@ import * as _ from "lodash";
 import { checkIfStateModificationsAreAllowed } from 'mobx/lib/internal';
 import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
 import { indexOf } from 'lodash';
+import { protocol } from 'socket.io-client';
 
 
 library.add(faTimes);
@@ -379,22 +380,42 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             let docs = DocListCast(selectedCollection.dataDoc[Doc.LayoutFieldKey(selectedCollection.dataDoc)]);
             let found: [Doc, string[], string[]][] = [];
             let docsforFilter: Doc[] = []
-            docs.forEach((d) => {
-                let hlights: string[] = [];
-                const protos = Doc.GetAllPrototypes(d);
-                let proto = protos[protos.length - 2];
-                Object.keys(proto).forEach(key => {
-                    if (StrCast(d[key]).includes(query)) {
-                        console.log(key, d[key]);
-                        hlights.push(key);
+            let newarray: Doc[] = [];
+
+            while (docs.length > 0) {
+                console.log("iteration");
+                newarray = [];
+                docs.forEach((d) => {
+                    console.log(d);
+                    if (d.data != undefined) {
+                        let newdocs = DocListCast(d.data);
+                        newdocs.forEach((newdoc) => {
+                            console.log(newdoc);
+                            newarray.push(newdoc);
+
+                        });
                     }
+
+
+                    let hlights: string[] = [];
+
+                    const protos = Doc.GetAllPrototypes(d);
+                    let proto = protos[protos.length - 1];
+                    protos.forEach(proto => {
+                        Object.keys(proto).forEach(key => {
+                            // console.log(key, d[key]);
+                            if (StrCast(d[key]).includes(query) && !hlights.includes(key)) {
+                                hlights.push(key);
+                            }
+                        })
+                    });
+                    if (hlights.length > 0) {
+                        found.push([d, hlights, []]);
+                        docsforFilter.push(d);
+                    };
                 });
-                if (hlights.length > 0) {
-                    found.push([d, hlights, []]);
-                    docsforFilter.push(d);
-                };
-            });
-            console.log(found);
+                docs = newarray;
+            }
             this._results = found;
             this.docsforfilter = docsforFilter;
             if (this.filter === true) {
@@ -408,6 +429,20 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
 
     }
 
+
+    documentKeys(doc: Doc) {
+        const keys: { [key: string]: boolean } = {};
+        // bcz: ugh.  this is untracked since otherwise a large collection of documents will blast the server for all their fields.
+        //  then as each document's fields come back, we update the documents _proxies.  Each time we do this, the whole schema will be
+        //  invalidated and re-rendered.   This workaround will inquire all of the document fields before the options button is clicked.
+        //  then by the time the options button is clicked, all of the fields should be in place.  If a new field is added while this menu
+        //  is displayed (unlikely) it won't show up until something else changes.
+        //TODO Types
+        Doc.GetAllPrototypes(doc).map
+            (proto => Object.keys(proto).forEach(key => keys[key] = false));
+        return Array.from(Object.keys(keys));
+    }
+
     applyBasicFieldFilters(query: string) {
         let finalQuery = "";
 
@@ -669,7 +704,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         const endIndex = 30;
         this._endIndex = endIndex === -1 ? 12 : endIndex;
         this._endIndex = 30;
-        let headers = new Set<string>(["title", "author", "creationDate"]);
+        let headers = new Set<string>(["title", "author", "lastModified"]);
         if ((this._numTotalResults === 0 || this._results.length === 0) && this._openNoResults) {
             if (this.noresults === "") {
                 this.noresults = "No search results :(";
@@ -734,12 +769,8 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                             if (i < this._visibleDocuments.length) {
                                 this._visibleDocuments[i] = result[0];
                                 this._isSearch[i] = "search";
-                                console.log("WHYYYY");
-                                console.log(result[0]);
-
                                 Doc.AddDocToList(this.dataDoc, this.props.fieldKey, result[0]);
                                 this.children++;
-
                             }
                         }
                     }
-- 
cgit v1.2.3-70-g09d2


From 8303cd6389fe9e3c861d7b429bb4e32d3417a895 Mon Sep 17 00:00:00 2001
From: Geireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>
Date: Mon, 3 Aug 2020 02:58:31 +0800
Subject: Merge remote-tracking branch 'origin/menu_restructure' into
 presentation_updates

---
 package.json                                       |   6 +-
 src/Utils.ts                                       |   4 +-
 src/client/documents/DocumentTypes.ts              |   1 +
 src/client/documents/Documents.ts                  |  12 +
 src/client/util/CurrentUserUtils.ts                | 116 ++-
 src/client/util/GroupMemberView.scss               |   2 +-
 src/client/util/SelectionManager.ts                |   3 +
 src/client/util/SharingManager.tsx                 |   6 +-
 src/client/views/ContextMenuItem.tsx               |   4 +-
 src/client/views/DocumentButtonBar.tsx             |   8 +-
 src/client/views/DocumentDecorations.tsx           |  19 +-
 src/client/views/EditableView.tsx                  |   2 +-
 src/client/views/MainView.scss                     | 135 +++-
 src/client/views/MainView.tsx                      | 393 ++++++----
 src/client/views/PreviewCursor.tsx                 |   6 +-
 src/client/views/PropertiesButtons.scss            | 119 +++
 src/client/views/PropertiesButtons.tsx             | 598 ++++++++++++++
 .../views/collections/CollectionDockingView.scss   |  16 +-
 .../views/collections/CollectionDockingView.tsx    |  20 +-
 src/client/views/collections/CollectionMenu.tsx    |  79 +-
 .../views/collections/CollectionSchemaView.tsx     |   2 +-
 .../views/collections/CollectionStackingView.tsx   |   1 +
 .../CollectionStackingViewFieldColumn.tsx          |   2 +-
 src/client/views/collections/CollectionSubView.tsx |   2 +-
 .../views/collections/CollectionTreeView.tsx       |   7 +-
 src/client/views/collections/CollectionView.scss   |   1 +
 src/client/views/collections/CollectionView.tsx    |  11 +-
 .../views/collections/ParentDocumentSelector.tsx   |   6 +-
 src/client/views/collections/SchemaTable.tsx       |   8 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  12 +-
 .../collectionFreeForm/FormatShapePane.tsx         |  27 +-
 .../collectionFreeForm/PropertiesView.scss         | 620 +++++++++++++++
 .../collectionFreeForm/PropertiesView.tsx          | 858 +++++++++++++++++++++
 src/client/views/linking/LinkMenuItem.tsx          |   3 +-
 .../views/nodes/ContentFittingDocumentView.tsx     |   3 +
 src/client/views/nodes/DocumentContentsView.tsx    |   3 +-
 src/client/views/nodes/DocumentLinksButton.tsx     |   5 +-
 src/client/views/nodes/DocumentView.tsx            |  62 +-
 src/client/views/nodes/FieldView.tsx               |   1 +
 src/client/views/nodes/FontIconBox.scss            |   2 +-
 src/client/views/nodes/MenuIconBox.scss            |  49 ++
 src/client/views/nodes/MenuIconBox.tsx             |  33 +
 src/client/views/nodes/PresBox.tsx                 |  10 +-
 .../views/nodes/formattedText/DashFieldView.tsx    |   2 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |   4 +-
 .../views/nodes/formattedText/RichTextMenu.tsx     |  41 +-
 src/client/views/nodes/formattedText/nodes_rts.ts  |   8 +-
 src/fields/Doc.ts                                  |   6 +-
 src/server/ActionUtilities.ts                      |  10 +-
 src/server/ApiManagers/UtilManager.ts              |   1 -
 src/server/DashUploadUtils.ts                      |  27 +-
 src/server/GarbageCollector.ts                     |   6 +-
 src/server/MemoryDatabase.ts                       |   5 +-
 src/server/Message.ts                              |   2 +-
 src/server/ProcessFactory.ts                       |   6 +-
 src/server/Recommender.ts                          | 133 ----
 src/server/RouteManager.ts                         |   8 +-
 src/server/Search.ts                               |   2 +-
 src/server/database.ts                             |   8 +-
 src/server/downsize.ts                             |   2 +-
 src/server/index.ts                                |  34 +-
 src/server/server_Initialization.ts                |  38 +-
 src/server/websocket.ts                            |  27 +-
 63 files changed, 3126 insertions(+), 521 deletions(-)
 create mode 100644 src/client/views/PropertiesButtons.scss
 create mode 100644 src/client/views/PropertiesButtons.tsx
 create mode 100644 src/client/views/collections/collectionFreeForm/PropertiesView.scss
 create mode 100644 src/client/views/collections/collectionFreeForm/PropertiesView.tsx
 create mode 100644 src/client/views/nodes/MenuIconBox.scss
 create mode 100644 src/client/views/nodes/MenuIconBox.tsx
 delete mode 100644 src/server/Recommender.ts

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

diff --git a/package.json b/package.json
index 11af6b2c6..420765e7c 100644
--- a/package.json
+++ b/package.json
@@ -11,8 +11,8 @@
     },
     "scripts": {
         "start-release": "cross-env RELEASE=true NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts",
-        "start": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev --transpile-only -- src/server/index.ts",
-        "oldstart": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts",
+        "start": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev --debug --transpile-only  -- src/server/index.ts",
+        "oldstart": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev --debug -- src/server/index.ts",
         "debug": "cross-env NODE_OPTIONS=--max_old_space_size=8192 ts-node-dev --transpile-only --inspect -- src/server/index.ts",
         "build": "cross-env NODE_OPTIONS=--max_old_space_size=8192 webpack --env production",
         "test": "mocha -r ts-node/register test/**/*.ts",
@@ -260,4 +260,4 @@
         "xoauth2": "^1.2.0",
         "xregexp": "^4.3.0"
     }
-}
+}
\ No newline at end of file
diff --git a/src/Utils.ts b/src/Utils.ts
index a01a94134..0b057dc23 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -1,8 +1,8 @@
 import v4 = require('uuid/v4');
 import v5 = require("uuid/v5");
-import { Socket, Room } from 'socket.io';
-import { Message } from './server/Message';
 import { ColorState } from 'react-color';
+import { Socket } from 'socket.io';
+import { Message } from './server/Message';
 
 export namespace Utils {
     export let DRAG_THRESHOLD = 4;
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index 985fcce11..659f78970 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -13,6 +13,7 @@ export enum DocumentType {
     INK = "ink",        // ink stroke
     SCREENSHOT = "screenshot",  // view of a desktop application
     FONTICON = "fonticonbox",   // font icon
+    MENUICON = "menuiconbox",
     QUERY = "query",            // search query
     LABEL = "label",            // simple text label
     BUTTON = "button",          // onClick button
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 0da93aa7a..01cdb1eee 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -31,6 +31,7 @@ import { ColorBox } from "../views/nodes/ColorBox";
 import { ComparisonBox } from "../views/nodes/ComparisonBox";
 import { DocHolderBox } from "../views/nodes/DocHolderBox";
 import { FontIconBox } from "../views/nodes/FontIconBox";
+import { MenuIconBox } from "../views/nodes/MenuIconBox";
 import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox";
 import { ImageBox } from "../views/nodes/ImageBox";
 import { KeyValueBox } from "../views/nodes/KeyValueBox";
@@ -305,6 +306,13 @@ export namespace Docs {
                 layout: { view: FontIconBox, dataField: defaultDataKey },
                 options: { _width: 40, _height: 40, borderRounding: "100%" },
             }],
+            [DocumentType.MENUICON, {
+                layout: { view: MenuIconBox, dataField: defaultDataKey },
+            }],
+            // [DocumentType.RECOMMENDATION, {
+            //     layout: { view: RecommendationsBox, dataField: defaultDataKey },
+            //     options: { _width: 200, _height: 200 },
+            // }],
             [DocumentType.WEBCAM, {
                 layout: { view: DashWebRTCVideo, dataField: defaultDataKey }
             }],
@@ -791,6 +799,10 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.FONTICON), undefined, { hideLinkButton: true, ...(options || {}) });
         }
 
+        export function MenuIconDocument(options?: DocumentOptions) {
+            return InstanceFromProto(Prototypes.get(DocumentType.MENUICON), undefined, { hideLinkButton: true, ...(options || {}) });
+        }
+
         export function PresElementBoxDocument(options?: DocumentOptions) {
             return InstanceFromProto(Prototypes.get(DocumentType.PRESELEMENT), undefined, { ...(options || {}) });
         }
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 6d752832a..b37c91c56 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -38,6 +38,16 @@ export class CurrentUserUtils {
     @observable public static GuestWorkspace: Doc | undefined;
     @observable public static GuestMobile: Doc | undefined;
 
+    @observable public static toolsBtn: any | undefined;
+    @observable public static libraryBtn: any | undefined;
+    @observable public static searchBtn: any | undefined;
+
+    @observable public static toolsStack: any | undefined;
+    @observable public static workspaceStack: any | undefined;
+    @observable public static catalogStack: any | undefined;
+    @observable public static closedStack: any | undefined;
+    @observable public static searchStack: any | undefined;
+
     // sets up the default User Templates - slideView, queryView, descriptionView
     static setupUserTemplateButtons(doc: Doc) {
         if (doc["template-button-query"] === undefined) {
@@ -492,6 +502,46 @@ export class CurrentUserUtils {
         return doc.myItemCreators as Doc;
     }
 
+    static menuBtnDescriptions(): {
+        title: string, icon: string, click: string,
+    }[] {
+        return [
+            { title: "Workspace", icon: "desktop", click: 'scriptContext.selectMenu("Workspace")' },
+            { title: "Catalog", icon: "file", click: 'scriptContext.selectMenu("Catalog")' },
+            { title: "Archive", icon: "archive", click: 'scriptContext.selectMenu("Archive")' },
+            { title: "Import", icon: "upload", click: 'scriptContext.selectMenu("Import")' },
+            { title: "Sharing", icon: "users", click: 'scriptContext.selectMenu("Sharing")' },
+            { title: "Tools", icon: "wrench", click: 'scriptContext.selectMenu("Tools")' },
+            { title: "Help", icon: "question-circle", click: 'scriptContext.selectMenu("Help")' },
+            { title: "Settings", icon: "cog", click: 'scriptContext.selectMenu("Settings")' },
+        ];
+    }
+
+    static setupMenuPanel(doc: Doc) {
+        if (doc.menuStack === undefined) {
+            const buttons = CurrentUserUtils.menuBtnDescriptions();
+            const menuBtns = buttons.map(({ title, icon, click }) => Docs.Create.MenuIconDocument({
+                icon,
+                title,
+                _backgroundColor: "black",
+                stayInCollection: true,
+                _width: 60,
+                _height: 60,
+                onClick: ScriptField.MakeScript(click, { scriptContext: "any" }),
+            }));
+
+            doc.menuStack = new PrefetchProxy(Docs.Create.StackingDocument(menuBtns, {
+                title: "menuItemPanel",
+                _backgroundColor: "black",
+                _gridGap: 0,
+                _yMargin: 0,
+                _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, lockedPosition: true, _chromeStatus: "disabled",
+            }));
+        }
+        return doc.menuStack as Doc;
+    }
+
+
     // Sets up mobile menu if it is undefined creates a new one, otherwise returns existing menu
     static setupActiveMobileMenu(doc: Doc) {
         if (doc.activeMobileMenu === undefined) {
@@ -601,6 +651,8 @@ export class CurrentUserUtils {
         const creatorBtns = await CurrentUserUtils.setupCreatorButtons(doc);
         const templateBtns = CurrentUserUtils.setupUserTemplateButtons(doc);
 
+        doc["tabs-button-tools"] = undefined;
+
         if (doc.myCreators === undefined) {
             doc.myCreators = new PrefetchProxy(Docs.Create.StackingDocument([creatorBtns, templateBtns], {
                 title: "all Creators", _yMargin: 0, _autoHeight: true, _xMargin: 0,
@@ -617,8 +669,11 @@ export class CurrentUserUtils {
 
         if (doc["tabs-button-tools"] === undefined) {
             const toolsStack = new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker as Doc], {
-                _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true
+                _width: 500, lockedPosition: true, _chromeStatus: "disabled", hideFilterView: true, title: "tools stack", forceActive: true
             })) as any as Doc;
+
+            CurrentUserUtils.toolsStack = toolsStack;
+
             doc["tabs-button-tools"] = new PrefetchProxy(Docs.Create.ButtonDocument({
                 _width: 35, _height: 25, title: "Tools", _fontSize: "10pt",
                 letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
@@ -627,41 +682,63 @@ export class CurrentUserUtils {
                 dragFactory: toolsStack,
                 removeDropProperties: new List<string>(["lockedPosition"]),
                 stayInCollection: true,
+                hideFilterView: true,
                 targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc,
                 onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"),
             }));
         }
-        (doc["tabs-button-tools"] as Doc).sourcePanel; // prefetch sourcePanel
-        return doc["tabs-button-tools"] as Doc;
+        (doc["tabs-button-tools"] as any as Doc).sourcePanel; // prefetch sourcePanel
+
+        return doc["tabs-button-tools"] as any as Doc;
     }
 
     static setupWorkspaces(doc: Doc) {
         // setup workspaces library item
+        doc.myWorkspaces === undefined;
         if (doc.myWorkspaces === undefined) {
             doc.myWorkspaces = new PrefetchProxy(Docs.Create.TreeDocument([], {
-                title: "WORKSPACES", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true,
+                title: "WORKSPACES", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true, treeViewOpen: true,
             }));
         }
         const newWorkspace = ScriptField.MakeScript(`createNewWorkspace()`);
         (doc.myWorkspaces as Doc).contextMenuScripts = new List<ScriptField>([newWorkspace!]);
         (doc.myWorkspaces as Doc).contextMenuLabels = new List<string>(["Create New Workspace"]);
 
+        const workspaces = doc.myWorkspaces as Doc;
+
+        CurrentUserUtils.workspaceStack = new PrefetchProxy(Docs.Create.TreeDocument([workspaces], {
+            title: " ", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
+            treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, treeViewOpen: true,
+            lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
+        })) as any as Doc;
+
         return doc.myWorkspaces as Doc;
     }
     static setupCatalog(doc: Doc) {
+        doc.myCatalog === undefined;
         if (doc.myCatalog === undefined) {
             doc.myCatalog = new PrefetchProxy(Docs.Create.SchemaDocument([], [], {
                 title: "CATALOG", _height: 1000, _fitWidth: true, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: false,
-                childDropAction: "alias", targetDropAction: "same", stayInCollection: true,
+                childDropAction: "alias", targetDropAction: "same", stayInCollection: true, treeViewOpen: true,
             }));
         }
+
+        const catalog = doc.myCatalog as Doc;
+
+        CurrentUserUtils.catalogStack = new PrefetchProxy(Docs.Create.TreeDocument([catalog], {
+            title: " ", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
+            treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, treeViewOpen: true,
+            lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
+        })) as any as Doc;
+
         return doc.myCatalog as Doc;
     }
     static setupRecentlyClosed(doc: Doc) {
         // setup Recently Closed library item
+        doc.myRecentlyClosed === undefined;
         if (doc.myRecentlyClosed === undefined) {
             doc.myRecentlyClosed = new PrefetchProxy(Docs.Create.TreeDocument([], {
-                title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, stayInCollection: true,
+                title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: false, treeViewOpen: true, stayInCollection: true,
             }));
         }
         // this is equivalent to using PrefetchProxies to make sure the recentlyClosed doc is ready
@@ -670,6 +747,14 @@ export class CurrentUserUtils {
         (doc.myRecentlyClosed as Doc).contextMenuScripts = new List<ScriptField>([clearAll!]);
         (doc.myRecentlyClosed as Doc).contextMenuLabels = new List<string>(["Clear All"]);
 
+        const recentlyClosed = doc.myRecentlyClosed as Doc;
+
+        CurrentUserUtils.closedStack = new PrefetchProxy(Docs.Create.TreeDocument([recentlyClosed], {
+            title: " ", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
+            treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, treeViewOpen: true,
+            lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
+        })) as any as Doc;
+
         return doc.myRecentlyClosed as Doc;
     }
     // setup the Library button which will display the library panel.  This panel includes a collection of workspaces, documents, and recently closed views
@@ -681,7 +766,7 @@ export class CurrentUserUtils {
         if (doc["tabs-button-library"] === undefined) {
             const libraryStack = new PrefetchProxy(Docs.Create.TreeDocument([workspaces, documents, recentlyClosed, doc], {
                 title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
-                treeViewTruncateTitleWidth: 150,
+                treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false,
                 lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
             })) as any as Doc;
             doc["tabs-button-library"] = new PrefetchProxy(Docs.Create.ButtonDocument({
@@ -701,6 +786,7 @@ export class CurrentUserUtils {
 
     // setup the Search button which will display the search panel.
     static setupSearchBtnPanel(doc: Doc, sidebarContainer: Doc) {
+        doc["tabs-button-search"] = undefined;
         if (doc["tabs-button-search"] === undefined) {
             doc["tabs-button-search"] = new PrefetchProxy(Docs.Create.ButtonDocument({
                 _width: 50, _height: 25, title: "Search", _fontSize: "10pt",
@@ -711,8 +797,9 @@ export class CurrentUserUtils {
                 lockedPosition: true,
                 onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel")
             }));
+            CurrentUserUtils.searchStack = new PrefetchProxy(Docs.Create.QueryDocument({ title: "search stack", })) as any as Doc;
         }
-        return doc["tabs-button-search"] as Doc;
+        return doc["tabs-button-search"] as any as Doc;
     }
 
     static setupSidebarContainer(doc: Doc) {
@@ -728,17 +815,17 @@ export class CurrentUserUtils {
     // setup the list of sidebar mode buttons which determine what is displayed in the sidebar
     static async setupSidebarButtons(doc: Doc) {
         const sidebarContainer = CurrentUserUtils.setupSidebarContainer(doc);
-        const toolsBtn = await CurrentUserUtils.setupToolsBtnPanel(doc, sidebarContainer);
-        const libraryBtn = CurrentUserUtils.setupLibraryPanel(doc, sidebarContainer);
-        const searchBtn = CurrentUserUtils.setupSearchBtnPanel(doc, sidebarContainer);
+        CurrentUserUtils.toolsBtn = await CurrentUserUtils.setupToolsBtnPanel(doc, sidebarContainer);
+        CurrentUserUtils.libraryBtn = CurrentUserUtils.setupLibraryPanel(doc, sidebarContainer);
+        CurrentUserUtils.searchBtn = CurrentUserUtils.setupSearchBtnPanel(doc, sidebarContainer);
 
         // Finally, setup the list of buttons to display in the sidebar
         if (doc["tabs-buttons"] === undefined) {
-            doc["tabs-buttons"] = new PrefetchProxy(Docs.Create.StackingDocument([libraryBtn, searchBtn, toolsBtn], {
+            doc["tabs-buttons"] = new PrefetchProxy(Docs.Create.StackingDocument([CurrentUserUtils.libraryBtn, CurrentUserUtils.searchBtn, CurrentUserUtils.toolsBtn], {
                 _width: 500, _height: 80, boxShadow: "0 0", _pivotField: "title", _columnsHideIfEmpty: true, ignoreClick: true, _chromeStatus: "view-mode",
                 title: "sidebar btn row stack", backgroundColor: "dimGray",
             }));
-            (toolsBtn.onClick as ScriptField).script.run({ this: toolsBtn });
+            (CurrentUserUtils.toolsBtn.onClick as ScriptField).script.run({ this: CurrentUserUtils.toolsBtn });
         }
     }
 
@@ -749,7 +836,7 @@ export class CurrentUserUtils {
     })) as any as Doc
 
     static ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({
-        ...opts, dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100
+        ...opts, dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40
     })) as any as Doc
 
     /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window
@@ -855,6 +942,7 @@ export class CurrentUserUtils {
         this.setupDocTemplates(doc); // sets up the template menu of templates
         this.setupRightSidebar(doc);  // sets up the right sidebar collection for mobile upload documents and sharing
         this.setupActiveMobileMenu(doc); // sets up the current mobile menu for Dash Mobile
+        this.setupMenuPanel(doc);
         this.setupOverlays(doc);  // documents in overlay layer
         this.setupDockedButtons(doc);  // the bottom bar of font icons
         this.setupDefaultPresentation(doc); // presentation that's initially triggered
diff --git a/src/client/util/GroupMemberView.scss b/src/client/util/GroupMemberView.scss
index 2fc27ed03..2eb164988 100644
--- a/src/client/util/GroupMemberView.scss
+++ b/src/client/util/GroupMemberView.scss
@@ -44,7 +44,7 @@
             background: none;
 
             &:hover {
-                text-overflow: visible;
+                text-overflow: unset;
                 overflow-x: auto;
             }
         }
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 20d881961..05ba00331 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -12,6 +12,7 @@ export namespace SelectionManager {
 
         @observable IsDragging: boolean = false;
         SelectedDocuments: ObservableMap<DocumentView, boolean> = new ObservableMap();
+
         @action
         SelectDoc(docView: DocumentView, ctrlPressed: boolean): void {
 
@@ -32,6 +33,7 @@ export namespace SelectionManager {
         }
         @action
         DeselectDoc(docView: DocumentView): void {
+
             if (manager.SelectedDocuments.get(docView)) {
                 manager.SelectedDocuments.delete(docView);
                 docView.props.whenActiveChanged(false);
@@ -40,6 +42,7 @@ export namespace SelectionManager {
         }
         @action
         DeselectAll(): void {
+
             Array.from(manager.SelectedDocuments.keys()).map(dv => dv.props.whenActiveChanged(false));
             manager.SelectedDocuments.clear();
             Doc.UserDoc().activeSelection = new List<Doc>([]);
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 5896bdf92..000b3e46c 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -72,8 +72,6 @@ export default class SharingManager extends React.Component<{}> {
     @observable private showUserOptions: boolean = false; // whether to show individuals as options when sharing (in the react-select component)
     @observable private showGroupOptions: boolean = false; // // whether to show groups as options when sharing (in the react-select component)
 
-
-
     // private get linkVisible() {
     //     return this.sharingDoc ? this.sharingDoc[PublicKey] !== SharingPermissions.None : false;
     // }
@@ -148,7 +146,7 @@ export default class SharingManager extends React.Component<{}> {
         const members: string[] = JSON.parse(StrCast(group.members));
         const users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email));
 
-        const target = this.targetDoc!;
+        const target = targetDoc || this.targetDoc!;
         const ACL = `ACL-${StrCast(group.groupName)}`;
 
         target.author === Doc.CurrentUserEmail && distributeAcls(ACL, permission as SharingPermissions, target);
@@ -222,7 +220,7 @@ export default class SharingManager extends React.Component<{}> {
 
     setInternalSharing = (recipient: ValidatedUser, permission: string) => {
         const { user, notificationDoc } = recipient;
-        const target = this.targetDoc!;
+        const target = targetDoc || this.targetDoc!;
         const key = user.email.replace('.', '_');
         const ACL = `ACL-${key}`;
 
diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index 81432968d..7e233ec04 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -80,7 +80,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
     render() {
         if ("event" in this.props) {
             return (
-                <div className={"contextMenu-item" + (this.props.selected ? " contextMenu-itemSelected" : "")} onClick={this.handleEvent}>
+                <div className={"contextMenu-item" + (this.props.selected ? " contextMenu-itemSelected" : "")} onPointerDown={this.handleEvent}>
                     {this.props.icon ? (
                         <span className="icon-background">
                             <FontAwesomeIcon icon={this.props.icon} size="sm" />
@@ -95,7 +95,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
             const where = !this.overItem ? "" : this._overPosY < window.innerHeight / 3 ? "flex-start" : this._overPosY > window.innerHeight * 2 / 3 ? "flex-end" : "center";
             const marginTop = !this.overItem ? "" : this._overPosY < window.innerHeight / 3 ? "20px" : this._overPosY > window.innerHeight * 2 / 3 ? "-20px" : "";
             const submenu = !this.overItem ? (null) :
-                <div className="contextMenu-subMenu-cont" style={{ marginLeft: "25%", left: "0px", marginTop }}>
+                <div className="contextMenu-subMenu-cont" style={{ marginLeft: "90%", left: "0px", marginTop }}>
                     {this._items.map(prop => <ContextMenuItem {...prop} key={prop.description} closeMenu={this.props.closeMenu} />)}
                 </div>;
             if (!("noexpand" in this.props)) {
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 6b85616c2..23a3e1684 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -281,7 +281,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
             {DocumentLinksButton.StartLink ? <div className="documentButtonBar-button">
                 <DocumentLinksButton links={this.view0.allLinks} View={this.view0} AlwaysOn={true} InMenu={true} StartLink={false} />
             </div> : null}
-            <div className="documentButtonBar-button">
+            {/* <div className="documentButtonBar-button">
                 {this.templateButton}
             </div>
             <div className="documentButtonBar-button">
@@ -289,16 +289,16 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
             </div>
             <div className="documentButtonBar-button">
                 {this.contextButton}
-            </div>
+            </div> */}
             <div className="documentButtonBar-button">
                 {this.pinButton}
             </div>
-            <div className="documentButtonBar-button" style={{ display: !considerPush ? "none" : "" }}>
+            {/* <div className="documentButtonBar-button" style={{ display: !considerPush ? "none" : "" }}>
                 {this.considerGoogleDocsPush}
             </div>
             <div className="documentButtonBar-button" style={{ display: !considerPull ? "none" : "" }}>
                 {this.considerGoogleDocsPull}
-            </div>
+            </div> */}
         </div>;
     }
 }
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 7fc4a5c99..dd5303904 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,5 +1,5 @@
 import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faTextHeight, faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faShare, faStopCircle, faSyncAlt, faTag, faTimes, faAngleLeft, faAngleRight, faAngleDoubleLeft, faAngleDoubleRight, faPause } from '@fortawesome/free-solid-svg-icons';
+import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faTextHeight, faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faShare, faStopCircle, faSyncAlt, faTag, faTimes, faAngleLeft, faAngleRight, faAngleDoubleLeft, faAngleDoubleRight, faPause, faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { action, computed, observable, reaction, runInAction, get } from "mobx";
 import { observer } from "mobx-react";
@@ -47,6 +47,7 @@ library.add(faAngleDoubleRight);
 library.add(faAngleLeft);
 library.add(faAngleRight);
 library.add(faPause);
+library.add(faExternalLinkAlt);
 
 @observer
 export class DocumentDecorations extends React.Component<{}, { value: string }> {
@@ -533,12 +534,12 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 const ink = Cast(doc.data, InkField)?.inkData;
                 if (ink) {
                     const newPoints: { X: number, Y: number }[] = [];
-                    for (var i = 0; i < ink.length; i++) {
+                    ink.forEach(i => {
                         // (new x — oldx) + (oldxpoint * newWidt)/oldWidth 
-                        const newX = (doc.x - this._inkDocs[index].x) + (ink[i].X * doc._width) / this._inkDocs[index].width;
-                        const newY = (doc.y - this._inkDocs[index].y) + (ink[i].Y * doc._height) / this._inkDocs[index].height;
+                        const newX = ((doc.x || 0) - this._inkDocs[index].x) + (i.X * (doc._width || 0)) / this._inkDocs[index].width;
+                        const newY = ((doc.y || 0) - this._inkDocs[index].y) + (i.Y * (doc._height || 0)) / this._inkDocs[index].height;
                         newPoints.push({ X: newX, Y: newY });
-                    }
+                    });
                     doc.data = new InkField(newPoints);
 
                 }
@@ -617,9 +618,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 </div>}
             </> :
             <>
-                {minimal ? (null) : <Tooltip title={<><div className="dash-tooltip">Show context menu</div></>} placement="top"><div className="documentDecorations-contextMenu" key="menu" onPointerDown={this.onSettingsDown}>
-                    <FontAwesomeIcon size="lg" icon="cog" />
-                </div></Tooltip>}
+                {/* {minimal ? (null) : <Tooltip title={<><div className="dash-tooltip">Show context menu</div></>} placement="top"><div className="documentDecorations-contextMenu" key="menu" onPointerDown={this.onSettingsDown}>
+                    <FontAwesomeIcon size="lg" icon="bars" />
+                </div></Tooltip>} */}
                 <div className="documentDecorations-title" key="title" onPointerDown={this.onTitleDown} >
                     <span style={{ width: "100%", display: "inline-block", cursor: "move" }}>{`${this.selectionTitle}`}</span>
                 </div>
@@ -666,7 +667,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                                 {"_"}
                             </div></Tooltip>}
                     <Tooltip title={<><div className="dash-tooltip">Open Document In Tab</div></>} placement="top"><div className="documentDecorations-openInTab" onPointerDown={this.onMaximizeDown}>
-                        {SelectionManager.SelectedDocuments().length === 1 ? DocumentDecorations.DocumentIcon(StrCast(seldoc.props.Document.layout, "...")) : "..."}
+                        {SelectionManager.SelectedDocuments().length === 1 ? <FontAwesomeIcon icon="external-link-alt" className="documentView-minimizedIcon" /> : "..."}
                     </div></Tooltip>
                     <div id="documentDecorations-rotation" className="documentDecorations-rotation"
                         onPointerDown={this.onRotateDown}> ⟲ </div>
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index c7b149842..f9d060681 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -191,7 +191,7 @@ export class EditableView extends React.Component<EditableProps> {
             return (this.props.contents instanceof ObjectField ? (null) :
                 <div className={`editableView-container-editing${this.props.oneLine ? "-oneLine" : ""}`}
                     ref={this._ref}
-                    style={{ display: this.props.display, minHeight: "20px", height: `${this.props.height ? this.props.height : "auto"}`, maxHeight: `${this.props.maxHeight}` }}
+                    style={{ display: this.props.display, minHeight: "17px", whiteSpace: "nowrap", height: `${this.props.height ? this.props.height : "auto"}`, maxHeight: `${this.props.maxHeight}` }}
                     onClick={this.onClick} placeholder={this.props.placeholder}>
                     <span style={{
                         fontStyle: this.props.fontStyle, fontSize: this.props.fontSize,
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index e1ddbc533..054a409df 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -102,6 +102,44 @@
     user-select: none;
 }
 
+.mainView-propertiesDragger {
+    background-color: rgb(140, 139, 139);
+    height: 55px;
+    width: 15.5px;
+    position: absolute;
+    top: 55%;
+    border: 1px black solid;
+    border-radius: 0;
+    border-top-left-radius: 10px;
+    border-bottom-left-radius: 10px;
+    border-right: unset;
+    z-index: 2;
+
+    .mainView-propertiesDragger-icon {
+        width: 10px;
+        height: 10px;
+        float: left;
+        margin-left: 3px;
+        padding-top: 19px;
+    }
+
+    &:hover {
+        cursor: grab;
+    }
+}
+
+.mainiView-propertiesView {
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+    position: absolute;
+    right: 0;
+    top: 0;
+    border-left: solid 1px;
+    z-index: 100000;
+    cursor: auto;
+}
+
 .mainView-flyoutContainer {
     display: flex;
     flex-direction: column;
@@ -114,6 +152,75 @@
     }
 }
 
+.mainView-menuPanel {
+
+    width: 60px;
+    background-color: black;
+    height: 100%;
+    //overflow-y: scroll;
+    //overflow-x: hidden;
+
+
+    .mainView-menuPanel-button {
+        padding: 7px;
+        padding-left: 7px;
+        width: 100%;
+
+        .mainView-menuPanel-button-wrap {
+            width: 45px;
+            /* padding: 5px; */
+            touch-action: none;
+            background: black;
+            transform-origin: top left;
+            /* margin-bottom: 5px; */
+            margin-top: 5px;
+            margin-right: 25px;
+            border-radius: 8px;
+
+            &:hover {
+                background: rgb(61, 61, 61);
+                cursor: pointer;
+            }
+        }
+    }
+
+    .mainView-menuPanel-button-label {
+        color: white;
+        margin-left: px;
+        margin-right: 4px;
+        border-radius: 8px;
+        width: 42px;
+        position: relative;
+        text-align: center;
+        font-size: 8px;
+        margin-top: 1px;
+        letter-spacing: normal;
+        padding: 3px;
+        background-color: inherit;
+    }
+
+    .mainView-menuPanel-button-icon {
+        width: auto;
+        height: 35px;
+        padding: 5px;
+    }
+
+    svg {
+        width: 95% !important;
+        height: 95%;
+    }
+}
+
+.mainView-searchPanel {
+    width: 100%;
+    height: 33px;
+    background-color: black;
+    color: white;
+    text-align: center;
+    vertical-align: middle;
+    padding-top: 6px;
+}
+
 .mainView-mainDiv {
     width: 100%;
     height: 100%;
@@ -162,26 +269,44 @@
     display: flex;
     flex-direction: column;
     z-index: 2;
+
+    .mainView-libraryFlyout-close {
+        right: 6;
+        top: 5;
+        position: absolute;
+        margin-right: 6px;
+        z-index: 10;
+        margin-bottom: 10;
+    }
 }
 
 .mainView-expandFlyoutButton {
     position: absolute;
-    top: 100px;
-    right: 30px;
+    top: 120px;
+    right: 55px;
     cursor: pointer;
 }
 
 .mainView-libraryHandle {
-    width: 20px;
+    width: 28px;
     left: calc(100% - 10px);
-    height: 40px;
+    height: 55px;
     top: 50%;
     border: 1px solid black;
-    border-radius: 5px;
+    border-radius: 8px;
     position: absolute;
     z-index: 2;
     touch-action: none;
     cursor: ew-resize;
+
+    .mainView-libraryHandle-icon {
+        width: 10px;
+        height: 10px;
+        float: right;
+        margin-right: 3px;
+        padding-top: 19px;
+    }
+
 }
 
 .mainView-workspace {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 58478ce92..54b57a887 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,7 +1,6 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faHireAHelper, faBuffer } from '@fortawesome/free-brands-svg-icons';
 import * as fa from '@fortawesome/free-solid-svg-icons';
-import { ANTIMODEMENU_HEIGHT } from './globalCssVariables.scss';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
@@ -12,51 +11,55 @@ import { Doc, DocListCast, Field, Opt } from '../../fields/Doc';
 import { Id } from '../../fields/FieldSymbols';
 import { List } from '../../fields/List';
 import { listSpec } from '../../fields/Schema';
+import { ScriptField } from '../../fields/ScriptField';
 import { BoolCast, Cast, FieldValue, StrCast } from '../../fields/Types';
 import { TraceMobx } from '../../fields/util';
-import { CurrentUserUtils } from '../util/CurrentUserUtils';
-import { emptyFunction, emptyPath, returnFalse, returnOne, returnZero, returnTrue, Utils, returnEmptyFilter } from '../../Utils';
+import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, Utils } from '../../Utils';
 import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
+import HypothesisAuthenticationManager from '../apis/HypothesisAuthenticationManager';
 import { DocServer } from '../DocServer';
 import { Docs, DocumentOptions } from '../documents/Documents';
 import { DocumentType } from '../documents/DocumentTypes';
+import { CurrentUserUtils } from '../util/CurrentUserUtils';
+import { DocumentManager } from '../util/DocumentManager';
+import GroupManager from '../util/GroupManager';
 import { HistoryUtil } from '../util/History';
-import RichTextMenu from './nodes/formattedText/RichTextMenu';
 import { Scripting } from '../util/Scripting';
+import { SelectionManager } from '../util/SelectionManager';
 import SettingsManager from '../util/SettingsManager';
-import GroupManager from '../util/GroupManager';
 import SharingManager from '../util/SharingManager';
+import { SnappingManager } from '../util/SnappingManager';
 import { Transform } from '../util/Transform';
+import { TimelineMenu } from './animationtimeline/TimelineMenu';
 import { CollectionDockingView } from './collections/CollectionDockingView';
+import FormatShapePane from "./collections/collectionFreeForm/FormatShapePane";
 import MarqueeOptionsMenu from './collections/collectionFreeForm/MarqueeOptionsMenu';
+import { PropertiesView } from './collections/collectionFreeForm/PropertiesView';
 import { CollectionLinearView } from './collections/CollectionLinearView';
+import CollectionMenu from './collections/CollectionMenu';
 import { CollectionView, CollectionViewType } from './collections/CollectionView';
 import { ContextMenu } from './ContextMenu';
 import { DictationOverlay } from './DictationOverlay';
 import { DocumentDecorations } from './DocumentDecorations';
 import GestureOverlay from './GestureOverlay';
+import { ANTIMODEMENU_HEIGHT } from './globalCssVariables.scss';
 import KeyManager from './GlobalKeyHandler';
+import { LinkMenu } from './linking/LinkMenu';
 import "./MainView.scss";
 import { MainViewNotifs } from './MainViewNotifs';
 import { AudioBox } from './nodes/AudioBox';
+import { DocumentLinksButton } from './nodes/DocumentLinksButton';
 import { DocumentView } from './nodes/DocumentView';
+import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
+import RichTextMenu from './nodes/formattedText/RichTextMenu';
+import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup';
+import { LinkDocPreview } from './nodes/LinkDocPreview';
 import { RadialMenu } from './nodes/RadialMenu';
+import { TaskCompletionBox } from './nodes/TaskCompletedBox';
 import { OverlayView } from './OverlayView';
 import PDFMenu from './pdf/PDFMenu';
 import { PreviewCursor } from './PreviewCursor';
-import { ScriptField } from '../../fields/ScriptField';
-import { TimelineMenu } from './animationtimeline/TimelineMenu';
-import { SnappingManager } from '../util/SnappingManager';
-import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
-import { DocumentManager } from '../util/DocumentManager';
-import { DocumentLinksButton } from './nodes/DocumentLinksButton';
-import { LinkMenu } from './linking/LinkMenu';
-import { LinkDocPreview } from './nodes/LinkDocPreview';
-import { TaskCompletionBox } from './nodes/TaskCompletedBox';
-import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup';
-import FormatShapePane from "./collections/collectionFreeForm/FormatShapePane";
-import HypothesisAuthenticationManager from '../apis/HypothesisAuthenticationManager';
-import CollectionMenu from './collections/CollectionMenu';
+import { undoBatch } from '../util/UndoManager';
 
 @observer
 export class MainView extends React.Component {
@@ -69,8 +72,8 @@ export class MainView extends React.Component {
 
     @observable private _panelWidth: number = 0;
     @observable private _panelHeight: number = 0;
-    @observable private _flyoutTranslate: boolean = true;
-    @observable public flyoutWidth: number = 250;
+    @observable private _flyoutTranslate: boolean = false;
+    @observable public flyoutWidth: number = 0;
     private get darkScheme() { return BoolCast(Cast(this.userDoc?.activeWorkspace, Doc, null)?.darkScheme); }
 
     @computed private get userDoc() { return Doc.UserDoc(); }
@@ -78,7 +81,27 @@ export class MainView extends React.Component {
     @computed public get mainFreeform(): Opt<Doc> { return (docs => (docs && docs.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); }
     @computed public get sidebarButtonsDoc() { return Cast(this.userDoc["tabs-buttons"], Doc) as Doc; }
 
+    @observable public sidebarContent: any = this.userDoc?.["tabs-panelContainer"];
+    @observable public panelContent: string = "none";
+    @observable public showProperties: boolean = false;
     public isPointerDown = false;
+    @computed get selectedDocumentView() {
+        if (SelectionManager.SelectedDocuments().length) {
+            return SelectionManager.SelectedDocuments()[0];
+        } else { return undefined; }
+    }
+
+    @observable _propertiesWidth: number = 0;
+    propertiesWidth = () => Math.max(0, Math.min(this._panelWidth - 50, this._propertiesWidth));
+
+    @computed get propertiesIcon() {
+        if (this.propertiesWidth() < 10) {
+            return "chevron-left";
+        } else {
+            return "chevron-right";
+        }
+    }
+    @observable propertiesDownX: number | undefined;
 
     componentDidMount() {
         DocServer.setPlaygroundFields(["dataTransition", "_viewTransition", "_panX", "_panY", "_viewScale", "_viewType", "_chromeStatus"]); // can play with these fields on someone else's
@@ -148,7 +171,10 @@ export class MainView extends React.Component {
             fa.faEye, fa.faArrowsAlt, fa.faQuoteLeft, fa.faSortAmountDown, fa.faAlignLeft, fa.faAlignCenter, fa.faAlignRight, fa.faHeading, fa.faRulerCombined,
             fa.faFillDrip, fa.faLink, fa.faUnlink, fa.faBold, fa.faItalic, fa.faChevronLeft, fa.faUnderline, fa.faStrikethrough, fa.faSuperscript, fa.faSubscript,
             fa.faIndent, fa.faEyeDropper, fa.faPaintRoller, fa.faBars, fa.faBrush, fa.faShapes, fa.faEllipsisH, fa.faHandPaper, fa.faMap, fa.faUser, faHireAHelper,
-            fa.faBezierCurve, fa.faCircle, fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, fa.faAngleUp, fa.faAngleDown, fa.faPlayCircle, fa.faClock,
+            fa.faDesktop, fa.faTrashRestore, fa.faUsers, fa.faWrench, fa.faCog, fa.faMap, fa.faBellSlash, fa.faExpandAlt, fa.faArchive, fa.faBezierCurve, fa.faCircle,
+            fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, faBuffer, fa.faExpand, fa.faUndo, fa.faSlidersH);
+        //Pres trail icons (just for the sake of merging)
+        library.add(fa.faAngleUp, fa.faAngleDown, fa.faPlayCircle, fa.faClock,
             fa.faRocket, fa.faExchangeAlt, faBuffer);
         this.initEventListeners();
         this.initAuthenticationRouters();
@@ -211,7 +237,7 @@ export class MainView extends React.Component {
         const freeformOptions: DocumentOptions = {
             x: 0,
             y: 400,
-            _width: this._panelWidth * .7,
+            _width: this._panelWidth * .7 - this.propertiesWidth(),
             _height: this._panelHeight,
             title: "Collection " + workspaceCount,
         };
@@ -277,16 +303,21 @@ export class MainView extends React.Component {
 
     @action
     onResize = (r: any) => {
-        this._panelWidth = r.offset.width;
+        this._panelWidth = r.offset.width;// - this.propertiesWidth();
         this._panelHeight = r.offset.height;
     }
-    getPWidth = () => this._panelWidth;
+
+    @action
+    getPWidth = () => this._panelWidth - this.propertiesWidth()
+
     getPHeight = () => this._panelHeight;
     getContentsHeight = () => this._panelHeight - this._buttonBarHeight;
 
-    defaultBackgroundColors = (doc: Doc) => {
+    defaultBackgroundColors = (doc: Opt<Doc>) => {
+        if (this.panelContent === doc?.title) return "lightgrey";
         if (this.darkScheme) {
             switch (doc?.type) {
+                case DocumentType.MENUICON: return "white";
                 case DocumentType.RTF || DocumentType.LABEL || DocumentType.BUTTON: return "#2d2d2d";
                 case DocumentType.LINK:
                 case DocumentType.COL: {
@@ -296,6 +327,7 @@ export class MainView extends React.Component {
             }
         } else {
             switch (doc?.type) {
+                case DocumentType.MENUICON: return "black";
                 case DocumentType.RTF: return "#f1efeb";
                 case DocumentType.BUTTON:
                 case DocumentType.LABEL: return "lightgray";
@@ -308,7 +340,8 @@ export class MainView extends React.Component {
         }
     }
     @computed get mainDocView() {
-        return <DocumentView Document={this.mainContainer!}
+        return <DocumentView
+            Document={this.mainContainer!}
             DataDoc={undefined}
             LibraryPath={emptyPath}
             addDocument={undefined}
@@ -324,7 +357,6 @@ export class MainView extends React.Component {
             NativeWidth={returnZero}
             PanelWidth={this.getPWidth}
             PanelHeight={this.getPHeight}
-            renderDepth={0}
             focus={emptyFunction}
             parentActive={returnTrue}
             whenActiveChanged={emptyFunction}
@@ -332,103 +364,63 @@ export class MainView extends React.Component {
             docFilters={returnEmptyFilter}
             ContainingCollectionView={undefined}
             ContainingCollectionDoc={undefined}
+            renderDepth={-1}
         />;
     }
     @computed get dockingContent() {
         TraceMobx();
         const mainContainer = this.mainContainer;
         const width = this.flyoutWidth;
-        return <Measure offset onResize={this.onResize}>
-            {({ measureRef }) =>
-                <div ref={measureRef} className="mainContent-div" onDrop={this.onDrop} style={{ width: `calc(100% - ${width}px)` }}>
-                    {!mainContainer ? (null) : this.mainDocView}
-                </div>
-            }
-        </Measure>;
-    }
-
-    _canClick = false;
-    onPointerDown = (e: React.PointerEvent) => {
-        if (this._flyoutTranslate) {
-            this._canClick = true;
-            this._flyoutSizeOnDown = e.clientX;
-            document.removeEventListener("pointermove", this.onPointerMove);
-            document.removeEventListener("pointerup", this.onPointerUp);
-            document.addEventListener("pointermove", this.onPointerMove);
-            document.addEventListener("pointerup", this.onPointerUp);
-            e.stopPropagation();
-            e.preventDefault();
-        }
+        return <div className="mainContent-div" onDrop={this.onDrop} style={{ width: `calc(100% - ${width}px)` }}>
+            {!mainContainer ? (null) : this.mainDocView}
+        </div>;
     }
 
     @action
-    pointerLeaveDragger = () => {
-        if (!this._flyoutTranslate) {
-            this.flyoutWidth = 0;
-            this._flyoutTranslate = true;
-        }
+    onPropertiesPointerDown = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
+            this._propertiesWidth = this._panelWidth - e.clientX;
+            return false;
+        }), returnFalse, action(() => this._propertiesWidth = this.propertiesWidth() < 15 ? Math.min(this._panelWidth - 50, 250) : 0), false);
     }
 
     @action
-    onPointerMove = (e: PointerEvent) => {
-        this.flyoutWidth = Math.max(e.clientX, 0);
-        Math.abs(this.flyoutWidth - this._flyoutSizeOnDown) > 6 && (this._canClick = false);
-        this.sidebarButtonsDoc._columnWidth = this.flyoutWidth / 3 - 30;
-    }
-    @action
-    onPointerUp = (e: PointerEvent) => {
-        if (Math.abs(e.clientX - this._flyoutSizeOnDown) < 4 && this._canClick) {
-            this.flyoutWidth = this.flyoutWidth < 15 ? 250 : 0;
-            this.flyoutWidth && (this.sidebarButtonsDoc._columnWidth = this.flyoutWidth / 3 - 30);
+    onFlyoutPointerDown = (e: React.PointerEvent) => {
+        this.panelContent = "none";
+        if (this._flyoutTranslate) {
+            setupMoveUpEvents(this, e, action((e: PointerEvent) => {
+                this.flyoutWidth = Math.max(e.clientX, 0);
+                this.sidebarButtonsDoc._columnWidth = this.flyoutWidth / 3 - 30;
+                return false;
+            }), emptyFunction, action(() => {
+                this.flyoutWidth = this.flyoutWidth < 15 ? 250 : 0;
+                this.flyoutWidth && (this.sidebarButtonsDoc._columnWidth = this.flyoutWidth / 3 - 30);
+            }));
         }
-        document.removeEventListener("pointermove", this.onPointerMove);
-        document.removeEventListener("pointerup", this.onPointerUp);
     }
+
     flyoutWidthFunc = () => this.flyoutWidth;
     addDocTabFunc = (doc: Doc, where: string, libraryPath?: Doc[]): boolean => {
         return where === "close" ? CollectionDockingView.CloseRightSplit(doc) :
             doc.dockingConfig ? this.openWorkspace(doc) :
                 CollectionDockingView.AddRightSplit(doc, libraryPath);
     }
-    sidebarScreenToLocal = () => new Transform(0, (RichTextMenu.Instance.Pinned ? -35 : 0) + (CollectionMenu.Instance.Pinned ? -35 : 0), 1);
+    sidebarScreenToLocal = () => new Transform(0, (CollectionMenu.Instance.Pinned ? -35 : 0), 1);
+    //sidebarScreenToLocal = () => new Transform(0, (RichTextMenu.Instance.Pinned ? -35 : 0) + (CollectionMenu.Instance.Pinned ? -35 : 0), 1);
     mainContainerXf = () => this.sidebarScreenToLocal().translate(0, -this._buttonBarHeight);
 
+    @computed get closePosition() { return 55 + this.flyoutWidth; }
     @computed get flyout() {
-        const sidebarContent = this.userDoc?.["tabs-panelContainer"];
-        if (!(sidebarContent instanceof Doc)) {
-            return (null);
-        }
-        return <div className="mainView-flyoutContainer" >
-            <div className="mainView-tabButtons" style={{ height: `${this._buttonBarHeight - 10/*margin-top*/}px`, backgroundColor: StrCast(this.sidebarButtonsDoc.backgroundColor) }}>
-                <DocumentView
-                    Document={this.sidebarButtonsDoc}
-                    DataDoc={undefined}
-                    LibraryPath={emptyPath}
-                    addDocument={undefined}
-                    rootSelected={returnTrue}
-                    addDocTab={this.addDocTabFunc}
-                    pinToPres={emptyFunction}
-                    removeDocument={undefined}
-                    onClick={undefined}
-                    ScreenToLocalTransform={this.sidebarScreenToLocal}
-                    ContentScaling={returnOne}
-                    NativeHeight={returnZero}
-                    NativeWidth={returnZero}
-                    PanelWidth={this.flyoutWidthFunc}
-                    PanelHeight={this.getPHeight}
-                    renderDepth={0}
-                    focus={emptyFunction}
-                    backgroundColor={this.defaultBackgroundColors}
-                    parentActive={returnTrue}
-                    whenActiveChanged={emptyFunction}
-                    bringToFront={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined} />
-            </div>
-            <div className="mainView-contentArea" style={{ position: "relative", height: `calc(100% - ${this._buttonBarHeight}px)`, width: "100%", overflow: "visible" }}>
+        if (!this.sidebarContent) return null;
+        return <div className="mainView-libraryFlyout">
+            <div className="mainView-contentArea" style={{ position: "relative", height: `100%`, width: "100%", overflow: "visible" }}>
+                {this.flyoutWidth > 0 ? <div className="mainView-libraryFlyout-close"
+                    onPointerDown={this.closeFlyout}>
+                    <FontAwesomeIcon icon="times" color="black" size="sm" />
+                </div> : null}
+
                 <DocumentView
-                    Document={sidebarContent}
+                    Document={this.sidebarContent}
                     DataDoc={undefined}
                     LibraryPath={emptyPath}
                     addDocument={undefined}
@@ -451,52 +443,162 @@ export class MainView extends React.Component {
                     bringToFront={emptyFunction}
                     docFilters={returnEmptyFilter}
                     ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined} />
-                <div className="buttonContainer" >
-                    <button className="mainView-settings" key="settings" onClick={() => SettingsManager.Instance.open()}>
-                        <FontAwesomeIcon icon="cog" size="lg" />
-                    </button>
-                </div>
+                    ContainingCollectionDoc={undefined}
+                    relative={true}
+                />
             </div>
-            {this.docButtons}
+            {this.docButtons}</div>;
+    }
+
+    @computed get menuPanel() {
+
+        return <div className="mainView-menuPanel">
+            <DocumentView
+                Document={Doc.UserDoc().menuStack as Doc}
+                DataDoc={undefined}
+                LibraryPath={emptyPath}
+                addDocument={undefined}
+                addDocTab={this.addDocTabFunc}
+                pinToPres={emptyFunction}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
+                rootSelected={returnTrue}
+                removeDocument={returnFalse}
+                onClick={undefined}
+                ScreenToLocalTransform={this.mainContainerXf}
+                ContentScaling={returnOne}
+                PanelWidth={() => 70}
+                PanelHeight={this.getContentsHeight}
+                renderDepth={0}
+                focus={emptyFunction}
+                backgroundColor={this.defaultBackgroundColors}
+                parentActive={returnTrue}
+                whenActiveChanged={emptyFunction}
+                bringToFront={emptyFunction}
+                docFilters={returnEmptyFilter}
+                ContainingCollectionView={undefined}
+                ContainingCollectionDoc={undefined}
+                relative={true}
+                scriptContext={this}
+            />
+        </div>;
+    }
+
+
+    @action @undoBatch
+    closeFlyout = () => {
+        this.panelContent = "none";
+        this.flyoutWidth = 0;
+    }
+
+    get groupManager() { return GroupManager.Instance; }
+
+    @action @undoBatch
+    selectMenu = (str: string) => {
+        if (this.panelContent === str && this.flyoutWidth !== 0) {
+            this.panelContent = "none";
+            this.flyoutWidth = 0;
+        } else {
+            this.panelContent = str;
+            switch (this.panelContent) {
+                case "Tools": this.sidebarContent.proto = CurrentUserUtils.toolsStack; break;
+                case "Workspace": this.sidebarContent.proto = CurrentUserUtils.workspaceStack; break;
+                case "Catalog": this.sidebarContent.proto = CurrentUserUtils.catalogStack; break;
+                case "Archive": this.sidebarContent.proto = CurrentUserUtils.closedStack; break;
+                case "Settings": this.sidebarContent.proto = SettingsManager.Instance.open(); break;
+                case "Sharing": this.sidebarContent.proto = GroupManager.Instance.open(); break;
+            }
+            if (str === "Settings" || str === "Sharing" || str === "Help") {
+                this.panelContent = "none";
+                this.flyoutWidth = 0;
+            } else {
+                MainView.expandFlyout();
+            }
+        }
+        return true;
+    }
+
+    @action @undoBatch
+    closeProperties = () => {
+        this._propertiesWidth = 0;
+    }
+
+    @computed get propertiesView() {
+        TraceMobx();
+        return <div className="mainView-propertiesView" style={{
+            overflow: this.propertiesWidth() < 15 ? "hidden" : undefined
+        }}>
+            <PropertiesView
+                width={this.propertiesWidth()}
+                height={this._panelHeight}
+                renderDepth={1}
+                ScreenToLocalTransform={Transform.Identity}
+                onDown={this.closeProperties}
+            />
         </div>;
     }
 
+    @computed get mainInnerContent() {
+        const rightFlyout = this.propertiesWidth() - 1;
+        return <>
+            {this.menuPanel}
+            <div style={{ display: "contents", flexDirection: "row", position: "relative" }}>
+                <div className="mainView-flyoutContainer" style={{ width: this.flyoutWidth }}>
+                    {this.flyoutWidth !== 0 ? <div className="mainView-libraryHandle"
+                        onPointerDown={this.onFlyoutPointerDown}
+                        style={{ backgroundColor: this.defaultBackgroundColors(undefined) }}>
+                        <span title="library View Dragger" style={{
+                            width: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "100%" : "3vw",
+                            //height: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "100%" : "100vh",
+                            position: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "absolute" : "fixed",
+                            top: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "" : "0"
+                        }} />
+                        <div className="mainview-libraryHandle-icon">
+                            <FontAwesomeIcon icon="chevron-left" color="black" size="sm" /> </div>
+                    </div> : null}
+                    <div className="mainView-libraryFlyout" style={{
+                        //transformOrigin: this._flyoutTranslate ? "" : "left center",
+                        transition: this._flyoutTranslate ? "" : "width .5s",
+                        //transform: `scale(${this._flyoutTranslate ? 1 : 0.8})`,
+                        boxShadow: this._flyoutTranslate ? "" : "rgb(156, 147, 150) 0.2vw 0.2vw 0.2vw"
+                    }}>
+                        {this.flyout}
+                        {this.expandButton}
+                    </div>
+                </div>
+                {this.dockingContent}
+                {this.showProperties ? (null) :
+                    <div className="mainView-propertiesDragger" title="Properties View Dragger" onPointerDown={this.onPropertiesPointerDown}
+                        style={{ right: rightFlyout, top: "45%" }}>
+                        <div className="mainView-propertiesDragger-icon">
+                            <FontAwesomeIcon icon={this.propertiesIcon} color="white" size="sm" /> </div>
+                    </div>
+                }
+                {this.propertiesWidth() < 10 ? (null) :
+                    <div style={{ width: this.propertiesWidth() }}> {this.propertiesView} </div>}
+            </div>
+        </>;
+    }
+
     @computed get mainContent() {
-        const sidebar = this.userDoc?.["tabs-panelContainer"];
-        const n = (RichTextMenu.Instance?.Pinned ? 1 : 0) + (CollectionMenu.Instance?.Pinned ? 1 : 0);
+        //const n = (RichTextMenu.Instance?.Pinned ? 1 : 0) + (CollectionMenu.Instance?.Pinned ? 1 : 0);
+        const n = (CollectionMenu.Instance?.Pinned ? 1 : 0);
         const height = `calc(100% - ${n * Number(ANTIMODEMENU_HEIGHT.replace("px", ""))}px)`;
-        return !this.userDoc || !(sidebar instanceof Doc) ? (null) : (
-            <div className="mainView-mainContent" style={{
-                color: this.darkScheme ? "rgb(205,205,205)" : "black",
-                //change to times 2 for both pinned
-                height,
-                width: (FormatShapePane.Instance?.Pinned) ? `calc(100% - 200px)` : "100%"
-            }} >
-                <div style={{ display: "contents", flexDirection: "row", position: "relative" }}>
-                    <div className="mainView-flyoutContainer" onPointerLeave={this.pointerLeaveDragger} style={{ width: this.flyoutWidth }}>
-                        <div className="mainView-libraryHandle" onPointerDown={this.onPointerDown}
-                            style={{ backgroundColor: this.defaultBackgroundColors(sidebar) }}>
-                            <span title="library View Dragger" style={{
-                                width: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "100%" : "3vw",
-                                //height: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "100%" : "100vh",
-                                position: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "absolute" : "fixed",
-                                top: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "" : "0"
-                            }} />
-                        </div>
-                        <div className="mainView-libraryFlyout" style={{
-                            //transformOrigin: this._flyoutTranslate ? "" : "left center",
-                            transition: this._flyoutTranslate ? "" : "width .5s",
-                            //transform: `scale(${this._flyoutTranslate ? 1 : 0.8})`,
-                            boxShadow: this._flyoutTranslate ? "" : "rgb(156, 147, 150) 0.2vw 0.2vw 0.8vw"
-                        }}>
-                            {this.flyout}
-                            {this.expandButton}
-                        </div>
+        const pinned = FormatShapePane.Instance?.Pinned;
+        const innerContent = this.mainInnerContent;
+        return !this.userDoc ? (null) : (
+            <Measure offset onResize={this.onResize}>
+                {({ measureRef }) =>
+                    <div className="mainView-mainContent" ref={measureRef} style={{
+                        color: this.darkScheme ? "rgb(205,205,205)" : "black",
+                        //change to times 2 for both pinned
+                        height,
+                        width: pinned ? `calc(100% - 200px)` : "100%"
+                    }} >
+                        {innerContent}
                     </div>
-                    {this.dockingContent}
-                </div>
-            </div>);
+                }
+            </Measure>);
     }
 
     public static expandFlyout = action(() => {
@@ -506,7 +608,7 @@ export class MainView extends React.Component {
     });
 
     @computed get expandButton() {
-        return !this._flyoutTranslate ? (<div className="mainView-expandFlyoutButton" title="Re-attach sidebar" onPointerDown={MainView.expandFlyout}><FontAwesomeIcon icon="chevron-right" color="grey" size="lg" /></div>) : (null);
+        return !this._flyoutTranslate ? (<div className="mainView-expandFlyoutButton" title="Re-attach sidebar" onPointerDown={MainView.expandFlyout}></div>) : (null);
     }
 
     addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", doc), true);
@@ -600,8 +702,16 @@ export class MainView extends React.Component {
         </svg>;
     }
 
+    @computed get search() {
+        return <div className="mainView-searchPanel">
+            <div style={{ float: "left", marginLeft: "10px" }}>{Doc.CurrentUserEmail}</div>
+            <div>SEARCH GOES HERE</div>
+        </div>;
+    }
+
     render() {
         return (<div className={"mainView-container" + (this.darkScheme ? "-dark" : "")} ref={this._mainViewRef}>
+
             {this.inkResources}
             <DictationOverlay />
             <SharingManager />
@@ -610,9 +720,10 @@ export class MainView extends React.Component {
             <GoogleAuthenticationManager />
             <HypothesisAuthenticationManager />
             <DocumentDecorations />
+            {/* {this.search} */}
             <CollectionMenu />
             <FormatShapePane />
-            <RichTextMenu key="rich" />
+            <div style={{ display: "none" }}><RichTextMenu key="rich" /></div>
             {LinkDescriptionPopup.descriptionPopup ? <LinkDescriptionPopup /> : null}
             {DocumentLinksButton.EditLink ? <LinkMenu location={DocumentLinksButton.EditLinkLoc} docView={DocumentLinksButton.EditLink} addDocTab={DocumentLinksButton.EditLink.props.addDocTab} changeFlyout={emptyFunction} /> : (null)}
             {LinkDocPreview.LinkInfo ? <LinkDocPreview location={LinkDocPreview.LinkInfo.Location} backgroundColor={this.defaultBackgroundColors}
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index b4116e980..d7034fcfb 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -112,10 +112,10 @@ export class PreviewCursor extends React.Component<{}> {
                 } else if (e.clipboardData.items.length) {
                     const batch = UndoManager.StartBatch("collection view drop");
                     const files: File[] = [];
-                    for (let i = 0; i < e.clipboardData.items.length; i++) {
-                        const file = e.clipboardData.items[i].getAsFile();
+                    Array.from(e.clipboardData.items).forEach(item => {
+                        const file = item.getAsFile();
                         file && files.push(file);
-                    }
+                    });
                     const generatedDocuments = await DocUtils.uploadFilesToDocs(files, { x: newPoint[0], y: newPoint[1] });
                     generatedDocuments.forEach(PreviewCursor._addDocument);
                     batch.end();
diff --git a/src/client/views/PropertiesButtons.scss b/src/client/views/PropertiesButtons.scss
new file mode 100644
index 000000000..e099122c4
--- /dev/null
+++ b/src/client/views/PropertiesButtons.scss
@@ -0,0 +1,119 @@
+@import "globalCssVariables";
+
+$linkGap : 3px;
+
+.propertiesButtons-linkFlyout {
+    grid-column: 2/4;
+}
+
+.propertiesButtons-linkButton-empty:hover {
+    background: $main-accent;
+    transform: scale(1.05);
+    cursor: pointer;
+}
+
+.propertiesButtons-linkButton-nonempty:hover {
+    background: $main-accent;
+    transform: scale(1.05);
+    cursor: pointer;
+}
+
+.propertiesButtons-linkButton-empty,
+.propertiesButtons-linkButton-nonempty {
+    height: 30px;
+    width: 30px;
+    border-radius: 5px;
+    opacity: 0.9;
+    pointer-events: auto;
+    background-color: #121721;
+    color: #fcfbf7;
+    text-transform: uppercase;
+    letter-spacing: 2px;
+    font-size: 75%;
+    transition: transform 0.2s;
+    text-align: center;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin-right: 10px;
+
+    &:hover {
+        background: $main-accent;
+        transform: scale(1.05);
+        cursor: pointer;
+    }
+}
+
+.propertiesButtons {
+    margin-top: $linkGap;
+    grid-column: 1/4;
+    width: max-content;
+    height: auto;
+    display: flex;
+    flex-direction: row;
+    overflow-x: visible;
+}
+
+.onClickFlyout-editScript {
+    text-align: center;
+    border: 0.5px solid grey;
+    background-color: rgb(230, 230, 230);
+    border-radius: 9px;
+    padding: 4px;
+}
+
+
+.propertiesButtons-button {
+    pointer-events: auto;
+    padding-right: 5px;
+    width: 25px;
+    border-radius: 5px;
+    margin-right: 18px;
+}
+
+.propertiesButtons-linker {
+    height: 30px;
+    width: 30px;
+    text-align: center;
+    border-radius: 5px;
+    pointer-events: auto;
+    color: $dark-color;
+    border: $dark-color 1px solid;
+    transition: 0.2s ease all;
+    margin-right: 5px;
+}
+
+.propertiesButtons-linker:hover {
+    cursor: pointer;
+    transform: scale(1.05);
+}
+
+
+@-moz-keyframes spin {
+    100% {
+        -moz-transform: rotate(360deg);
+    }
+}
+
+@-webkit-keyframes spin {
+    100% {
+        -webkit-transform: rotate(360deg);
+    }
+}
+
+@keyframes spin {
+    100% {
+        -webkit-transform: rotate(360deg);
+        transform: rotate(360deg);
+    }
+}
+
+@keyframes shadow-pulse {
+    0% {
+        box-shadow: 0 0 0 0px rgba(0, 0, 0, 0.8);
+    }
+
+    100% {
+        box-shadow: 0 0 0 10px rgba(0, 255, 0, 0);
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
new file mode 100644
index 000000000..59e7cc7c8
--- /dev/null
+++ b/src/client/views/PropertiesButtons.tsx
@@ -0,0 +1,598 @@
+import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
+import { faArrowAltCircleDown, faArrowAltCircleRight, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faPhotoVideo, faShare, faStopCircle, faSyncAlt, faTag, faTimes } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action, computed, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import { Doc, DocListCast } from "../../fields/Doc";
+import { RichTextField } from '../../fields/RichTextField';
+import { Cast, NumCast, BoolCast } from "../../fields/Types";
+import { emptyFunction, setupMoveUpEvents, Utils } from "../../Utils";
+import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
+import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils';
+import { Docs, DocUtils } from '../documents/Documents';
+import { DragManager } from '../util/DragManager';
+import { CollectionDockingView, DockedFrameRenderer } from './collections/CollectionDockingView';
+import { ParentDocSelector } from './collections/ParentDocumentSelector';
+import './collections/ParentDocumentSelector.scss';
+import './PropertiesButtons.scss';
+import { MetadataEntryMenu } from './MetadataEntryMenu';
+import { DocumentView } from './nodes/DocumentView';
+import { GoogleRef } from "./nodes/formattedText/FormattedTextBox";
+import { TemplateMenu } from "./TemplateMenu";
+import { Template, Templates } from "./Templates";
+import React = require("react");
+import { Tooltip } from '@material-ui/core';
+import { SelectionManager } from '../util/SelectionManager';
+import SharingManager from '../util/SharingManager';
+import { GooglePhotos } from '../apis/google_docs/GooglePhotosClientUtils';
+import { ImageField } from '../../fields/URLField';
+import { undoBatch, UndoManager } from '../util/UndoManager';
+import { DocumentType } from '../documents/DocumentTypes';
+import { CollectionFreeFormView } from './collections/collectionFreeForm/CollectionFreeFormView';
+const higflyout = require("@hig/flyout");
+export const { anchorPoints } = higflyout;
+export const Flyout = higflyout.default;
+
+library.add(faLink);
+library.add(faTag);
+library.add(faTimes);
+library.add(faArrowAltCircleDown);
+library.add(faArrowAltCircleUp);
+library.add(faArrowAltCircleRight);
+library.add(faStopCircle);
+library.add(faCheckCircle);
+library.add(faCloudUploadAlt);
+library.add(faSyncAlt);
+library.add(faShare);
+library.add(faPhotoVideo);
+
+const cloud: IconProp = "cloud-upload-alt";
+const fetch: IconProp = "sync-alt";
+
+enum UtilityButtonState {
+    Default,
+    OpenRight,
+    OpenExternally
+}
+
+@observer
+export class PropertiesButtons extends React.Component<{}, {}> {
+    private _dragRef = React.createRef<HTMLDivElement>();
+    private _pullAnimating = false;
+    private _pushAnimating = false;
+    private _pullColorAnimating = false;
+
+    @observable private pushIcon: IconProp = "arrow-alt-circle-up";
+    @observable private pullIcon: IconProp = "arrow-alt-circle-down";
+    @observable private pullColor: string = "white";
+    @observable public isAnimatingFetch = false;
+    @observable public isAnimatingPulse = false;
+
+    @observable private openHover: UtilityButtonState = UtilityButtonState.Default;
+
+    @observable public static Instance: PropertiesButtons;
+    public static hasPushedHack = false;
+    public static hasPulledHack = false;
+
+
+    @computed get selectedDocumentView() {
+        if (SelectionManager.SelectedDocuments().length) {
+            return SelectionManager.SelectedDocuments()[0];
+        } else { return undefined; }
+    }
+    @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
+    @computed get dataDoc() { return this.selectedDocumentView?.dataDoc; }
+
+    @computed get onClick() { return this.selectedDoc?.onClickBehavior ? this.selectedDoc?.onClickBehavior : "nothing"; }
+
+    public startPullOutcome = action((success: boolean) => {
+        if (!this._pullAnimating) {
+            this._pullAnimating = true;
+            this.pullIcon = success ? "check-circle" : "stop-circle";
+            setTimeout(() => runInAction(() => {
+                this.pullIcon = "arrow-alt-circle-down";
+                this._pullAnimating = false;
+            }), 1000);
+        }
+    });
+
+    public startPushOutcome = action((success: boolean) => {
+        this.isAnimatingPulse = false;
+        if (!this._pushAnimating) {
+            this._pushAnimating = true;
+            this.pushIcon = success ? "check-circle" : "stop-circle";
+            setTimeout(() => runInAction(() => {
+                this.pushIcon = "arrow-alt-circle-up";
+                this._pushAnimating = false;
+            }), 1000);
+        }
+    });
+
+    public setPullState = action((unchanged: boolean) => {
+        this.isAnimatingFetch = false;
+        if (!this._pullColorAnimating) {
+            this._pullColorAnimating = true;
+            this.pullColor = unchanged ? "lawngreen" : "red";
+            setTimeout(this.clearPullColor, 1000);
+        }
+    });
+
+    private clearPullColor = action(() => {
+        this.pullColor = "white";
+        this._pullColorAnimating = false;
+    });
+
+    @computed
+    get considerGoogleDocsPush() {
+        const targetDoc = this.selectedDoc;
+        const published = targetDoc && Doc.GetProto(targetDoc)[GoogleRef] !== undefined;
+        const animation = this.isAnimatingPulse ? "shadow-pulse 1s linear infinite" : "none";
+        return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{`${published ? "Push" : "Publish"} to Google Docs`}</div></>}>
+            <div
+                className="propertiesButtons-linker"
+                style={{ animation }}
+                onClick={async () => {
+                    await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken();
+                    !published && runInAction(() => this.isAnimatingPulse = true);
+                    PropertiesButtons.hasPushedHack = false;
+                    targetDoc[Pushes] = NumCast(targetDoc[Pushes]) + 1;
+                }}>
+                <FontAwesomeIcon className="documentdecorations-icon" icon={published ? (this.pushIcon as any) : cloud} size={published ? "sm" : "xs"} />
+            </div></Tooltip>;
+    }
+
+    @computed
+    get considerGoogleDocsPull() {
+        const targetDoc = this.selectedDoc;
+        const dataDoc = targetDoc && Doc.GetProto(targetDoc);
+        const animation = this.isAnimatingFetch ? "spin 0.5s linear infinite" : "none";
+
+        const title = (() => {
+            switch (this.openHover) {
+                default:
+                case UtilityButtonState.Default: return `${!dataDoc?.unchanged ? "Pull from" : "Fetch"} Google Docs`;
+                case UtilityButtonState.OpenRight: return "Open in Right Split";
+                case UtilityButtonState.OpenExternally: return "Open in new Browser Tab";
+            }
+        })();
+
+        return !targetDoc || !dataDoc || !dataDoc[GoogleRef] ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{title}</div></>}>
+            <div className="propertiesButtons-linker"
+                style={{ backgroundColor: this.pullColor }}
+                onPointerEnter={action(e => {
+                    if (e.altKey) {
+                        this.openHover = UtilityButtonState.OpenExternally;
+                    } else if (e.shiftKey) {
+                        this.openHover = UtilityButtonState.OpenRight;
+                    }
+                })}
+                onPointerLeave={action(() => this.openHover = UtilityButtonState.Default)}
+                onClick={async e => {
+                    const googleDocUrl = `https://docs.google.com/document/d/${dataDoc[GoogleRef]}/edit`;
+                    if (e.shiftKey) {
+                        e.preventDefault();
+                        let googleDoc = await Cast(dataDoc.googleDoc, Doc);
+                        if (!googleDoc) {
+                            const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false, UseCors: false };
+                            googleDoc = Docs.Create.WebDocument(googleDocUrl, options);
+                            dataDoc.googleDoc = googleDoc;
+                        }
+                        CollectionDockingView.AddRightSplit(googleDoc);
+                    } else if (e.altKey) {
+                        e.preventDefault();
+                        window.open(googleDocUrl);
+                    } else {
+                        this.clearPullColor();
+                        PropertiesButtons.hasPulledHack = false;
+                        targetDoc[Pulls] = NumCast(targetDoc[Pulls]) + 1;
+                        dataDoc.unchanged && runInAction(() => this.isAnimatingFetch = true);
+                    }
+                }}>
+                <FontAwesomeIcon className="documentdecorations-icon" size="sm"
+                    style={{ WebkitAnimation: animation, MozAnimation: animation }}
+                    icon={(() => {
+                        switch (this.openHover) {
+                            default:
+                            case UtilityButtonState.Default: return dataDoc.unchanged === false ? (this.pullIcon as any) : fetch;
+                            case UtilityButtonState.OpenRight: return "arrow-alt-circle-right";
+                            case UtilityButtonState.OpenExternally: return "share";
+                        }
+                    })()}
+                />
+            </div></Tooltip>;
+    }
+    @computed
+    get pinButton() {
+        const targetDoc = this.selectedDoc;
+        const isPinned = targetDoc && Doc.isDocPinned(targetDoc);
+        return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div></>}>
+            <div className="propertiesButtons-linker"
+                style={{ backgroundColor: isPinned ? "white" : "rgb(37, 43, 51)", color: isPinned ? "black" : "white" }}
+                onClick={e => DockedFrameRenderer.PinDoc(targetDoc, isPinned)}>
+                <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin"
+                />
+            </div></Tooltip>;
+    }
+
+    @computed
+    get metadataButton() {
+        //const view0 = this.view0;
+        if (this.selectedDoc) {
+            return <Tooltip title={<><div className="dash-tooltip">Show metadata panel</div></>}>
+                <div className="propertiesButtons-linkFlyout">
+                    <Flyout anchorPoint={anchorPoints.LEFT_TOP}
+                        content={<MetadataEntryMenu docs={[this.selectedDoc]} suggestWithFunction />  /* tfs: @bcz This might need to be the data document? */}>
+                        <div className={"propertiesButtons-linkButton-" + "empty"} onPointerDown={e => e.stopPropagation()} >
+                            {<FontAwesomeIcon className="documentdecorations-icon" icon="tag" size="sm" />}
+                        </div>
+                    </Flyout>
+                </div></Tooltip>;
+        } else {
+            return null;
+        }
+
+    }
+
+    @observable _aliasDown = false;
+    onAliasButtonDown = (e: React.PointerEvent): void => {
+        setupMoveUpEvents(this, e, this.onAliasButtonMoved, emptyFunction, emptyFunction);
+    }
+    onAliasButtonMoved = () => {
+        if (this._dragRef.current) {
+            const dragDocView = this.selectedDocumentView!;
+            const dragData = new DragManager.DocumentDragData([dragDocView.props.Document]);
+            const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+            dragData.dropAction = "alias";
+            DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, left, top, {
+                offsetX: dragData.offset[0],
+                offsetY: dragData.offset[1],
+                hideSource: false
+            });
+            return true;
+        }
+        return false;
+    }
+
+    @computed
+    get templateButton() {
+        const docView = this.selectedDocumentView;
+        const templates: Map<Template, boolean> = new Map();
+        const views = [this.selectedDocumentView];
+        Array.from(Object.values(Templates.TemplateList)).map(template =>
+            templates.set(template, views.reduce((checked, doc) => checked || doc?.props.Document["_show" + template.Name] ? true : false, false as boolean)));
+        return !docView ? (null) :
+            <Tooltip title={<><div className="dash-tooltip">Customize layout</div></>}>
+                <div className="propertiesButtons-linkFlyout">
+                    <Flyout anchorPoint={anchorPoints.LEFT_TOP} //onOpen={action(() => this._aliasDown = true)} onClose={action(() => this._aliasDown = false)}
+                        content={<TemplateMenu docViews={views.filter(v => v).map(v => v as DocumentView)} templates={templates} />}>
+                        <div className={"propertiesButtons-linkButton-empty"} >
+                            {<FontAwesomeIcon className="documentdecorations-icon" icon="edit" size="sm" />}
+                        </div>
+                    </Flyout>
+                </div></Tooltip>;
+    }
+
+    onCopy = () => {
+        if (this.selectedDoc && this.selectedDocumentView) {
+            const copy = Doc.MakeCopy(this.selectedDocumentView.props.Document, true);
+            copy.x = NumCast(this.selectedDoc.x) + NumCast(this.selectedDoc._width);
+            copy.y = NumCast(this.selectedDoc.y) + 30;
+            this.selectedDocumentView.props.addDocument?.(copy);
+        }
+    }
+
+    @computed
+    get copyButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Tap or Drag to create an alias"}</div></>}>
+            <div className={"propertiesButtons-linkButton-empty"}
+                ref={this._dragRef}
+                onPointerDown={this.onAliasButtonDown}
+                onClick={this.onCopy}>
+                {<FontAwesomeIcon className="documentdecorations-icon" icon="copy" size="sm" />}
+            </div>
+        </Tooltip>;
+    }
+
+    @action
+    onLock = () => {
+        this.selectedDocumentView?.toggleLockPosition();
+    }
+
+    @computed
+    get lockButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{this.selectedDoc?.lockedPosition ?
+                "Unlock Position" : "Lock Position"}</div></>}>
+            <div className={"propertiesButtons-linkButton-empty"}
+                onPointerDown={this.onLock} >
+                {<FontAwesomeIcon className="documentdecorations-icon"
+                    icon={BoolCast(this.selectedDoc?.lockedPosition) ? "unlock" : "lock"} size="sm" />}
+            </div>
+        </Tooltip>;
+    }
+
+    @computed
+    get downloadButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{"Download Document"}</div></>}>
+            <div className={"propertiesButtons-linkButton-empty"}
+                onPointerDown={async () => {
+                    if (this.selectedDocumentView?.props.Document) {
+                        Doc.Zip(this.selectedDocumentView?.props.Document);
+                    }
+                }}>
+                {<FontAwesomeIcon className="propertiesButtons-icon"
+                    icon="download" size="sm" />}
+            </div>
+        </Tooltip>;
+    }
+
+    @computed
+    get deleteButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{"Delete Document"}</div></>}>
+            <div className={"propertiesButtons-linkButton-empty"}
+                onPointerDown={() => {
+                    this.selectedDocumentView?.props.ContainingCollectionView?.removeDocument(this.selectedDocumentView?.props.Document);
+                }}>
+                {<FontAwesomeIcon className="propertiesButtons-icon"
+                    icon="trash-alt" size="sm" />}
+            </div>
+        </Tooltip>;
+    }
+
+    @computed
+    get sharingButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{"Share Document"}</div></>}>
+            <div className={"propertiesButtons-linkButton-empty"}
+                onPointerDown={() => {
+                    if (this.selectedDocumentView) {
+                        SharingManager.Instance.open(this.selectedDocumentView);
+                    }
+                }}>
+                {<FontAwesomeIcon className="propertiesButtons-icon"
+                    icon="users" size="sm" />}
+            </div>
+        </Tooltip>;
+    }
+
+    @computed
+    get onClickButton() {
+        if (this.selectedDoc) {
+            return <Tooltip title={<><div className="dash-tooltip">Choose onClick behavior</div></>}>
+                <div className="propertiesButtons-linkFlyout">
+                    <Flyout anchorPoint={anchorPoints.LEFT_TOP}
+                        content={this.onClickFlyout}>
+                        <div className={"propertiesButtons-linkButton-" + "empty"} onPointerDown={e => e.stopPropagation()} >
+                            {<FontAwesomeIcon className="documentdecorations-icon" icon="mouse-pointer" size="sm" />}
+                        </div>
+                    </Flyout>
+                </div></Tooltip>;
+        } else {
+            return null;
+        }
+    }
+
+    @action
+    handleOptionChange = (e: any) => {
+        const value = e.target.value;
+        this.selectedDoc && (this.selectedDoc.onClickBehavior = e.target.value);
+        if (value === "nothing") {
+            this.selectedDocumentView?.noOnClick();
+        } else if (value === "enterPortal") {
+            this.selectedDocumentView?.noOnClick();
+            this.selectedDocumentView?.makeIntoPortal();
+        } else if (value === "toggleDetail") {
+            this.selectedDocumentView?.noOnClick();
+            this.selectedDocumentView?.toggleDetail();
+        } else if (value === "linkInPlace") {
+            this.selectedDocumentView?.noOnClick();
+            this.selectedDocumentView?.toggleFollowLink("inPlace", true, false);
+        } else if (value === "linkOnRight") {
+            this.selectedDocumentView?.noOnClick();
+            this.selectedDocumentView?.toggleFollowLink("onRight", false, false);
+        }
+    }
+
+    @undoBatch @action
+    editOnClickScript = () => {
+        if (this.selectedDoc) {
+            DocUtils.makeCustomViewClicked(this.selectedDoc, undefined, "onClick");
+        }
+    }
+
+    @computed
+    get onClickFlyout() {
+        return <div><form>
+            <div className="radio">
+                <label>
+                    <input type="radio" value="nothing"
+                        checked={this.onClick === 'nothing'}
+                        onChange={this.handleOptionChange} />
+                    Select Document
+                </label>
+            </div>
+            <div className="radio">
+                <label>
+                    <input type="radio" value="enterPortal"
+                        checked={this.onClick === 'enterPortal'}
+                        onChange={this.handleOptionChange} />
+                    Enter Portal
+                </label>
+            </div>
+            <div className="radio">
+                <label>
+                    <input type="radio" value="toggleDetail"
+                        checked={this.onClick === 'toggleDetail'}
+                        onChange={this.handleOptionChange} />
+                    Toggle Detail
+                </label>
+            </div>
+            <div className="radio">
+                <label>
+                    <input type="radio" value="linkInPlace"
+                        checked={this.onClick === 'linkInPlace'}
+                        onChange={this.handleOptionChange} />
+                    Follow Link
+                </label>
+            </div>
+            <div className="radio">
+                <label>
+                    <input type="radio" value="linkOnRight"
+                        checked={this.onClick === 'linkOnRight'}
+                        onChange={this.handleOptionChange} />
+                    Open Link on Right
+                </label>
+            </div>
+        </form>
+            <div onPointerDown={this.editOnClickScript} className="onClickFlyout-editScript"> Edit onClick Script</div>
+        </div>;
+    }
+
+    @computed
+    get googlePhotosButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{"Export to Google Photos"}</div></>}>
+            <div className={"propertiesButtons-linkButton-empty"}
+                onPointerDown={() => {
+                    if (this.selectedDocumentView) {
+                        GooglePhotos.Export.CollectionToAlbum({ collection: this.selectedDocumentView.Document }).then(console.log);
+                    }
+                }}>
+                {<FontAwesomeIcon className="documentdecorations-icon"
+                    icon="cloud-upload-alt" size="sm" />}
+            </div>
+        </Tooltip>;
+    }
+
+    @computed
+    get clustersButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{this.selectedDoc?.useClusters ? "Stop Showing Clusters" : "Show Clusters"}</div></>}>
+            <div className={"propertiesButtons-linkButton-empty"}
+                style={{ backgroundColor: this.selectedDoc?.useClusters ? "#a0a0a0" : "" }}
+                onPointerDown={this.changeClusters}>
+                {<FontAwesomeIcon className="documentdecorations-icon"
+                    color={this.selectedDoc?.useClusters ? "black" : "white"}
+                    icon="braille" size="sm" />}
+            </div>
+        </Tooltip>;
+    }
+
+    @action @undoBatch
+    changeFitToBox = () => {
+        this.selectedDoc && (this.selectedDoc._fitToBox = !this.selectedDoc._fitToBox);
+    }
+
+    @action @undoBatch
+    changeClusters = () => {
+        this.selectedDoc && (this.selectedDoc.useClusters = !this.selectedDoc.useClusters);
+    }
+
+    @computed
+    get fitContentButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{this.selectedDoc?._fitToBox ? "Stop Fitting Content" : "Fit Content"}</div></>}>
+            <div className={"propertiesButtons-linkButton-empty"}
+                style={{ backgroundColor: this.selectedDoc?._fitToBox ? "#a0a0a0" : "" }}
+                onPointerDown={this.changeFitToBox}>
+                {<FontAwesomeIcon className="documentdecorations-icon"
+                    color={this.selectedDoc?._fitToBox ? "black" : "white"}
+                    icon="expand" size="sm" />}
+            </div>
+        </Tooltip>;
+    }
+
+    // @computed
+    // get importButton() {
+    //     const targetDoc = this.selectedDoc;
+    //     return !targetDoc ? (null) : <Tooltip
+    //         title={<><div className="dash-tooltip">{"Import a Document"}</div></>}>
+    //         <div className={"propertiesButtons-linkButton-empty"}
+    //             onPointerDown={() => {
+    //                 if (this.selectedDocumentView) {
+    //                     CollectionFreeFormView.importDocument(100, 100);
+    //                 }
+    //             }}>
+    //             {<FontAwesomeIcon className="documentdecorations-icon"
+    //                 icon="upload" size="sm" />}
+    //         </div>
+    //     </Tooltip>;
+    // }
+
+
+    render() {
+        if (!this.selectedDoc) return (null);
+
+        const isText = this.selectedDoc[Doc.LayoutFieldKey(this.selectedDoc)] instanceof RichTextField;
+        const considerPull = isText && this.considerGoogleDocsPull;
+        const considerPush = isText && this.considerGoogleDocsPush;
+        const isImage = this.selectedDoc[Doc.LayoutFieldKey(this.selectedDoc)] instanceof ImageField;
+        const isCollection = this.selectedDoc.type === DocumentType.COL ? true : false;
+        const isFreeForm = this.selectedDoc._viewType === "freeform" ? true : false;
+
+        return <div><div className="propertiesButtons" style={{ paddingBottom: "5.5px" }}>
+            <div className="propertiesButtons-button">
+                {this.templateButton}
+            </div>
+            {/* <div className="propertiesButtons-button">
+                {this.metadataButton}
+            </div> */}
+            <div className="propertiesButtons-button">
+                {this.pinButton}
+            </div>
+            <div className="propertiesButtons-button">
+                {this.copyButton}
+            </div>
+            <div className="propertiesButtons-button">
+                {this.lockButton}
+            </div>
+            <div className="propertiesButtons-button">
+                {this.downloadButton}
+            </div>
+        </div>
+            <div className="propertiesButtons">
+                <div className="propertiesButtons-button">
+                    {this.deleteButton}
+                </div>
+                <div className="propertiesButtons-button">
+                    {this.onClickButton}
+                </div>
+                <div className="propertiesButtons-button">
+                    {this.sharingButton}
+                </div>
+                <div className="propertiesButtons-button" style={{ display: !considerPush ? "none" : "" }}>
+                    {this.considerGoogleDocsPush}
+                </div>
+                <div className="propertiesButtons-button" style={{ display: !considerPull ? "none" : "" }}>
+                    {this.considerGoogleDocsPull}
+                </div>
+                <div className="propertiesButtons-button" style={{ display: !isImage ? "none" : "" }}>
+                    {this.googlePhotosButton}
+                </div>
+                {/* <div className="propertiesButtons-button" style={{ display: !isCollection ? "none" : "" }}>
+                    {this.importButton}
+                </div> */}
+
+                <div className="propertiesButtons-button" style={{ display: !isFreeForm ? "none" : "" }}>
+                    {this.clustersButton}
+                </div>
+
+                <div className="propertiesButtons-button" style={{ display: !isFreeForm ? "none" : "" }}>
+                    {this.fitContentButton}
+                </div>
+
+            </div>
+        </div>;
+    }
+}
diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss
index 9b14df760..6d93b2ba8 100644
--- a/src/client/views/collections/CollectionDockingView.scss
+++ b/src/client/views/collections/CollectionDockingView.scss
@@ -12,6 +12,7 @@
         width: 100%;
         height: 100%;
         position: absolute;
+
         .miniThumb {
             background: #25252525;
             position: absolute;
@@ -89,6 +90,7 @@
     transform: translate(0px, -3px);
     cursor: grab;
 }
+
 .lm_title.focus-visible {
     cursor: text;
 }
@@ -96,23 +98,25 @@
 .lm_title_wrap {
     overflow: hidden;
     height: 19px;
-    margin-top: -3px;
-    display:inline-block;
+    margin-top: -2px;
+    display: inline-block;
 }
+
 .lm_active .lm_title {
     border: solid 1px lightgray;
 }
+
 .lm_header .lm_tab .lm_close_tab {
     position: absolute;
     text-align: center;
 }
 
 .lm_header .lm_tab {
-    padding-right : 20px;
+    padding-right: 20px;
 }
 
 .lm_popout {
-    display:none;
+    display: none;
 }
 
 .messageCounter {
@@ -135,6 +139,7 @@
     position: absolute;
     top: 0;
     left: 0;
+
     // overflow: hidden;  // bcz: menus don't show up when this is on (e.g., the parentSelectorMenu)
     .collectionDockingView-gear {
         padding-left: 5px;
@@ -142,7 +147,10 @@
         width: 18px;
         display: inline-block;
         margin: auto;
+
+        display: none;
     }
+
     .collectionDockingView-dragAsDocument {
         touch-action: none;
         position: absolute;
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index f658e9816..d685fac4e 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -1,9 +1,8 @@
 import 'golden-layout/src/css/goldenlayout-base.css';
 import 'golden-layout/src/css/goldenlayout-dark-theme.css';
-import { action, computed, Lambda, observable, reaction, runInAction, trace } from "mobx";
+import { action, computed, Lambda, observable, reaction, runInAction, trace, IReactionDisposer } from "mobx";
 import { observer } from "mobx-react";
 import * as ReactDOM from 'react-dom';
-import Measure from "react-measure";
 import * as GoldenLayout from "../../../client/goldenLayout";
 import { DateField } from '../../../fields/DateField';
 import { Doc, DocListCast, Field, Opt, DataSym } from "../../../fields/Doc";
@@ -507,7 +506,6 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
 
             const doc = await DocServer.GetRefField(tab.contentItem.config.props.documentId) as Doc;
             if (doc instanceof Doc) {
-                //tab.titleElement[0].outerHTML = `<input class='lm_title' style="background:black" value='${doc.title}' />`;
                 tab.titleElement[0].onclick = (e: any) => tab.titleElement[0].focus();
                 tab.titleElement[0].onchange = (e: any) => {
                     tab.titleElement[0].size = e.currentTarget.value.length + 1;
@@ -522,6 +520,10 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
                 gearSpan.style.paddingLeft = "0px";
                 gearSpan.style.paddingRight = "12px";
                 const stack = tab.contentItem.parent;
+                tab.element[0].onpointerdown = (e: any) => {
+                    const view = DocumentManager.Instance.getDocumentView(doc);
+                    view && SelectionManager.SelectDoc(view, false);
+                };
                 // shifts the focus to this tab when another tab is dragged over it
                 tab.element[0].onmouseenter = (e: any) => {
                     if (!this._isPointerDown || !SnappingManager.GetIsDragging()) return;
@@ -676,10 +678,15 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     @observable private _panelHeight = 0;
     @observable private _document: Opt<Doc>;
     @observable private _isActive: boolean = false;
+    _tabReaction: IReactionDisposer | undefined;
 
     get _stack(): any {
         return (this.props as any).glContainer.parent.parent;
     }
+    get _tab(): any {
+        const tab = (this.props as any).glContainer.tab.element[0] as HTMLElement;
+        return tab.getElementsByClassName("lm_title")?.[0];
+    }
     constructor(props: any) {
         super(props);
         DocServer.GetRefField(this.props.documentId).then(action((f: Opt<Field>) => this._document = f as Doc));
@@ -740,9 +747,16 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
         this.props.glContainer.layoutManager.on("activeContentItemChanged", this.onActiveContentItemChanged);
         this.props.glContainer.on("tab", this.onActiveContentItemChanged);
         this.onActiveContentItemChanged();
+        this._tabReaction = reaction(() => ({ views: SelectionManager.SelectedDocuments(), color: StrCast(this._document?._backgroundColor, "white") }),
+            (data) => {
+                const selected = data.views.some(v => Doc.AreProtosEqual(v.props.Document, this._document));
+                this._tab.style.backgroundColor = selected ? data.color : "";
+            }
+        );
     }
 
     componentWillUnmount() {
+        this._tabReaction?.();
         this.props.glContainer.layoutManager.off("activeContentItemChanged", this.onActiveContentItemChanged);
         this.props.glContainer.off("tab", this.onActiveContentItemChanged);
     }
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 0ca86172f..fdd1b4e81 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -25,6 +25,8 @@ import { SelectionManager } from "../../util/SelectionManager";
 import { DocumentView } from "../nodes/DocumentView";
 import { ColorState } from "react-color";
 import { ObjectField } from "../../../fields/ObjectField";
+import RichTextMenu from "../nodes/formattedText/RichTextMenu";
+import { RichTextField } from "../../../fields/RichTextField";
 import { ScriptField } from "../../../fields/ScriptField";
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { DocUtils } from "../../documents/Documents";
@@ -47,7 +49,7 @@ export default class CollectionMenu extends AntimodeMenu {
 
     componentDidMount() {
         reaction(() => SelectionManager.SelectedDocuments().length && SelectionManager.SelectedDocuments()[0],
-            (doc) => doc && this.SetSelection(doc))
+            (doc) => doc && this.SetSelection(doc));
     }
 
     @action
@@ -160,7 +162,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         initialize: (button: Doc) => { button['target-docFilters'] = this.target._docFilters instanceof ObjectField ? ObjectField.MakeCopy(this.target._docFilters as any as ObjectField) : ""; },
     };
 
-    _freeform_commands = [this._viewCommand, this._saveFilterCommand, this._fitContentCommand, this._clusterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand];
+    @computed get _freeform_commands() { return Doc.UserDoc().noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; }
+
     _stacking_commands = [this._contentCommand, this._templateCommand];
     _masonry_commands = [this._contentCommand, this._templateCommand];
     _schema_commands = [this._templateCommand, this._narrativeCommand];
@@ -308,18 +311,32 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         </div>;
     }
 
+    @computed get selectedDocumentView() {
+        if (SelectionManager.SelectedDocuments().length) {
+            return SelectionManager.SelectedDocuments()[0];
+        } else { return undefined; }
+    }
+    @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
+    @computed get isText() {
+        if (this.selectedDoc) {
+            return this.selectedDoc[Doc.LayoutFieldKey(this.selectedDoc)] instanceof RichTextField;
+        }
+        else return false;
+    }
+
     render() {
         return (
             <div className="collectionMenu-cont" >
                 <div className="collectionMenu">
                     <div className="collectionViewBaseChrome">
-                        {this.props.type === CollectionViewType.Invalid || this.props.type === CollectionViewType.Docking ? (null) : this.viewModes}
-                        {this.props.type === CollectionViewType.Docking ? (null) : this.templateChrome}
-                        <div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: "grid" }}>
+                        {this.props.type === CollectionViewType.Invalid ||
+                            this.props.type === CollectionViewType.Docking || this.isText ? (null) : this.viewModes}
+                        {this.props.type === CollectionViewType.Docking || this.isText ? (null) : this.templateChrome}
+                        {/* <div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: "grid" }}>
                             <button className={"antimodeMenu-button"} onClick={this.toggleViewSpecs} >
                                 <FontAwesomeIcon icon="filter" size="lg" />
                             </button>
-                        </div>
+                        </div> */}
 
                         {this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? (null) : <button className={"antimodeMenu-button"} key="float"
                             style={{ backgroundColor: !this.props.docView.layoutDoc.isAnnotating ? "121212" : undefined, borderRight: "1px solid gray" }}
@@ -356,6 +373,20 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     @computed get childDocs() {
         return DocListCast(this.dataField);
     }
+
+    @computed get selectedDocumentView() {
+        if (SelectionManager.SelectedDocuments().length) {
+            return SelectionManager.SelectedDocuments()[0];
+        } else { return undefined; }
+    }
+    @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
+    @computed get isText() {
+        if (this.selectedDoc) {
+            return this.selectedDoc[Doc.LayoutFieldKey(this.selectedDoc)] instanceof RichTextField;
+        }
+        else return false;
+    }
+
     @undoBatch
     @action
     nextKeyframe = (): void => {
@@ -384,6 +415,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     miniMap = (): void => {
         this.document.hideMinimap = !this.document.hideMinimap;
     }
+
     private _palette = ["#D0021B", "#F5A623", "#F8E71C", "#8B572A", "#7ED321", "#417505", "#9013FE", "#4A90E2", "#50E3C2", "#B8E986", "#000000", "#4A4A4A", "#9B9B9B", "#FFFFFF", ""];
     private _width = ["1", "5", "10", "100"];
     // private _draw = ["⎯", "→", "↔︎", "∿", "↝", "↭", "ロ", "O", "∆"];
@@ -523,40 +555,44 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     }
 
     @computed get formatPane() {
-        return <button className="antimodeMenu-button" key="format" title="toggle foramatting pane"
-            onPointerDown={action(e => FormatShapePane.Instance.Pinned = !FormatShapePane.Instance.Pinned)}
-            style={{ backgroundColor: this._fillBtn ? "121212" : "" }}>
-            <FontAwesomeIcon icon="angle-double-right" size="lg" />
-        </button>;
+        // return <button className="antimodeMenu-button" key="format" title="toggle foramatting pane"
+        //     onPointerDown={action(e => FormatShapePane.Instance.Pinned = !FormatShapePane.Instance.Pinned)}
+        //     style={{ backgroundColor: this._fillBtn ? "121212" : "" }}>
+        //     <FontAwesomeIcon icon="angle-double-right" size="lg" />
+        // </button>;
+        return null;
     }
 
     render() {
         return !this.props.docView.layoutDoc ? (null) : <div className="collectionFreeFormMenu-cont">
-            {this.props.docView.props.renderDepth !== 0 ? (null) :
+            {this.props.docView.props.renderDepth !== 0 || this.isText ? (null) :
                 <div key="map" title="mini map" className="backKeyframe" onClick={this.miniMap}>
                     <FontAwesomeIcon icon={"map"} size={"lg"} />
                 </div>
             }
-            <div key="back" title="back frame" className="backKeyframe" onClick={this.prevKeyframe}>
+            {!!!this.isText ? <div key="back" title="back frame" className="backKeyframe" onClick={this.prevKeyframe}>
                 <FontAwesomeIcon icon={"caret-left"} size={"lg"} />
-            </div>
-            <div key="num" title="toggle view all" className="numKeyframe" style={{ backgroundColor: this.document.editing ? "#759c75" : "#c56565" }}
+            </div> : null}
+            {!!!this.isText ? <div key="num" title="toggle view all" className="numKeyframe" style={{ backgroundColor: this.document.editing ? "#759c75" : "#c56565" }}
                 onClick={action(() => this.document.editing = !this.document.editing)} >
                 {NumCast(this.document.currentFrame)}
-            </div>
-            <div key="fwd" title="forward frame" className="fwdKeyframe" onClick={this.nextKeyframe}>
+            </div> : null}
+            {!!!this.isText ? <div key="fwd" title="forward frame" className="fwdKeyframe" onClick={this.nextKeyframe}>
                 <FontAwesomeIcon icon={"caret-right"} size={"lg"} />
-            </div>
+            </div> : null}
 
-            {!this.props.isOverlay || this.document.type !== DocumentType.WEB ? (null) :
+            {!this.props.isOverlay || this.document.type !== DocumentType.WEB || this.isText ? (null) :
                 <button className={"antimodeMenu-button"} key="hypothesis"
-                    style={{ backgroundColor: !this.props.docView.layoutDoc.isAnnotating ? "121212" : undefined, borderRight: "1px solid gray" }}
+                    style={{
+                        backgroundColor: !this.props.docView.layoutDoc.isAnnotating ? "121212" : undefined,
+                        borderRight: "1px solid gray"
+                    }}
                     title="Use Hypothesis"
                     onClick={() => this.props.docView.layoutDoc.isAnnotating = !this.props.docView.layoutDoc.isAnnotating}>
                     <FontAwesomeIcon icon={["fab", "hire-a-helper"]} size={"lg"} />
                 </button>
             }
-            {!this.props.isOverlay || this.props.docView.layoutDoc.isAnnotating ?
+            {(!this.props.isOverlay || this.props.docView.layoutDoc.isAnnotating) && !this.isText ?
                 <>
                     {this.drawButtons}
                     {this.widthPicker}
@@ -566,6 +602,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
                 </> :
                 (null)
             }
+            {this.isText ? <RichTextMenu key="rich" /> : null}
         </div>;
     }
 }
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 5553bbbb7..f67e049fd 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -253,7 +253,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
             <div className="collectionSchema-headerMenu-group">
                 <div onClick={() => this.typesDropdownChange(!this._openTypes)}>
                     <label>Column type:</label>
-                    <FontAwesomeIcon icon={"caret-down"} size="sm" style={{ float: "right" }} />
+                    <FontAwesomeIcon icon={"caret-down"} size="lg" style={{ float: "right" }} />
                 </div>
                 {this._openTypes ? allColumnTypes : justColType}
             </div >
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 425dc90e4..a104ac011 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -227,6 +227,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
             addDocTab={this.addDocTab}
             bringToFront={returnFalse}
             ContentScaling={returnOne}
+            scriptContext={this.props.scriptContext}
             pinToPres={this.props.pinToPres}
         />;
     }
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 26d2ee8a3..68c233a16 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -351,7 +351,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
             {this.props.parent.Document._columnsHideIfEmpty ? (null) : headingView}
             {
                 this.collapsed ? (null) :
-                    <div style={{ marginTop: 5 }}>
+                    <div>
                         <div key={`${heading}-stack`} className={`collectionStackingView-masonry${singleColumn ? "Single" : "Grid"}`}
                             style={{
                                 padding: singleColumn ? `${columnYMargin}px ${0}px ${style.yMargin}px ${0}px` : `${columnYMargin}px ${0}px`,
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 9f78c15eb..c90e85271 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -296,7 +296,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                             const reg = new RegExp(Utils.prepend(""), "g");
                             const modHtml = srcUrl ? html.replace(reg, srcUrl) : html;
                             const htmlDoc = Docs.Create.HtmlDocument(modHtml, { ...options, title: "-web page-", _width: 300, _height: 300 });
-                            Doc.GetProto(htmlDoc)["data-text"] = Doc.GetProto(htmlDoc)["text"] = text;
+                            Doc.GetProto(htmlDoc)["data-text"] = Doc.GetProto(htmlDoc).text = text;
                             this.props.addDocument(htmlDoc);
                             if (srcWeb) {
                                 const focusNode = (SelectionManager.SelectedDocuments()[0].ContentDiv?.getElementsByTagName("iframe")[0].contentDocument?.getSelection()?.focusNode as any);
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index b8996c178..e5c4b9187 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -90,7 +90,10 @@ class TreeView extends React.Component<TreeViewProps> {
     get displayName() { return "TreeView(" + this.doc.title + ")"; }  // this makes mobx trace() statements more descriptive
     get defaultExpandedView() { return this.childDocs ? this.fieldKey : StrCast(this.doc.defaultExpandedView, this.noviceMode ? "layout" : "fields"); }
     @observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state
-    set treeViewOpen(c: boolean) { if (this.props.treeViewPreventOpen) this._overrideTreeViewOpen = c; else this.doc.treeViewOpen = this._overrideTreeViewOpen = c; }
+    set treeViewOpen(c: boolean) {
+        if (this.props.treeViewPreventOpen) this._overrideTreeViewOpen = c;
+        else this.doc.treeViewOpen = this._overrideTreeViewOpen = c;
+    }
     @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && !this.doc.treeViewPreventOpen && BoolCast(this.doc.treeViewOpen)) || this._overrideTreeViewOpen; }
     @computed get treeViewExpandedView() { return StrCast(this.doc.treeViewExpandedView, this.defaultExpandedView); }
     @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containingCollection.maxEmbedHeight, 200); }
@@ -101,7 +104,7 @@ class TreeView extends React.Component<TreeViewProps> {
         const layout = Doc.LayoutField(this.doc) instanceof Doc ? Doc.LayoutField(this.doc) as Doc : undefined;
         return ((this.props.dataDoc ? DocListCast(this.props.dataDoc[field]) : undefined) || // if there's a data doc for an expanded template, use it's data field
             (layout ? DocListCast(layout[field]) : undefined) || // else if there's a layout doc, display it's fields
-            DocListCast(this.doc[field])) as Doc[]; // otherwise use the document's data field
+            DocListCast(this.doc[field])); // otherwise use the document's data field
     }
     @computed get childDocs() { return this.childDocList(this.fieldKey); }
     @computed get childLinks() { return this.childDocList("links"); }
diff --git a/src/client/views/collections/CollectionView.scss b/src/client/views/collections/CollectionView.scss
index b630f9cf8..a5aef86de 100644
--- a/src/client/views/collections/CollectionView.scss
+++ b/src/client/views/collections/CollectionView.scss
@@ -24,6 +24,7 @@
         border-right: unset;
         z-index: 2;
     }
+
     .collectionTimeView-treeView {
         display: flex;
         flex-direction: column;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 7e7ea6786..62e8dc26a 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -78,6 +78,7 @@ export interface CollectionViewCustomProps {
     childLayoutTemplate?: () => Opt<Doc>;  // specify a layout Doc template to use for children of the collection
     childLayoutString?: string;  // specify a layout string to use for children of the collection
     childOpacity?: () => number;
+    hideFilter?: true;
 }
 
 export interface CollectionRenderProps {
@@ -309,7 +310,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
 
             const options = cm.findByDescription("Options...");
             const optionItems = options && "subitems" in options ? options.subitems : [];
-            optionItems.splice(0, 0, { description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" });
+            !Doc.UserDoc().noviceMode ? optionItems.splice(0, 0, { description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" }) : null;
             if (this.props.Document.childLayout instanceof Doc) {
                 optionItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, "onRight"), icon: "project-diagram" });
             }
@@ -368,7 +369,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
     get _facetWidth() { return NumCast(this.props.Document._facetWidth); }
     set _facetWidth(value) { this.props.Document._facetWidth = value; }
 
-    bodyPanelWidth = () => this.props.PanelWidth() - this.facetWidth();
+    bodyPanelWidth = () => this.props.PanelWidth();
     facetWidth = () => Math.max(0, Math.min(this.props.PanelWidth() - 25, this._facetWidth));
 
     @computed get dataDoc() {
@@ -490,6 +491,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
             return false;
         }), returnFalse, action(() => this._facetWidth = this.facetWidth() < 15 ? Math.min(this.props.PanelWidth() - 25, 200) : 0), false);
     }
+
     filterBackground = () => "rgba(105, 105, 105, 0.432)";
     get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; } // this makes the tree view collection ignore these filters (otherwise, the filters would filter themselves)
     @computed get scriptField() {
@@ -559,6 +561,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 </div>
             </div>;
     }
+
     childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null);
     childLayoutString = this.props.childLayoutString || StrCast(this.props.Document.childLayoutString);
 
@@ -588,11 +591,11 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                         Utils.CorsProxy(Cast(d.data, ImageField)!.url.href) : Cast(d.data, ImageField)!.url.href
                     :
                     ""))}
-            {(!this.props.isSelected() && !this.props.Document.forceActive) || this.props.Document.hideFilterView ? (null) :
+            {/* {(!this.props.isSelected() && !this.props.Document.forceActive) || this.props.Document.hideFilterView ? (null) :
                 <div className="collectionView-filterDragger" title="library View Dragger" onPointerDown={this.onPointerDown}
                     style={{ right: this.facetWidth() - 1, top: this.props.Document._viewType === CollectionViewType.Docking ? "25%" : "55%" }} />
             }
-            {this.facetWidth() < 10 ? (null) : this.filterView}
+            {this.facetWidth() < 10 ? (null) : this.filterView}  */}
         </div>);
     }
 }
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index 8c0b8de9d..532dd6abc 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -42,14 +42,14 @@ export class SelectorContextMenu extends React.Component<SelectorProps> {
     async fetchDocuments() {
         const aliases = (await SearchUtil.GetAliasesOfDocument(this.props.Document));
         const containerProtoSets = await Promise.all(aliases.map(async alias =>
-            await Promise.all((await SearchUtil.Search("", true, { fq: `data_l:"${alias[Id]}"` })).docs)));
+            ((await SearchUtil.Search("", true, { fq: `data_l:"${alias[Id]}"` })).docs)));
         const containerProtos = containerProtoSets.reduce((p, set) => { set.map(s => p.add(s)); return p; }, new Set<Doc>());
         const containerSets = await Promise.all(Array.from(containerProtos.keys()).map(async container => {
-            return (await SearchUtil.GetAliasesOfDocument(container));
+            return (SearchUtil.GetAliasesOfDocument(container));
         }));
         const containers = containerSets.reduce((p, set) => { set.map(s => p.add(s)); return p; }, new Set<Doc>());
         const doclayoutSets = await Promise.all(Array.from(containers.keys()).map(async (dp) => {
-            return (await SearchUtil.GetAliasesOfDocument(dp));
+            return (SearchUtil.GetAliasesOfDocument(dp));
         }));
         const doclayouts = Array.from(doclayoutSets.reduce((p, set) => { set.map(s => p.add(s)); return p; }, new Set<Doc>()).keys());
         runInAction(() => {
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index cde795098..7e2840c2c 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -148,7 +148,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     }
 
     @action
-    changeTitleMode = () => this._showTitleDropdown = !this._showTitleDropdown;
+    changeTitleMode = () => this._showTitleDropdown = !this._showTitleDropdown
 
     @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); }
     @computed get tableColumns(): Column<Doc>[] {
@@ -208,7 +208,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                 }}>
                 {col.heading}</div>;
 
-            const sortIcon = col.desc === undefined ? "circle" : col.desc === true ? "caret-down" : "caret-up";
+            const sortIcon = col.desc === undefined ? "caret-right" : col.desc === true ? "caret-down" : "caret-up";
 
             const header =
                 <div //className="collectionSchemaView-header"
@@ -224,12 +224,12 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                         {keysDropdown}
                     </div>
                     <div onClick={e => this.changeSorting(col)}
-                        style={{ paddingRight: "6px", display: "inline" }}>
+                        style={{ paddingRight: "6px", marginLeft: "4px", display: "inline" }}>
                         <FontAwesomeIcon icon={sortIcon} size="sm" />
                     </div>
                     <div onClick={e => this.props.openHeader(col, e.clientX, e.clientY)}
                         style={{ float: "right", paddingRight: "6px" }}>
-                        <FontAwesomeIcon icon={"compass"} size="sm" />
+                        <FontAwesomeIcon icon={"cog"} size="sm" />
                     </div>
                 </div>;
 
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 151acb64d..109808956 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1145,7 +1145,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
     @action
     componentDidMount() {
         super.componentDidMount?.();
-        this._layoutComputeReaction = reaction(() => { TraceMobx(); return this.doLayoutComputation },
+        this._layoutComputeReaction = reaction(() => this.doLayoutComputation,
             (elements) => this._layoutElements = elements || [],
             { fireImmediately: true, name: "doLayout" });
 
@@ -1240,13 +1240,15 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         const appearanceItems = appearance && "subitems" in appearance ? appearance.subitems : [];
         appearanceItems.push({ description: "Reset View", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: "compress-arrows-alt" });
         appearanceItems.push({ description: `${this.fitToContent ? "Make Zoomable" : "Scale to Window"}`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" });
-        appearanceItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" });
+        !Doc.UserDoc().noviceMode ? appearanceItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }) : null;
         !appearance && ContextMenu.Instance.addItem({ description: "Appearance...", subitems: appearanceItems, icon: "eye" });
 
         const viewctrls = ContextMenu.Instance.findByDescription("UI Controls...");
         const viewCtrlItems = viewctrls && "subitems" in viewctrls ? viewctrls.subitems : [];
-        viewCtrlItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " Snap Lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" });
-        viewCtrlItems.push({ description: (this.Document.useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" });
+
+
+        !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " Snap Lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }) : null;
+        !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (this.Document.useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }) : null;
         !viewctrls && ContextMenu.Instance.addItem({ description: "UI Controls...", subitems: viewCtrlItems, icon: "eye" });
 
         const options = ContextMenu.Instance.findByDescription("Options...");
@@ -1291,7 +1293,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
                         setTimeout(() => {
                             SearchUtil.Search(`{!join from=id to=proto_i}id:link*`, true, {}).then(docs => {
                                 docs.docs.forEach(d => LinkManager.Instance.addLink(d));
-                            })
+                            });
                         }, 2000); // need to give solr some time to update so that this query will find any link docs we've added.
                     }
                 }
diff --git a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
index ddc282e57..6263be261 100644
--- a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
+++ b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
@@ -13,7 +13,6 @@ import AntimodeMenu from "../../AntimodeMenu";
 import "./FormatShapePane.scss";
 import { undoBatch } from "../../../util/UndoManager";
 import { ColorState, SketchPicker } from 'react-color';
-import { DocumentView } from "../../../views/nodes/DocumentView"
 
 @observer
 export default class FormatShapePane extends AntimodeMenu {
@@ -124,12 +123,12 @@ export default class FormatShapePane extends AntimodeMenu {
                     console.log(ink);
                     if (ink) {
                         const newPoints: { X: number, Y: number }[] = [];
-                        for (var j = 0; j < ink.length; j++) {
+                        ink.forEach(i => {
                             // (new x — oldx) + (oldxpoint * newWidt)/oldWidth 
-                            const newX = (doc.x - oldX) + (ink[j].X * doc._width) / oldWidth;
-                            const newY = (doc.y - oldY) + (ink[j].Y * doc._height) / oldHeight;
+                            const newX = ((doc.x || 0) - oldX) + (i.X * (doc._width || 0)) / oldWidth;
+                            const newY = ((doc.y || 0) - oldY) + (i.Y * (doc._height || 0)) / oldHeight;
                             newPoints.push({ X: newX, Y: newY });
-                        }
+                        });
                         doc.data = new InkField(newPoints);
                     }
                 }
@@ -148,12 +147,12 @@ export default class FormatShapePane extends AntimodeMenu {
                     console.log(ink);
                     if (ink) {
                         const newPoints: { X: number, Y: number }[] = [];
-                        for (var j = 0; j < ink.length; j++) {
+                        ink.forEach(i => {
                             // (new x — oldx) + (oldxpoint * newWidt)/oldWidth 
-                            const newX = (doc.x - oldX) + (ink[j].X * doc._width) / oldWidth;
-                            const newY = (doc.y - oldY) + (ink[j].Y * doc._height) / oldHeight;
+                            const newX = ((doc.x || 0) - oldX) + (i.X * (doc._width || 0)) / oldWidth;
+                            const newY = ((doc.y || 0) - oldY) + (i.Y * (doc._height || 0)) / oldHeight;
                             newPoints.push({ X: newX, Y: newY });
-                        }
+                        });
                         doc.data = new InkField(newPoints);
                     }
                 }
@@ -191,11 +190,11 @@ export default class FormatShapePane extends AntimodeMenu {
                 if (ink) {
 
                     const newPoints: { X: number, Y: number }[] = [];
-                    for (var i = 0; i < ink.length; i++) {
-                        const newX = Math.cos(angle) * (ink[i].X - _centerPoints[index].X) - Math.sin(angle) * (ink[i].Y - _centerPoints[index].Y) + _centerPoints[index].X;
-                        const newY = Math.sin(angle) * (ink[i].X - _centerPoints[index].X) + Math.cos(angle) * (ink[i].Y - _centerPoints[index].Y) + _centerPoints[index].Y;
+                    ink.forEach(i => {
+                        const newX = Math.cos(angle) * (i.X - _centerPoints[index].X) - Math.sin(angle) * (i.Y - _centerPoints[index].Y) + _centerPoints[index].X;
+                        const newY = Math.sin(angle) * (i.X - _centerPoints[index].X) + Math.cos(angle) * (i.Y - _centerPoints[index].Y) + _centerPoints[index].Y;
                         newPoints.push({ X: newX, Y: newY });
-                    }
+                    });
                     doc.data = new InkField(newPoints);
                     const xs = newPoints.map(p => p.X);
                     const ys = newPoints.map(p => p.Y);
@@ -395,12 +394,12 @@ export default class FormatShapePane extends AntimodeMenu {
     @computed get widInput() { return this.inputBox("wid", this.shapeWid, (val: string) => this.shapeWid = val); }
     @computed get rotInput() { return this.inputBoxDuo("rot", this.shapeRot, (val: string) => { this.rotate(Number(val) - Number(this.shapeRot)); this.shapeRot = val; return true; }, "∠:", "rot", this.shapeRot, (val: string) => this.shapeRot = val, ""); }
 
-    @computed get XpsInput() { return this.inputBoxDuo("Xps", this.shapeXps, (val: string) => this.shapeXps = val, "X:", "Yps", this.shapeYps, (val: string) => this.shapeYps = val, "Y:"); }
     @computed get YpsInput() { return this.inputBox("Yps", this.shapeYps, (val: string) => this.shapeYps = val); }
 
     @computed get controlPoints() { return this.controlPointsButton(); }
     @computed get lockRatio() { return this.lockRatioButton(); }
     @computed get rotate90() { return this.rotate90Button(); }
+    @computed get XpsInput() { return this.inputBoxDuo("Xps", this.shapeXps, (val: string) => this.shapeXps = val, "X:", "Yps", this.shapeYps, (val: string) => this.shapeYps = val, "Y:"); }
 
 
     @computed get propertyGroupItems() {
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.scss b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
new file mode 100644
index 000000000..74f32275a
--- /dev/null
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
@@ -0,0 +1,620 @@
+.propertiesView {
+
+    background-color: rgb(205, 205, 205);
+    height: 100%;
+    font-family: "Noto Sans";
+    cursor: auto;
+
+    overflow-x: visible;
+    overflow-y: visible;
+
+    .propertiesView-title {
+        background-color: rgb(159, 159, 159);
+        text-align: center;
+        padding-top: 12px;
+        padding-bottom: 12px;
+        display: flex;
+        font-size: 18px;
+        font-weight: bold;
+        justify-content: center;
+
+        .propertiesView-title-icon {
+            width: 20px;
+            height: 20px;
+            padding-left: 38px;
+            margin-top: -5px;
+            right: 19;
+            position: absolute;
+
+            &:hover {
+                color: grey;
+                cursor: pointer;
+            }
+
+        }
+
+    }
+
+    .propertiesView-name {
+        border-bottom: 1px solid black;
+        padding: 8.5px;
+        font-size: 12.5px;
+
+        &:hover {
+            cursor: pointer;
+        }
+    }
+
+    .propertiesView-settings {
+        border-bottom: 1px solid black;
+        //padding: 8.5px;
+        font-size: 12.5px;
+        font-weight: bold;
+
+        .propertiesView-settings-title {
+            font-weight: bold;
+            font-size: 12.5px;
+            padding: 4px;
+            display: flex;
+            color: white;
+            padding-left: 8px;
+            background-color: rgb(51, 51, 51);
+
+            .propertiesView-settings-title-icon {
+                float: right;
+                right: 0;
+                position: absolute;
+                margin-left: 2px;
+                margin-right: 9px;
+
+                &:hover {
+                    cursor: pointer;
+                }
+            }
+        }
+
+        .propertiesView-settings-content {
+            margin-left: 12px;
+            padding-bottom: 10px;
+            padding-top: 8px;
+        }
+
+    }
+
+    .propertiesView-sharing {
+        border-bottom: 1px solid black;
+        //padding: 8.5px;
+
+        .propertiesView-sharing-title {
+            font-weight: bold;
+            font-size: 12.5px;
+            padding: 4px;
+            display: flex;
+            color: white;
+            padding-left: 8px;
+            background-color: rgb(51, 51, 51);
+
+            .propertiesView-sharing-title-icon {
+                float: right;
+                right: 0;
+                position: absolute;
+                margin-left: 2px;
+                margin-right: 9px;
+
+                &:hover {
+                    cursor: pointer;
+                }
+            }
+        }
+
+        .propertiesView-sharing-content {
+            font-size: 10px;
+            padding: 10px;
+            margin-left: 5px;
+        }
+    }
+
+    .propertiesView-appearance {
+        border-bottom: 1px solid black;
+        //padding: 8.5px;
+
+        .propertiesView-appearance-title {
+            font-weight: bold;
+            font-size: 12.5px;
+            padding: 4px;
+            display: flex;
+            color: white;
+            padding-left: 8px;
+            background-color: rgb(51, 51, 51);
+
+            .propertiesView-appearance-title-icon {
+                float: right;
+                right: 0;
+                position: absolute;
+                margin-left: 2px;
+                margin-right: 9px;
+
+                &:hover {
+                    cursor: pointer;
+                }
+            }
+        }
+
+        .propertiesView-appearance-content {
+            font-size: 10px;
+            padding: 10px;
+            margin-left: 5px;
+        }
+    }
+
+    .propertiesView-transform {
+        border-bottom: 1px solid black;
+        //padding: 8.5px;
+
+        .propertiesView-transform-title {
+            font-weight: bold;
+            font-size: 12.5px;
+            padding: 4px;
+            display: flex;
+            color: white;
+            padding-left: 8px;
+            background-color: rgb(51, 51, 51);
+
+            .propertiesView-transform-title-icon {
+                float: right;
+                right: 0;
+                position: absolute;
+                margin-left: 2px;
+                margin-right: 9px;
+
+                &:hover {
+                    cursor: pointer;
+                }
+            }
+        }
+
+        .propertiesView-transform-content {
+            font-size: 10px;
+            padding: 10px;
+            margin-left: 5px;
+        }
+    }
+
+    .notify-button {
+        padding: 2px;
+        width: 12px;
+        height: 12px;
+        background-color: black;
+        border-radius: 10px;
+        padding-left: 2px;
+        padding-right: 2px;
+        margin-top: 2px;
+        margin-left: 3px;
+
+        .notify-button-icon {
+            width: 6px;
+            height: 6.5px;
+            margin-left: .5px;
+        }
+
+        &:hover {
+            background-color: rgb(158, 158, 158);
+            cursor: pointer;
+        }
+    }
+
+    .expansion-button-icon {
+        width: 11px;
+        height: 11px;
+        color: black;
+        margin-left: 27px;
+
+        &:hover {
+            color: rgb(131, 131, 131);
+            cursor: pointer;
+        }
+    }
+
+    .propertiesView-sharingTable {
+
+        border: 1px solid black;
+        padding: 5px;
+        border-radius: 6px;
+        /* width: 170px; */
+        margin-right: 10px;
+        background-color: #ececec;
+        max-height: 130px;
+        overflow-y: scroll;
+
+        .propertiesView-sharingTable-item {
+
+            display: flex;
+            padding: 3px;
+            align-items: center;
+            border-bottom: 0.5px solid grey;
+
+            &:hover .propertiesView-sharingTable-item-name {
+                overflow-x: unset;
+                white-space: unset;
+                overflow-wrap: break-word;
+            }
+
+            .propertiesView-sharingTable-item-name {
+                font-weight: bold;
+                width: 80px;
+                overflow-x: hidden;
+                display: inline-block;
+                text-overflow: ellipsis;
+                white-space: nowrap;
+            }
+
+            .propertiesView-sharingTable-item-permission {
+                display: flex;
+                right: 34;
+                float: right;
+                position: absolute;
+
+                .permissions-select {
+                    z-index: 1;
+                    border: none;
+                    background-color: inherit;
+                    width: 75px;
+                    text-align: justify; // for Edge
+                    text-align-last: end;
+
+                    &:hover {
+                        cursor: pointer;
+                    }
+                }
+            }
+
+            &:last-child {
+                border-bottom: none;
+            }
+        }
+    }
+
+    .propertiesView-fields {
+        border-bottom: 1px solid black;
+        //padding: 8.5px;
+
+        .propertiesView-fields-title {
+            font-weight: bold;
+            font-size: 12.5px;
+            padding: 4px;
+            display: flex;
+            color: white;
+            padding-left: 8px;
+            background-color: rgb(51, 51, 51);
+
+            .propertiesView-fields-title-name {
+                font-size: 12.5px;
+                font-weight: bold;
+                white-space: nowrap;
+                width: 35px;
+                display: flex;
+            }
+
+            .propertiesView-fields-title-icon {
+                float: right;
+                right: 0;
+                position: absolute;
+                margin-left: 2px;
+                margin-right: 9px;
+
+                &:hover {
+                    cursor: pointer;
+                }
+            }
+        }
+
+        .propertiesView-fields-checkbox {
+            float: right;
+            height: 20px;
+            margin-top: -9px;
+
+            .propertiesView-fields-checkbox-text {
+                font-size: 7px;
+                margin-top: -10px;
+                margin-left: 6px;
+            }
+        }
+
+        .propertiesView-fields-content {
+            font-size: 10px;
+            margin-left: 2px;
+            padding: 10px;
+
+            &:hover {
+                cursor: pointer;
+            }
+        }
+    }
+
+    .field {
+        display: flex;
+        font-size: 7px;
+        background-color: #e8e8e8;
+        padding-right: 3px;
+        border: 0.5px solid grey;
+        border-radius: 5px;
+        padding-left: 3px;
+    }
+
+    .uneditable-field {
+        display: flex;
+        overflow-y: visible;
+        margin-bottom: 2px;
+
+        &:hover {
+            cursor: auto;
+        }
+    }
+
+    .propertiesView-layout {
+
+        .propertiesView-layout-title {
+            font-weight: bold;
+            font-size: 12.5px;
+            padding: 4px;
+            display: flex;
+            color: white;
+            padding-left: 8px;
+            background-color: rgb(51, 51, 51);
+
+            .propertiesView-layout-title-icon {
+                float: right;
+                right: 0;
+                position: absolute;
+                margin-left: 2px;
+                margin-right: 9px;
+
+                &:hover {
+                    cursor: pointer;
+                }
+            }
+        }
+
+        .propertiesView-layout-content {
+            overflow: hidden;
+            padding: 10px;
+        }
+
+    }
+}
+
+.inking-button {
+
+    display: flex;
+
+    .inking-button-points {
+        background-color: #333333;
+        padding: 7px;
+        border-radius: 7px;
+        margin-right: 32px;
+        width: 32;
+        height: 32;
+        padding-top: 9px;
+        margin-left: 18px;
+
+        &:hover {
+            background: rgb(131, 131, 131);
+            transform: scale(1.05);
+            cursor: pointer;
+        }
+    }
+
+    .inking-button-lock {
+        background-color: #333333;
+        padding: 7px;
+        border-radius: 7px;
+        margin-right: 32px;
+        width: 32;
+        height: 32;
+        padding-top: 9px;
+        padding-left: 10px;
+
+        &:hover {
+            background: rgb(131, 131, 131);
+            transform: scale(1.05);
+            cursor: pointer;
+        }
+    }
+
+    .inking-button-rotate {
+        background-color: #333333;
+        padding: 7px;
+        border-radius: 7px;
+        width: 32;
+        height: 32;
+        padding-top: 9px;
+        padding-left: 10px;
+
+        &:hover {
+            background: rgb(131, 131, 131);
+            transform: scale(1.05);
+            cursor: pointer;
+        }
+    }
+}
+
+.inputBox-duo {
+    display: flex;
+}
+
+.inputBox {
+
+    margin-top: 10px;
+    display: flex;
+    height: 19px;
+    margin-right: 15px;
+
+    .inputBox-title {
+        font-size: 12px;
+        padding-right: 5px;
+    }
+
+    .inputBox-input {
+        font-size: 10px;
+        width: 50px;
+        margin-right: 1px;
+        border-radius: 3px;
+
+        &:hover {
+            cursor: pointer;
+        }
+    }
+
+    .inputBox-button {
+
+        .inputBox-button-up {
+            background-color: #333333;
+            height: 9px;
+            padding-left: 3px;
+            padding-right: 3px;
+            padding-top: 1px;
+            padding-bottom: 1px;
+            border-radius: 1.5px;
+
+            &:hover {
+                background: rgb(131, 131, 131);
+                transform: scale(1.05);
+                cursor: pointer;
+            }
+        }
+
+        .inputBox-button-down {
+            background-color: #333333;
+            height: 9px;
+            padding-left: 3px;
+            padding-right: 3px;
+            padding-top: 1px;
+            padding-bottom: 1px;
+            border-radius: 1.5px;
+
+            &:hover {
+                background: rgb(131, 131, 131);
+                transform: scale(1.05);
+                cursor: pointer;
+            }
+        }
+
+    }
+}
+
+.color-palette {
+    width: 160px;
+    height: 360;
+}
+
+.strokeAndFill {
+    display: flex;
+    margin-top: 10px;
+
+    .fill {
+        margin-right: 40px;
+        display: flex;
+        padding-bottom: 7px;
+        margin-left: 35px;
+
+        .fill-title {
+            font-size: 12px;
+            margin-right: 2px;
+        }
+
+        .fill-button {
+            padding-top: 2px;
+            margin-top: -1px;
+        }
+    }
+
+    .stroke {
+        display: flex;
+
+        .stroke-title {
+            font-size: 12px;
+        }
+
+        .stroke-button {
+            padding-top: 2px;
+            margin-left: 2px;
+            margin-top: -1px;
+        }
+    }
+}
+
+.widthAndDash {
+
+    .width {
+        .width-top {
+            display: flex;
+
+            .width-title {
+                font-size: 12;
+                margin-right: 20px;
+                margin-left: 35px;
+                text-align: center;
+            }
+
+            .width-input {
+                margin-right: 30px;
+                margin-top: -10px;
+            }
+        }
+
+        .width-range {
+            margin-right: 1px;
+            margin-bottom: 6;
+        }
+    }
+
+    .arrows {
+
+        display: flex;
+        margin-bottom: 3px;
+
+        .arrows-head {
+
+            display: flex;
+            margin-right: 35px;
+
+            .arrows-head-title {
+                font-size: 10;
+            }
+
+            .arrows-head-input {
+                margin-left: 6px;
+                margin-top: 2px;
+            }
+        }
+
+        .arrows-tail {
+            display: flex;
+
+            .arrows-tail-title {
+                font-size: 10;
+            }
+
+            .arrows-tail-input {
+                margin-left: 6px;
+                margin-top: 2px;
+            }
+        }
+    }
+
+    .dashed {
+
+        display: flex;
+        margin-left: 74px;
+        margin-bottom: 6px;
+
+        .dashed-title {
+            font-size: 10;
+        }
+
+        .dashed-input {
+            margin-left: 6px;
+            margin-top: 2px;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
new file mode 100644
index 000000000..35c7fd425
--- /dev/null
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -0,0 +1,858 @@
+import React = require("react");
+import { observer } from "mobx-react";
+import "./PropertiesView.scss";
+import { observable, action, computed, runInAction } from "mobx";
+import { Doc, Field, DocListCast, WidthSym, HeightSym, AclSym, AclPrivate, AclReadonly, AclAddonly, AclEdit, AclAdmin, Opt } from "../../../../fields/Doc";
+import { DocumentView } from "../../nodes/DocumentView";
+import { ComputedField } from "../../../../fields/ScriptField";
+import { EditableView } from "../../EditableView";
+import { KeyValueBox } from "../../nodes/KeyValueBox";
+import { Cast, NumCast, StrCast } from "../../../../fields/Types";
+import { listSpec } from "../../../../fields/Schema";
+import { ContentFittingDocumentView } from "../../nodes/ContentFittingDocumentView";
+import { returnFalse, returnOne, emptyFunction, emptyPath, returnTrue, returnZero, returnEmptyFilter, Utils } from "../../../../Utils";
+import { Id } from "../../../../fields/FieldSymbols";
+import { Transform } from "../../../util/Transform";
+import { PropertiesButtons } from "../../PropertiesButtons";
+import { SelectionManager } from "../../../util/SelectionManager";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { Tooltip, Checkbox, Divider } from "@material-ui/core";
+import SharingManager from "../../../util/SharingManager";
+import { DocumentType } from "../../../documents/DocumentTypes";
+import FormatShapePane from "./FormatShapePane";
+import { SharingPermissions, GetEffectiveAcl } from "../../../../fields/util";
+import { InkField } from "../../../../fields/InkField";
+import { undoBatch } from "../../../util/UndoManager";
+import { ColorState, SketchPicker } from "react-color";
+import AntimodeMenu from "../../AntimodeMenu";
+import "./FormatShapePane.scss";
+import { discovery_v1 } from "googleapis";
+import { PresBox } from "../../nodes/PresBox";
+import { DocumentManager } from "../../../util/DocumentManager";
+
+
+interface PropertiesViewProps {
+    width: number;
+    height: number;
+    renderDepth: number;
+    ScreenToLocalTransform: () => Transform;
+    onDown: (event: any) => void;
+}
+
+@observer
+export class PropertiesView extends React.Component<PropertiesViewProps> {
+
+    @computed get MAX_EMBED_HEIGHT() { return 200; }
+
+    @computed get selectedDocumentView() {
+        if (SelectionManager.SelectedDocuments().length) {
+            return SelectionManager.SelectedDocuments()[0];
+        } else if (PresBox.Instance) {
+            const presSlide = PresBox.Instance._selectedArray[0];
+            const view = DocumentManager.Instance.getDocumentView(presSlide);
+            if (view) return view;
+        } else { return undefined; }
+    }
+    @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
+    @computed get dataDoc() { return this.selectedDocumentView?.dataDoc; }
+
+    @observable layoutFields: boolean = false;
+
+    @observable openActions: boolean = true;
+    @observable openSharing: boolean = true;
+    @observable openFields: boolean = true;
+    @observable openLayout: boolean = true;
+    @observable openAppearance: boolean = true;
+    @observable openTransform: boolean = true;
+
+    @computed get isInk() { return this.selectedDoc?.type === DocumentType.INK; }
+
+    @action
+    rtfWidth = () => {
+        if (this.selectedDoc) {
+            return Math.min(this.selectedDoc?.[WidthSym](), this.props.width - 20);
+        } else {
+            return 0;
+        }
+    }
+    @action
+    rtfHeight = () => {
+        if (this.selectedDoc) {
+            return this.rtfWidth() <= this.selectedDoc?.[WidthSym]() ? Math.min(this.selectedDoc?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
+        } else {
+            return 0;
+        }
+    }
+
+    @action
+    docWidth = () => {
+        if (this.selectedDoc) {
+            const layoutDoc = this.selectedDoc;
+            const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
+            if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.width - 20));
+            return NumCast(layoutDoc._nativeWidth) ? Math.min(layoutDoc[WidthSym](), this.props.width - 20) : this.props.width - 20;
+        } else {
+            return 0;
+        }
+    }
+
+    @action
+    docHeight = () => {
+        if (this.selectedDoc && this.dataDoc) {
+            const layoutDoc = this.selectedDoc;
+            return Math.max(70, Math.min(this.MAX_EMBED_HEIGHT, (() => {
+                const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
+                if (aspect) return this.docWidth() * aspect;
+                return layoutDoc._fitWidth ? (!this.dataDoc._nativeHeight ? NumCast(this.props.height) :
+                    Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, NumCast(layoutDoc._nativeHeight)) / NumCast(layoutDoc._nativeWidth,
+                        NumCast(this.props.height)))) :
+                    NumCast(layoutDoc._height) ? NumCast(layoutDoc._height) : 50;
+            })()));
+        } else {
+            return 0;
+        }
+    }
+
+    @computed get expandedField() {
+        if (this.dataDoc && this.selectedDoc) {
+            const ids: { [key: string]: string } = {};
+            const doc = this.layoutFields ? Doc.Layout(this.selectedDoc) : this.dataDoc;
+            doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
+            const rows: JSX.Element[] = [];
+            for (const key of Object.keys(ids).slice().sort()) {
+                const contents = doc[key];
+                if (key[0] === "#") {
+                    rows.push(<div style={{ display: "flex", overflowY: "visible", marginBottom: "2px" }} key={key}>
+                        <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key}</span>
+                    &nbsp;
+                </div>);
+                } else {
+                    let contentElement: (JSX.Element | null)[] | JSX.Element = [];
+                    contentElement = <EditableView key="editableView"
+                        contents={contents !== undefined ? Field.toString(contents as Field) : "null"}
+                        height={13}
+                        fontSize={10}
+                        GetValue={() => Field.toKeyValueString(doc, key)}
+                        SetValue={(value: string) => KeyValueBox.SetField(doc, key, value, true)}
+                    />;
+                    rows.push(<div style={{ display: "flex", overflowY: "visible", marginBottom: "-1px" }} key={key}>
+                        <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key + ":"}</span>
+                        &nbsp;
+                        {contentElement}
+                    </div>);
+                }
+            }
+            rows.push(<div className="field" key={"newKeyValue"} style={{ marginTop: "3px" }}>
+                <EditableView
+                    key="editableView"
+                    contents={"add key:value or #tags"}
+                    height={13}
+                    fontSize={10}
+                    GetValue={() => ""}
+                    SetValue={this.setKeyValue} />
+            </div>);
+            return rows;
+        }
+    }
+
+    @computed get noviceFields() {
+        if (this.dataDoc && this.selectedDoc) {
+            const ids: { [key: string]: string } = {};
+            const doc = this.dataDoc;
+            doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
+            const rows: JSX.Element[] = [];
+            for (const key of Object.keys(ids).slice().sort()) {
+                if (key[0] === key[0].toUpperCase() || key[0] === "#" || key === "author" || key === "creationDate" || key.indexOf("lastModified") !== -1) {
+                    const contents = doc[key];
+                    if (key[0] === "#") {
+                        rows.push(<div className="uneditable-field" key={key}>
+                            <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key}</span>
+                    &nbsp;
+                </div>);
+                    } else {
+                        const value = Field.toString(contents as Field);
+                        if (key === "author" || key === "creationDate" || key.indexOf("lastModified") !== -1) {
+                            rows.push(<div className="uneditable-field" key={key}>
+                                <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key + ": "}</span>
+                                <div style={{ whiteSpace: "nowrap", overflowX: "hidden" }}>{value}</div>
+                            </div>);
+                        } else {
+                            let contentElement: (JSX.Element | null)[] | JSX.Element = [];
+                            contentElement = <EditableView key="editableView"
+                                contents={contents !== undefined ? Field.toString(contents as Field) : "null"}
+                                height={13}
+                                fontSize={10}
+                                GetValue={() => Field.toKeyValueString(doc, key)}
+                                SetValue={(value: string) => KeyValueBox.SetField(doc, key, value, true)}
+                            />;
+
+                            rows.push(<div style={{ display: "flex", overflowY: "visible", marginBottom: "-1px" }} key={key}>
+                                <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key + ":"}</span>
+                            &nbsp;
+                            {contentElement}
+                            </div>);
+                        }
+                    }
+                }
+            }
+            rows.push(<div className="field" key={"newKeyValue"} style={{ marginTop: "3px" }}>
+                <EditableView
+                    key="editableView"
+                    contents={"add key:value or #tags"}
+                    height={13}
+                    fontSize={10}
+                    GetValue={() => ""}
+                    SetValue={this.setKeyValue} />
+            </div>);
+            return rows;
+        }
+    }
+
+
+    setKeyValue = (value: string) => {
+        if (this.selectedDoc && this.dataDoc) {
+            const doc = this.layoutFields ? Doc.Layout(this.selectedDoc) : this.dataDoc;
+            if (value.indexOf(":") !== -1) {
+                const newVal = value[0].toUpperCase() + value.substring(1, value.length);
+                KeyValueBox.SetField(doc, newVal.substring(0, newVal.indexOf(":")), newVal.substring(newVal.indexOf(":") + 1, newVal.length), true);
+                return true;
+            } else if (value[0] === "#") {
+                const newVal = value + `:'${value}'`;
+                KeyValueBox.SetField(doc, newVal.substring(0, newVal.indexOf(":")), newVal.substring(newVal.indexOf(":") + 1, newVal.length), true);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @computed get layoutPreview() {
+        if (this.selectedDoc) {
+            const layoutDoc = Doc.Layout(this.selectedDoc);
+            const panelHeight = StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : this.docHeight;
+            const panelWidth = StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : this.docWidth;
+            return <div style={{ display: "inline-block", height: panelHeight() }} key={this.selectedDoc[Id]}>
+                <ContentFittingDocumentView
+                    Document={layoutDoc}
+                    DataDoc={this.dataDoc}
+                    LibraryPath={emptyPath}
+                    renderDepth={this.props.renderDepth + 1}
+                    rootSelected={returnFalse}
+                    treeViewDoc={undefined}
+                    backgroundColor={() => "lightgrey"}
+                    fitToBox={false}
+                    FreezeDimensions={true}
+                    NativeWidth={layoutDoc.type ===
+                        StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : returnZero}
+                    NativeHeight={layoutDoc.type ===
+                        StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : returnZero}
+                    PanelWidth={panelWidth}
+                    PanelHeight={panelHeight}
+                    focus={returnFalse}
+                    ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+                    docFilters={returnEmptyFilter}
+                    ContainingCollectionDoc={undefined}
+                    ContainingCollectionView={undefined}
+                    addDocument={returnFalse}
+                    moveDocument={undefined}
+                    removeDocument={returnFalse}
+                    parentActive={() => false}
+                    whenActiveChanged={emptyFunction}
+                    addDocTab={returnFalse}
+                    pinToPres={emptyFunction}
+                    bringToFront={returnFalse}
+                    ContentScaling={returnOne}
+                    dontRegisterView={true}
+                />
+            </div>;
+        } else {
+            return null;
+        }
+    }
+
+    getPermissionsSelect(user: string) {
+        return <select className="permissions-select"
+            onChange={e => SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, this.selectedDoc!)}>
+            {Object.values(SharingPermissions).map(permission => {
+                return (
+                    <option key={permission} value={permission} selected={this.selectedDoc![`ACL-${user.replace(".", "_")}`] === permission}>
+                        {permission}
+                    </option>);
+            })}
+        </select>;
+    }
+
+    @computed get notifyIcon() {
+        return <Tooltip title={<><div className="dash-tooltip">Notify with message</div></>}>
+            <div className="notify-button">
+                <FontAwesomeIcon className="notify-button-icon" icon="bell" color="white" size="sm" />
+            </div>
+        </Tooltip>;
+    }
+
+    @computed get expansionIcon() {
+        return <Tooltip title={<><div className="dash-tooltip">{"Show more permissions"}</div></>}>
+            <div className="expansion-button" onPointerDown={() => {
+                if (this.selectedDocumentView) {
+                    SharingManager.Instance.open(this.selectedDocumentView);
+                }
+            }}>
+                <FontAwesomeIcon className="expansion-button-icon" icon="ellipsis-h" color="black" size="sm" />
+            </div>
+        </Tooltip>;
+    }
+
+    sharingItem(name: string, effectiveAcl: symbol, permission?: string) {
+        return <div className="propertiesView-sharingTable-item">
+            <div className="propertiesView-sharingTable-item-name" style={{ width: name !== "Me" ? "70px" : "80px" }}> {name} </div>
+            {name !== "Me" ? this.notifyIcon : null}
+            <div className="propertiesView-sharingTable-item-permission">
+                {effectiveAcl === AclAdmin && permission !== "Owner" ? this.getPermissionsSelect(name) : permission}
+                {permission === "Owner" ? this.expansionIcon : null}
+            </div>
+        </div>;
+    }
+
+    @computed get sharingTable() {
+        const AclMap = new Map<symbol, string>([
+            [AclPrivate, SharingPermissions.None],
+            [AclReadonly, SharingPermissions.View],
+            [AclAddonly, SharingPermissions.Add],
+            [AclEdit, SharingPermissions.Edit],
+            [AclAdmin, SharingPermissions.Admin]
+        ]);
+
+        const effectiveAcl = GetEffectiveAcl(this.selectedDoc!);
+        const tableEntries = [];
+
+        if (this.selectedDoc![AclSym]) {
+            for (const [key, value] of Object.entries(this.selectedDoc![AclSym])) {
+                const name = key.substring(4).replace("_", ".");
+                if (name !== Doc.CurrentUserEmail && name !== this.selectedDoc!.author) tableEntries.push(this.sharingItem(name, effectiveAcl, AclMap.get(value)!));
+            }
+        }
+
+        tableEntries.unshift(this.sharingItem("Me", effectiveAcl, Doc.CurrentUserEmail === this.selectedDoc!.author ? "Owner" : StrCast(this.selectedDoc![`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`])));
+        if (Doc.CurrentUserEmail !== this.selectedDoc!.author) tableEntries.unshift(this.sharingItem(StrCast(this.selectedDoc!.author), effectiveAcl, "Owner"));
+
+        return <div className="propertiesView-sharingTable">
+            {tableEntries}
+        </div>;
+    }
+
+    @computed get fieldsCheckbox() {
+        return <Checkbox
+            color="primary"
+            onChange={this.toggleCheckbox}
+            checked={this.layoutFields}
+        />;
+    }
+
+    @action
+    toggleCheckbox = () => {
+        this.layoutFields = !this.layoutFields;
+    }
+
+    @computed get editableTitle() {
+        return <EditableView
+            key="editableView"
+            contents={StrCast(this.selectedDoc?.title)}
+            height={25}
+            fontSize={14}
+            GetValue={() => StrCast(this.selectedDoc?.title)}
+            SetValue={this.setTitle} />;
+    }
+
+    @action
+    setTitle = (value: string) => {
+        if (this.dataDoc) {
+            this.selectedDoc && (this.selectedDoc.title = value);
+            KeyValueBox.SetField(this.dataDoc, "title", value, true);
+            return true;
+        }
+        return false;
+    }
+
+
+
+
+
+
+
+
+
+    @undoBatch
+    @action
+    rotate = (angle: number) => {
+        const _centerPoints: { X: number, Y: number }[] = [];
+        if (this.selectedDoc) {
+            const doc = this.selectedDoc;
+            if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
+                const ink = Cast(doc.data, InkField)?.inkData;
+                if (ink) {
+                    const xs = ink.map(p => p.X);
+                    const ys = ink.map(p => p.Y);
+                    const left = Math.min(...xs);
+                    const top = Math.min(...ys);
+                    const right = Math.max(...xs);
+                    const bottom = Math.max(...ys);
+                    _centerPoints.push({ X: left, Y: top });
+                }
+            }
+
+            var index = 0;
+            if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
+                doc.rotation = Number(doc.rotation) + Number(angle);
+                const ink = Cast(doc.data, InkField)?.inkData;
+                if (ink) {
+
+                    const newPoints: { X: number, Y: number }[] = [];
+                    for (var i = 0; i < ink.length; i++) {
+                        const newX = Math.cos(angle) * (ink[i].X - _centerPoints[index].X) - Math.sin(angle) * (ink[i].Y - _centerPoints[index].Y) + _centerPoints[index].X;
+                        const newY = Math.sin(angle) * (ink[i].X - _centerPoints[index].X) + Math.cos(angle) * (ink[i].Y - _centerPoints[index].Y) + _centerPoints[index].Y;
+                        newPoints.push({ X: newX, Y: newY });
+                    }
+                    doc.data = new InkField(newPoints);
+                    const xs = newPoints.map(p => p.X);
+                    const ys = newPoints.map(p => p.Y);
+                    const left = Math.min(...xs);
+                    const top = Math.min(...ys);
+                    const right = Math.max(...xs);
+                    const bottom = Math.max(...ys);
+
+                    doc._height = (bottom - top);
+                    doc._width = (right - left);
+                }
+                index++;
+            }
+        }
+    }
+
+    @observable _controlBtn: boolean = false;
+    @observable _lock: boolean = false;
+
+    @computed
+    get controlPointsButton() {
+        return <div className="inking-button">
+            <Tooltip title={<><div className="dash-tooltip">{"Edit points"}</div></>}>
+                <div className="inking-button-points" onPointerDown={action(() => this._controlBtn = !this._controlBtn)} style={{ backgroundColor: this._controlBtn ? "black" : "" }}>
+                    <FontAwesomeIcon icon="bezier-curve" color="white" size="lg" />
+                </div>
+            </Tooltip>
+            <Tooltip title={<><div className="dash-tooltip">{this._lock ? "Unlock points" : "Lock points"}</div></>}>
+                <div className="inking-button-lock" onPointerDown={action(() => this._lock = !this._lock)} >
+                    <FontAwesomeIcon icon={this._lock ? "unlock" : "lock"} color="white" size="lg" />
+                </div>
+            </Tooltip>
+            <Tooltip title={<><div className="dash-tooltip">{"Rotate 90˚"}</div></>}>
+                <div className="inking-button-rotate" onPointerDown={action(() => this.rotate(Math.PI / 2))}>
+                    <FontAwesomeIcon icon="undo" color="white" size="lg" />
+                </div>
+            </Tooltip>
+        </div>;
+    }
+
+    inputBox = (key: string, value: any, setter: (val: string) => {}, title: string) => {
+        return <div className="inputBox"
+            style={{
+                marginRight: title === "X:" ? "19px" : "",
+                marginLeft: title === "∠:" ? "39px" : ""
+            }}>
+            <div className="inputBox-title"> {title} </div>
+            <input className="inputBox-input"
+                type="text" value={value}
+                onChange={e => setter(e.target.value)} />
+            <div className="inputBox-button">
+                <div className="inputBox-button-up" key="up2"
+                    onPointerDown={undoBatch(action(() => this.upDownButtons("up", key)))} >
+                    <FontAwesomeIcon icon="caret-up" color="white" size="sm" />
+                </div>
+                <div className="inputbox-Button-down" key="down2"
+                    onPointerDown={undoBatch(action(() => this.upDownButtons("down", key)))} >
+                    <FontAwesomeIcon icon="caret-down" color="white" size="sm" />
+                </div>
+            </div>
+        </div>;
+    }
+
+    inputBoxDuo = (key: string, value: any, setter: (val: string) => {}, title1: string, key2: string, value2: any, setter2: (val: string) => {}, title2: string) => {
+        return <div className="inputBox-duo">
+            {this.inputBox(key, value, setter, title1)}
+            {title2 === "" ? (null) : this.inputBox(key2, value2, setter2, title2)}
+        </div>;
+    }
+
+    @action
+    upDownButtons = (dirs: string, field: string) => {
+        switch (field) {
+            case "rot": this.rotate((dirs === "up" ? .1 : -.1)); break;
+            // case "rot": this.selectedInk?.forEach(i => i.rootDoc.rotation = NumCast(i.rootDoc.rotation) + (dirs === "up" ? 0.1 : -0.1)); break;
+            case "Xps": this.selectedDoc && (this.selectedDoc.x = NumCast(this.selectedDoc?.x) + (dirs === "up" ? 10 : -10)); break;
+            case "Yps": this.selectedDoc && (this.selectedDoc.y = NumCast(this.selectedDoc?.y) + (dirs === "up" ? 10 : -10)); break;
+            case "stk": this.selectedDoc && (this.selectedDoc.strokeWidth = NumCast(this.selectedDoc?.strokeWidth) + (dirs === "up" ? .1 : -.1)); break;
+            case "wid":
+                const oldWidth = NumCast(this.selectedDoc?._width);
+                const oldHeight = NumCast(this.selectedDoc?._height);
+                const oldX = NumCast(this.selectedDoc?.x);
+                const oldY = NumCast(this.selectedDoc?.y);
+                this.selectedDoc && (this.selectedDoc._width = oldWidth + (dirs === "up" ? 10 : - 10));
+                this._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) / oldWidth * NumCast(this.selectedDoc?._height)));
+                const doc = this.selectedDoc;
+                if (doc?.type === DocumentType.INK && doc.x && doc.y && doc._height && doc._width) {
+                    console.log(doc.x, doc.y, doc._height, doc._width);
+                    const ink = Cast(doc.data, InkField)?.inkData;
+                    console.log(ink);
+                    if (ink) {
+                        const newPoints: { X: number, Y: number }[] = [];
+                        for (var j = 0; j < ink.length; j++) {
+                            // (new x — oldx) + (oldxpoint * newWidt)/oldWidth 
+                            const newX = (NumCast(doc.x) - oldX) + (ink[j].X * NumCast(doc._width)) / oldWidth;
+                            const newY = (NumCast(doc.y) - oldY) + (ink[j].Y * NumCast(doc._height)) / oldHeight;
+                            newPoints.push({ X: newX, Y: newY });
+                        }
+                        doc.data = new InkField(newPoints);
+                    }
+                }
+                break;
+            case "hgt":
+                const oWidth = NumCast(this.selectedDoc?._width);
+                const oHeight = NumCast(this.selectedDoc?._height);
+                const oX = NumCast(this.selectedDoc?.x);
+                const oY = NumCast(this.selectedDoc?.y);
+                this.selectedDoc && (this.selectedDoc._height = oHeight + (dirs === "up" ? 10 : - 10));
+                this._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) / oHeight * NumCast(this.selectedDoc?._width)));
+                const docu = this.selectedDoc;
+                if (docu?.type === DocumentType.INK && docu.x && docu.y && docu._height && docu._width) {
+                    console.log(docu.x, docu.y, docu._height, docu._width);
+                    const ink = Cast(docu.data, InkField)?.inkData;
+                    console.log(ink);
+                    if (ink) {
+                        const newPoints: { X: number, Y: number }[] = [];
+                        for (var j = 0; j < ink.length; j++) {
+                            // (new x — oldx) + (oldxpoint * newWidt)/oldWidth 
+                            const newX = (NumCast(docu.x) - oX) + (ink[j].X * NumCast(docu._width)) / oWidth;
+                            const newY = (NumCast(docu.y) - oY) + (ink[j].Y * NumCast(docu._height)) / oHeight;
+                            newPoints.push({ X: newX, Y: newY });
+                        }
+                        docu.data = new InkField(newPoints);
+                    }
+                }
+                break;
+        }
+    }
+
+    getField(key: string) {
+        //if (this.selectedDoc) {
+        return Field.toString(this.selectedDoc[key] as Field);
+        // } else {
+        //     return undefined as Opt<string>;
+        // }
+    }
+
+    @computed get shapeXps() { return this.getField("x"); }
+    @computed get shapeYps() { return this.getField("y"); }
+    @computed get shapeRot() { return this.getField("rotation"); }
+    @computed get shapeHgt() { return this.getField("_height"); }
+    @computed get shapeWid() { return this.getField("_width"); }
+    set shapeXps(value) { this.selectedDoc && (this.selectedDoc.x = Number(value)); }
+    set shapeYps(value) { this.selectedDoc && (this.selectedDoc.y = Number(value)); }
+    set shapeRot(value) { this.selectedDoc && (this.selectedDoc.rotation = Number(value)); }
+    set shapeWid(value) {
+        const oldWidth = NumCast(this.selectedDoc?._width);
+        this.selectedDoc && (this.selectedDoc._width = Number(value));
+        this._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) * NumCast(this.selectedDoc?._height)) / oldWidth);
+    }
+    set shapeHgt(value) {
+        const oldHeight = NumCast(this.selectedDoc?._height);
+        this.selectedDoc && (this.selectedDoc._height = Number(value));
+        this._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) * NumCast(this.selectedDoc?._width)) / oldHeight);
+    }
+
+    @computed get hgtInput() { return this.inputBoxDuo("hgt", this.shapeHgt, (val: string) => this.shapeHgt = val, "H:", "wid", this.shapeWid, (val: string) => this.shapeWid = val, "W:"); }
+    @computed get XpsInput() { return this.inputBoxDuo("Xps", this.shapeXps, (val: string) => this.shapeXps = val, "X:", "Yps", this.shapeYps, (val: string) => this.shapeYps = val, "Y:"); }
+    @computed get rotInput() { return this.inputBoxDuo("rot", this.shapeRot, (val: string) => { this.rotate(Number(val) - Number(this.shapeRot)); this.shapeRot = val; return true; }, "∠:", "rot", this.shapeRot, (val: string) => this.shapeRot = val, ""); }
+
+    @observable private _fillBtn = false;
+    @observable private _lineBtn = false;
+
+    private _lastFill = "#D0021B";
+    private _lastLine = "#D0021B";
+    private _lastDash: any = "2";
+
+    @computed get colorFil() { const ccol = this.getField("fillColor") || ""; ccol && (this._lastFill = ccol); return ccol; }
+    @computed get colorStk() { const ccol = this.getField("color") || ""; ccol && (this._lastLine = ccol); return ccol; }
+    set colorFil(value) { value && (this._lastFill = value); this.selectedDoc && (this.selectedDoc.fillColor = value ? value : undefined); }
+    set colorStk(value) { value && (this._lastLine = value); this.selectedDoc && (this.selectedDoc.color = value ? value : undefined); }
+
+    colorButton(value: string, setter: () => {}) {
+        return <div className="color-button" key="color" onPointerDown={undoBatch(action(e => setter()))}>
+            <div className="color-button-preview" style={{
+                backgroundColor: value ?? "121212", width: 15, height: 15,
+                display: value === "" || value === "transparent" ? "none" : ""
+            }} />
+            {value === "" || value === "transparent" ? <p style={{ fontSize: 25, color: "red", marginTop: -14, position: "fixed" }}>☒</p> : ""}
+        </div>;
+    }
+
+    @undoBatch
+    @action
+    switchStk = (color: ColorState) => {
+        const val = String(color.hex);
+        this.colorStk = val;
+        return true;
+    }
+    @undoBatch
+    @action
+    switchFil = (color: ColorState) => {
+        const val = String(color.hex);
+        this.colorFil = val;
+        return true;
+    }
+
+    colorPicker(setter: (color: string) => {}, type: string) {
+        return <SketchPicker onChange={type === "stk" ? this.switchStk : this.switchFil}
+            presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505',
+                '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B',
+                '#FFFFFF', '#f1efeb', 'transparent']}
+            color={type === "stk" ? this.colorStk : this.colorFil} />;
+    }
+
+    @computed get fillButton() { return this.colorButton(this.colorFil, () => { this._fillBtn = !this._fillBtn; this._lineBtn = false; return true; }); }
+    @computed get lineButton() { return this.colorButton(this.colorStk, () => { this._lineBtn = !this._lineBtn; this._fillBtn = false; return true; }); }
+
+    @computed get fillPicker() { return this.colorPicker((color: string) => this.colorFil = color, "fil"); }
+    @computed get linePicker() { return this.colorPicker((color: string) => this.colorStk = color, "stk"); }
+
+    @computed get strokeAndFill() {
+        return <div>
+            <div key="fill" className="strokeAndFill">
+                <div className="fill">
+                    <div className="fill-title">Fill:</div>
+                    <div className="fill-button">{this.fillButton}</div>
+                </div>
+                <div className="stroke">
+                    <div className="stroke-title"> Stroke: </div>
+                    <div className="stroke-button">{this.lineButton}</div>
+                </div>
+            </div>
+            {this._fillBtn ? this.fillPicker : ""}
+            {this._lineBtn ? this.linePicker : ""}
+        </div>;
+    }
+
+    @computed get solidStk() { return this.selectedDoc?.color && (!this.selectedDoc?.strokeDash || this.selectedDoc?.strokeDash === "0") ? true : false; }
+    @computed get dashdStk() { return this.selectedDoc?.strokeDash || ""; }
+    @computed get unStrokd() { return this.selectedDoc?.color ? true : false; }
+    @computed get widthStk() { return this.getField("strokeWidth") || "1"; }
+    @computed get markHead() { return this.getField("strokeStartMarker") || ""; }
+    @computed get markTail() { return this.getField("strokeEndMarker") || ""; }
+    set solidStk(value) { this.dashdStk = ""; this.unStrokd = !value; }
+    set dashdStk(value) {
+        value && (this._lastDash = value) && (this.unStrokd = false);
+        this.selectedDoc && (this.selectedDoc.strokeDash = value ? this._lastDash : undefined);
+    }
+    set widthStk(value) { this.selectedDoc && (this.selectedDoc.strokeWidth = Number(value)); }
+    set unStrokd(value) { this.colorStk = value ? "" : this._lastLine; }
+    set markHead(value) { this.selectedDoc && (this.selectedDoc.strokeStartMarker = value); }
+    set markTail(value) { this.selectedDoc && (this.selectedDoc.strokeEndMarker = value); }
+
+
+    @computed get stkInput() { return this.regInput("stk", this.widthStk, (val: string) => this.widthStk = val); }
+
+
+    regInput = (key: string, value: any, setter: (val: string) => {}) => {
+        return <div className="inputBox">
+            <input className="inputBox-input"
+                type="text" value={value}
+                onChange={e => setter(e.target.value)} />
+            <div className="inputBox-button">
+                <div className="inputBox-button-up" key="up2"
+                    onPointerDown={undoBatch(action(() => this.upDownButtons("up", key)))} >
+                    <FontAwesomeIcon icon="caret-up" color="white" size="sm" />
+                </div>
+                <div className="inputbox-Button-down" key="down2"
+                    onPointerDown={undoBatch(action(() => this.upDownButtons("down", key)))} >
+                    <FontAwesomeIcon icon="caret-down" color="white" size="sm" />
+                </div>
+            </div>
+        </div>;
+    }
+
+    @computed get widthAndDash() {
+        return <div className="widthAndDash">
+            <div className="width">
+                <div className="width-top">
+                    <div className="width-title">Width:</div>
+                    <div className="width-input">{this.stkInput}</div>
+                </div>
+                <input className="width-range" type="range"
+                    defaultValue={Number(this.widthStk)} min={1} max={100}
+                    onChange={undoBatch(action((e) => this.widthStk = e.target.value))} />
+            </div>
+
+            <div className="arrows">
+                <div className="arrows-head">
+                    <div className="arrows-head-title" >Arrow Head: </div>
+                    <input key="markHead" className="arrows-head-input" type="checkbox"
+                        checked={this.markHead !== ""}
+                        onChange={undoBatch(action(() => this.markHead = this.markHead ? "" : "arrow"))} />
+                </div>
+                <div className="arrows-tail">
+                    <div className="arrows-tail-title" >Arrow End: </div>
+                    <input key="markTail" className="arrows-tail-input" type="checkbox"
+                        checked={this.markTail !== ""}
+                        onChange={undoBatch(action(() => this.markTail = this.markTail ? "" : "arrow"))} />
+                </div>
+            </div>
+            <div className="dashed">
+                <div className="dashed-title">Dash:</div>
+                <input key="markHead" className="dashed-input"
+                    type="checkbox" checked={this.dashdStk === "2"}
+                    onChange={this.changeDash} />
+            </div>
+        </div>;
+    }
+
+    @undoBatch @action
+    changeDash = () => {
+        const dash = this.dashdStk;
+        if (dash === "2") {
+            this.dashdStk = "0";
+        } else {
+            this.dashdStk = "2";
+        }
+    }
+
+    @computed get appearanceEditor() {
+        return <div className="appearance-editor">
+            {this.widthAndDash}
+            {this.strokeAndFill}
+        </div>;
+    }
+
+    @computed get transformEditor() {
+        return <div className="transform-editor">
+            {this.controlPointsButton}
+            {this.hgtInput}
+            {this.XpsInput}
+            {this.rotInput}
+        </div>;
+    }
+
+    render() {
+
+        if (!this.selectedDoc) {
+            return <div className="propertiesView" style={{ width: this.props.width }}>
+                <div className="propertiesView-title" style={{ width: this.props.width, paddingLeft: 6 }}>
+                    No Document Selected
+            </div> </div>;
+        }
+
+        const novice = Doc.UserDoc().noviceMode;
+
+        return <div className="propertiesView" style={{ width: this.props.width }} >
+            <div className="propertiesView-title" style={{ width: this.props.width }}>
+                Properties
+                <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}>
+                    <FontAwesomeIcon icon="times" color="black" size="sm" />
+                </div>
+            </div>
+            <div className="propertiesView-name">
+                {this.editableTitle}
+            </div>
+            <div className="propertiesView-settings">
+                <div className="propertiesView-settings-title"
+                    onPointerDown={() => runInAction(() => { this.openActions = !this.openActions; })}
+                    style={{ backgroundColor: this.openActions ? "black" : "" }}>
+                    Actions
+                    <div className="propertiesView-settings-title-icon">
+                        <FontAwesomeIcon icon={this.openActions ? "caret-down" : "caret-right"} size="lg" color="white" />
+                    </div>
+                </div>
+                {this.openActions ? <div className="propertiesView-settings-content">
+                    <PropertiesButtons />
+                </div> : null}
+            </div>
+            <div className="propertiesView-sharing">
+                <div className="propertiesView-sharing-title"
+                    onPointerDown={() => runInAction(() => { this.openSharing = !this.openSharing; })}
+                    style={{ backgroundColor: this.openSharing ? "black" : "" }}>
+                    Sharing {"&"} Permissions
+                    <div className="propertiesView-sharing-title-icon">
+                        <FontAwesomeIcon icon={this.openSharing ? "caret-down" : "caret-right"} size="lg" color="white" />
+                    </div>
+                </div>
+                {this.openSharing ? <div className="propertiesView-sharing-content">
+                    {this.sharingTable}
+                </div> : null}
+            </div>
+
+
+
+
+            {this.isInk ? <div className="propertiesView-appearance">
+                <div className="propertiesView-appearance-title"
+                    onPointerDown={() => runInAction(() => { this.openAppearance = !this.openAppearance; })}
+                    style={{ backgroundColor: this.openAppearance ? "black" : "" }}>
+                    Appearance
+                    <div className="propertiesView-appearance-title-icon">
+                        <FontAwesomeIcon icon={this.openAppearance ? "caret-down" : "caret-right"} size="lg" color="white" />
+                    </div>
+                </div>
+                {this.openAppearance ? <div className="propertiesView-appearance-content">
+                    {this.appearanceEditor}
+                </div> : null}
+            </div> : null}
+
+            {this.isInk ? <div className="propertiesView-transform">
+                <div className="propertiesView-transform-title"
+                    onPointerDown={() => runInAction(() => { this.openTransform = !this.openTransform; })}
+                    style={{ backgroundColor: this.openTransform ? "black" : "" }}>
+                    Transform
+                    <div className="propertiesView-transform-title-icon">
+                        <FontAwesomeIcon icon={this.openTransform ? "caret-down" : "caret-right"} size="lg" color="white" />
+                    </div>
+                </div>
+                {this.openTransform ? <div className="propertiesView-transform-content">
+                    {this.transformEditor}
+                </div> : null}
+            </div> : null}
+
+
+
+
+
+            <div className="propertiesView-fields">
+                <div className="propertiesView-fields-title"
+                    onPointerDown={() => runInAction(() => { this.openFields = !this.openFields; })}
+                    style={{ backgroundColor: this.openFields ? "black" : "" }}>
+                    <div className="propertiesView-fields-title-name">
+                        Fields {"&"} Tags
+                        <div className="propertiesView-fields-title-icon">
+                            <FontAwesomeIcon icon={this.openFields ? "caret-down" : "caret-right"} size="lg" color="white" />
+                        </div>
+                    </div>
+                </div>
+                {!novice && this.openFields ? <div className="propertiesView-fields-checkbox">
+                    {this.fieldsCheckbox}
+                    <div className="propertiesView-fields-checkbox-text">Layout</div>
+                </div> : null}
+                {this.openFields ?
+                    <div className="propertiesView-fields-content">
+                        {novice ? this.noviceFields : this.expandedField}
+                    </div> : null}
+            </div>
+            <div className="propertiesView-layout">
+                <div className="propertiesView-layout-title"
+                    onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })}
+                    style={{ backgroundColor: this.openLayout ? "black" : "" }}>
+                    Layout
+                    <div className="propertiesView-layout-title-icon"
+                        onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })}>
+                        <FontAwesomeIcon icon={this.openLayout ? "caret-down" : "caret-right"} size="lg" color="white" />
+                    </div>
+                </div>
+                {this.openLayout ? <div className="propertiesView-layout-content">{this.layoutPreview}</div> : null}
+            </div>
+        </div>;
+    }
+} 
\ No newline at end of file
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index d1c839c3b..0aabf5319 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -182,7 +182,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
         switch (this.props.destinationDoc.type) {
             case DocumentType.IMG: destinationIcon = "image"; break;
             case DocumentType.COMPARISON: destinationIcon = "columns"; break;
-            case DocumentType.RTF: destinationIcon = "font"; break;
+            case DocumentType.RTF: destinationIcon = "sticky-note"; break;
             case DocumentType.COL: destinationIcon = "folder"; break;
             case DocumentType.WEB: destinationIcon = "globe-asia"; break;
             case DocumentType.SCREENSHOT: destinationIcon = "photo-video"; break;
@@ -196,6 +196,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
             case DocumentType.DOCHOLDER: destinationIcon = "expand"; break;
             case DocumentType.VID: destinationIcon = "video"; break;
             case DocumentType.INK: destinationIcon = "pen-nib"; break;
+            case DocumentType.PDF: destinationIcon = "file"; break;
             default: destinationIcon = "question"; break;
         }
 
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 6081def5d..f7e253f42 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -78,6 +78,9 @@ export class ContentFittingDocumentView extends React.Component<DocumentViewProp
 
     render() {
         TraceMobx();
+        if (this.props.Document.title === "Archive") {
+            console.log("");
+        }
         return (<div className="contentFittingDocumentView" style={{
             width: Math.abs(this.centeringYOffset) > 0.001 ? "auto" : this.props.PanelWidth(),
             height: Math.abs(this.centeringOffset) > 0.0001 ? "auto" : this.props.PanelHeight(),
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index e8173d103..e3f258b8d 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -18,6 +18,7 @@ import { DocHolderBox } from "./DocHolderBox";
 import { DocumentViewProps } from "./DocumentView";
 import "./DocumentView.scss";
 import { FontIconBox } from "./FontIconBox";
+import { MenuIconBox } from "./MenuIconBox";
 import { FieldView, FieldViewProps } from "./FieldView";
 import { FormattedTextBox } from "./formattedText/FormattedTextBox";
 import { ImageBox } from "./ImageBox";
@@ -189,7 +190,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
                 blacklistedAttrs={[]}
                 renderInWrapper={false}
                 components={{
-                    FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, LabelBox, SliderBox, FieldView,
+                    FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, MenuIconBox, LabelBox, SliderBox, FieldView,
                     CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
                     PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, QueryBox,
                     ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, DocHolderBox, LinkBox, ScriptingBox,
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 3b91ac6b5..198a90225 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -198,8 +198,11 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
             // }))} 
             >
 
+                {/* {this.props.InMenu ? this.props.StartLink ? <FontAwesomeIcon className="documentdecorations-icon" icon="link" size="sm" /> :
+                    <FontAwesomeIcon className="documentdecorations-icon" icon="hand-paper" size="sm" /> : links.length} */}
+
                 {this.props.InMenu ? this.props.StartLink ? <FontAwesomeIcon className="documentdecorations-icon" icon="link" size="sm" /> :
-                    <FontAwesomeIcon className="documentdecorations-icon" icon="hand-paper" size="sm" /> : links.length}
+                    link : links.length}
 
             </div>
             {DocumentLinksButton.StartLink && this.props.InMenu && !!!this.props.StartLink && DocumentLinksButton.StartLink !== this.props.View ? <div className={"documentLinksButton-endLink"}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b3bfadf4f..22a2bb8fe 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -94,6 +94,8 @@ export interface DocumentViewProps {
     layoutKey?: string;
     radialMenu?: String[];
     display?: string;
+    relative?: boolean;
+    scriptContext?: any;
 }
 
 @observer
@@ -287,7 +289,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     onClick = action((e: React.MouseEvent | React.PointerEvent) => {
-        if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick &&
+        if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick && this.props.renderDepth >= 0 &&
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
             let stopPropagate = true;
             let preventDefault = true;
@@ -319,10 +321,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 const func = () => this.onClickHandler.script.run({
                     this: this.layoutDoc,
                     self: this.rootDoc,
+                    scriptContext: this.props.scriptContext,
                     thisContainer: this.props.ContainingCollectionDoc,
                     shiftKey: e.shiftKey
                 }, console.log);
-                if (this.props.Document !== Doc.UserDoc()["dockedBtn-undo"] && this.props.Document !== Doc.UserDoc()["dockedBtn-redo"]) {
+                if (!Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()["dockedBtn-undo"] as Doc) && !Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()["dockedBtn-redo"] as Doc)) {
                     UndoManager.RunInBatch(func, "on click");
                 } else func();
             } else if (this.Document["onClick-rawScript"] && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) {// bcz: hack? don't edit a script if you're clicking on a scripting box itself
@@ -584,6 +587,18 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
     }
 
+
+    @undoBatch
+    noOnClick = (): void => {
+        this.Document.ignoreClick = false;
+        this.Document.isLinkButton = false;
+    }
+
+    @undoBatch
+    toggleDetail = (): void => {
+        this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.Document.layoutKey}")`);
+    }
+
     @undoBatch @action
     drop = async (e: Event, de: DragManager.DropEvent) => {
         if (this.props.Document === Doc.UserDoc().activeWorkspace) {
@@ -660,6 +675,14 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
     }
 
+    @action
+    onCopy = () => {
+        const copy = Doc.MakeCopy(this.props.Document, true);
+        copy.x = NumCast(this.props.Document.x) + NumCast(this.props.Document._width);
+        copy.y = NumCast(this.props.Document.y) + 30;
+        this.props.addDocument?.(copy);
+    }
+
     @action
     onContextMenu = async (e: React.MouseEvent | Touch): Promise<void> => {
         // the touch onContextMenu is button 0, the pointer onContextMenu is button 2
@@ -704,14 +727,14 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const existingOnClick = cm.findByDescription("OnClick...");
         const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
         onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" });
-        onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.Document.layoutKey}")`), icon: "window-restore" });
+        onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.Document.layoutKey}")`), icon: "concierge-bell" });
         onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" });
-        onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: () => this.toggleFollowLink("inPlace", true, false), icon: "concierge-bell" });
-        !this.Document.isLinkButton && onClicks.push({ description: "Follow Link on Right", event: () => this.toggleFollowLink("onRight", false, false), icon: "concierge-bell" });
-        onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? "Remove Click Behavior" : "Follow Link", event: () => this.toggleFollowLink(undefined, false, false), icon: "concierge-bell" });
-        onClicks.push({ description: (this.Document.isPushpin ? "Remove" : "Make") + " Pushpin", event: () => this.toggleFollowLink(undefined, false, true), icon: "snowflake" });
-        onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "edit" });
-        !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, addDivider: true, subitems: onClicks, icon: "hand-point-right" });
+        onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: () => this.toggleFollowLink("inPlace", true, false), icon: "link" });
+        !this.Document.isLinkButton && onClicks.push({ description: "Follow Link on Right", event: () => this.toggleFollowLink("onRight", false, false), icon: "link" });
+        onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? "Remove Click Behavior" : "Follow Link", event: () => this.toggleFollowLink(undefined, false, false), icon: "link" });
+        onClicks.push({ description: (this.Document.isPushpin ? "Remove" : "Make") + " Pushpin", event: () => this.toggleFollowLink(undefined, false, true), icon: "map-pin" });
+        onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "terminal" });
+        !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, addDivider: true, subitems: onClicks, icon: "mouse-pointer" });
 
         const funcs: ContextMenuProps[] = [];
         if (this.layoutDoc.onDragStart) {
@@ -724,6 +747,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const more = cm.findByDescription("More...");
         const moreItems = more && "subitems" in more ? more.subitems : [];
         moreItems.push({ description: "Download document", icon: "download", event: async () => Doc.Zip(this.props.Document) });
+        moreItems.push({ description: "Share", event: () => SharingManager.Instance.open(this), icon: "users" });
+        //moreItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
+        moreItems.push({ description: "Create an Alias", event: () => this.onCopy(), icon: "copy" });
         if (!Doc.UserDoc().noviceMode) {
             moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" });
             moreItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" });
@@ -735,16 +761,18 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             }
             moreItems.push({ description: "Copy ID", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "fingerprint" });
         }
+        //GetEffectiveAcl(this.props.Document) === AclEdit && moreItems.push({ description: "Delete", event: this.deleteClicked, icon: "trash" });
+
         const effectiveAcl = GetEffectiveAcl(this.props.Document);
         (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) && moreItems.push({ description: "Delete", event: this.deleteClicked, icon: "trash" });
-        moreItems.push({ description: "Share", event: () => SharingManager.Instance.open(this), icon: "external-link-alt" });
+
         !more && cm.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" });
         cm.moveAfter(cm.findByDescription("More...")!, cm.findByDescription("OnClick...")!);
 
         const help = cm.findByDescription("Help...");
         const helpItems: ContextMenuProps[] = help && "subitems" in help ? help.subitems : [];
+        !Doc.UserDoc().novice && helpItems.push({ description: "Show Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
         helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument(Utils.prepend("/assets/cheat-sheet.pdf"), { _width: 300, _height: 300 }), "onRight"), icon: "keyboard" });
-        helpItems.push({ description: "Show Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
         helpItems.push({ description: "Print Document in Console", event: () => console.log(this.props.Document), icon: "hand-point-right" });
         cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" });
 
@@ -786,8 +814,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
     @computed.struct get linkOffset() { return [-15, 0]; }
     @computed get contents() {
+        const pos = this.props.relative ? "relative " : "absolute";
         TraceMobx();
-        return (<div style={{ position: "absolute", width: "100%", height: "100%" }}>
+        return (<div style={{ width: "100%", height: "100%" }}>
             <DocumentContentsView key={1}
                 docFilters={this.props.docFilters}
                 ContainingCollectionView={this.props.ContainingCollectionView}
@@ -823,6 +852,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 ChromeHeight={this.chromeHeight}
                 isSelected={this.isSelected}
                 select={this.select}
+                scriptContext={this.props.scriptContext}
                 onClick={this.onClickFunc}
                 layoutKey={this.finalLayoutKey} />
             {this.layoutDoc.hideAllLinks ? (null) : this.allAnchors}
@@ -877,8 +907,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
     @computed get innards() {
         TraceMobx();
+        const pos = this.props.relative ? "relative" : undefined;
         if (this.props.treeViewDoc && !this.props.LayoutTemplateString?.includes("LinkAnchorBox")) {  // this happens when the document is a tree view label (but not an anchor dot)
-            return <div className="documentView-treeView" style={{ maxWidth: this.props.PanelWidth() || undefined }}>
+            return <div className="documentView-treeView" style={{
+                maxWidth: this.props.PanelWidth() || undefined,
+                position: pos
+            }}>
                 {StrCast(this.props.Document.title)}
                 {this.allAnchors}
             </div>;
@@ -1003,7 +1037,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 background: finalColor,
                 opacity: finalOpacity,
                 fontFamily: StrCast(this.Document._fontFamily, "inherit"),
-                fontSize: Cast(this.Document._fontSize, "string", null)
+                fontSize: Cast(this.Document._fontSize, "string", null),
             }}>
             {this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ? <>
                 {this.innards}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 5d5bc1d73..1b4151bd8 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -61,6 +61,7 @@ export interface FieldViewProps {
     color?: string;
     xMargin?: number;
     yMargin?: number;
+    scriptContext?: any;
 }
 
 @observer
diff --git a/src/client/views/nodes/FontIconBox.scss b/src/client/views/nodes/FontIconBox.scss
index 5b85d8b0b..69c835318 100644
--- a/src/client/views/nodes/FontIconBox.scss
+++ b/src/client/views/nodes/FontIconBox.scss
@@ -16,7 +16,7 @@
         position: absolute;
         text-align: center;
         font-size: 8px;
-        margin-top:4px;
+        //margin-top:4px;
         letter-spacing: normal;
         left: 0;
         overflow: hidden;
diff --git a/src/client/views/nodes/MenuIconBox.scss b/src/client/views/nodes/MenuIconBox.scss
new file mode 100644
index 000000000..1b72f5a8f
--- /dev/null
+++ b/src/client/views/nodes/MenuIconBox.scss
@@ -0,0 +1,49 @@
+.menuButton {
+    //padding: 7px;
+    padding-left: 7px;
+    width: 100%;
+    width: 60px;
+    height: 70px;
+
+    .menuButton-wrap {
+        width: 45px;
+        /* padding: 5px; */
+        touch-action: none;
+        background: black;
+        transform-origin: top left;
+        /* margin-bottom: 5px; */
+        margin-top: 5px;
+        margin-right: 25px;
+        border-radius: 8px;
+
+        &:hover {
+            background: rgb(61, 61, 61);
+            cursor: pointer;
+        }
+    }
+
+    .menuButton-label {
+        color: white;
+        margin-right: 4px;
+        border-radius: 8px;
+        width: 42px;
+        position: relative;
+        text-align: center;
+        font-size: 8px;
+        margin-top: 1px;
+        letter-spacing: normal;
+        padding: 3px;
+        background-color: inherit;
+    }
+
+    .menuButton-icon {
+        width: auto;
+        height: 35px;
+        padding: 5px;
+    }
+
+    svg {
+        width: 95% !important;
+        height: 95%;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/MenuIconBox.tsx b/src/client/views/nodes/MenuIconBox.tsx
new file mode 100644
index 000000000..0aa7b327e
--- /dev/null
+++ b/src/client/views/nodes/MenuIconBox.tsx
@@ -0,0 +1,33 @@
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { createSchema, makeInterface } from '../../../fields/Schema';
+import { StrCast } from '../../../fields/Types';
+import { DocComponent } from '../DocComponent';
+import { FieldView, FieldViewProps } from './FieldView';
+import './MenuIconBox.scss';
+const MenuIconSchema = createSchema({
+    icon: "string"
+});
+
+type MenuIconDocument = makeInterface<[typeof MenuIconSchema]>;
+const MenuIconDocument = makeInterface(MenuIconSchema);
+@observer
+export class MenuIconBox extends DocComponent<FieldViewProps, MenuIconDocument>(MenuIconDocument) {
+    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(MenuIconBox, fieldKey); }
+    _ref: React.RefObject<HTMLButtonElement> = React.createRef();
+
+    render() {
+
+        const color = this.props.backgroundColor?.(this.props.Document) === "lightgrey" ? "black" : "white";
+        const menuBTN = <div className="menuButton" style={{ backgroundColor: this.props.backgroundColor?.(this.props.Document) }}>
+            <div className="menuButton-wrap"
+                style={{ backgroundColor: this.props.backgroundColor?.(this.props.Document) }} >
+                <FontAwesomeIcon className="menuButton-icon" icon={StrCast(this.dataDoc.icon, "user") as any} color={color} size="lg" />
+                <div className="menuButton-label" style={{ color: color }}> {this.dataDoc.title} </div>
+            </div>
+        </div>;
+
+        return menuBTN;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index c04c6c409..97f223c02 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -32,6 +32,7 @@ import { conformsTo } from "lodash";
 import { translate } from "googleapis/build/src/apis/translate";
 import { DragManager, dropActionType } from "../../util/DragManager";
 import { actionAsync } from "mobx-utils";
+import { SelectionManager } from "../../util/SelectionManager";
 
 type PresBoxSchema = makeInterface<[typeof documentSchema]>;
 const PresBoxDocument = makeInterface(documentSchema);
@@ -260,7 +261,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
         const srcContext = await DocCastAsync(targetDoc.context);
         const presCollection = Cast(this.layoutDoc.presCollection, Doc, null);
-        const collectionDocView = presCollection ? DocumentManager.Instance.getDocumentView(presCollection) : undefined;
+        const collectionDocView = presCollection ? await DocumentManager.Instance.getDocumentView(presCollection) : undefined;
         if (this.itemIndex >= 0) {
             if (targetDoc) {
                 if (srcContext) this.layoutDoc.presCollection = srcContext;
@@ -496,6 +497,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     selectElement = (doc: Doc) => {
         // this._selectedArray = [];
         this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.itemIndex));
+        const view = DocumentManager.Instance.getDocumentView(doc);
+        view && SelectionManager.SelectDoc(view, false);
         // this._selectedArray.push(this.childDocs[this.childDocs.indexOf(doc)]);
         // console.log(this._selectedArray);
     }
@@ -504,8 +507,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     @action
     multiSelect = (doc: Doc, ref: HTMLElement) => {
         this._selectedArray.push(this.childDocs[this.childDocs.indexOf(doc)]);
-        const ele = ref.getElementsByClassName("stacking");
         this._eleArray.push(ref);
+        const view = DocumentManager.Instance.getDocumentView(doc);
+        view && SelectionManager.SelectDoc(view, true);
     }
 
     //Shift click
@@ -517,6 +521,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             for (let i = Math.min(this.itemIndex, this.childDocs.indexOf(doc)); i <= Math.max(this.itemIndex, this.childDocs.indexOf(doc)); i++) {
                 this._selectedArray.push(this.childDocs[i]);
                 this._eleArray.push(ref);
+                const view = DocumentManager.Instance.getDocumentView(doc);
+                view && SelectionManager.SelectDoc(view, true);
             }
         }
     }
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index 958a37568..8ae71c035 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -190,7 +190,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
             }
             list.map(c => c.heading).indexOf(this._fieldKey) === -1 && list.push(new SchemaHeaderField(this._fieldKey, "#f1efeb"));
             list.map(c => c.heading).indexOf("text") === -1 && list.push(new SchemaHeaderField("text", "#f1efeb"));
-            alias._pivotField = this._fieldKey;
+            alias._pivotField = this._fieldKey.startsWith("#") ? "#" : this._fieldKey;
             this.props.tbox.props.addDocTab(alias, "onRight");
         }
     }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 627c6e363..fc65f34eb 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1267,7 +1267,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         this.doLinkOnDeselect();
 
         // move the richtextmenu offscreen
-        if (!RichTextMenu.Instance.Pinned) RichTextMenu.Instance.delayHide();
+        //if (!RichTextMenu.Instance.Pinned) RichTextMenu.Instance.delayHide();
     }
 
     _lastTimedMark: Mark | undefined = undefined;
@@ -1346,7 +1346,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     @computed get sidebarColor() { return StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "transparent")); }
     render() {
         TraceMobx();
-        const scale = this.props.ContentScaling() * NumCast(this.layoutDoc._viewScale, 1);
+        const scale = this.props.hideOnLeave ? 1 : this.props.ContentScaling() * NumCast(this.layoutDoc._viewScale, 1);
         const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : "";
         const interactive = Doc.GetSelectedTool() === InkTool.None && !this.layoutDoc.isBackground;
         setTimeout(() => this._editorView && RichTextMenu.Instance.updateFromDash(this._editorView, undefined, this.props), this.props.isSelected() ? 10 : 0); // need to make sure that we update a text box that is selected after updating the one that was deselected
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 7ccbfa051..f76707a79 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -77,7 +77,8 @@ export default class RichTextMenu extends AntimodeMenu {
         super(props);
         RichTextMenu.Instance = this;
         this._canFade = false;
-        this.Pinned = BoolCast(Doc.UserDoc()["menuRichText-pinned"]);
+        //this.Pinned = BoolCast(Doc.UserDoc()["menuRichText-pinned"]);
+        this.Pinned = true;
 
         this.fontSizeOptions = [
             { mark: schema.marks.pFontSize.create({ fontSize: 7 }), title: "Set font size", label: "7pt", command: this.changeFontSize },
@@ -529,7 +530,7 @@ export default class RichTextMenu extends AntimodeMenu {
 
     indentParagraph(state: EditorState<any>, dispatch: any) {
         var tr = state.tr;
-        let headin = false;
+        const heading = false;
         state.doc.nodesBetween(state.selection.from, state.selection.to, (node, pos, parent, index) => {
             if (node.type === schema.nodes.paragraph || node.type === schema.nodes.heading) {
                 const nodeval = node.attrs.indent ? Number(node.attrs.indent) : undefined;
@@ -539,7 +540,7 @@ export default class RichTextMenu extends AntimodeMenu {
             }
             return true;
         });
-        !headin && dispatch?.(tr);
+        !heading && dispatch?.(tr);
         return true;
     }
 
@@ -920,16 +921,22 @@ export default class RichTextMenu extends AntimodeMenu {
     render() {
         TraceMobx();
         const row1 = <div className="antimodeMenu-row" key="row 1" style={{ display: this.collapsed ? "none" : undefined }}>{[
-            !this.collapsed ? this.getDragger() : (null),
-            !this.Pinned ? (null) : <div key="frag1"> {[
-                this.createButton("bold", "Bold", this.boldActive, toggleMark(schema.marks.strong)),
-                this.createButton("italic", "Italic", this.italicsActive, toggleMark(schema.marks.em)),
-                this.createButton("underline", "Underline", this.underlineActive, toggleMark(schema.marks.underline)),
-                this.createButton("strikethrough", "Strikethrough", this.strikethroughActive, toggleMark(schema.marks.strikethrough)),
-                this.createButton("superscript", "Superscript", this.superscriptActive, toggleMark(schema.marks.superscript)),
-                this.createButton("subscript", "Subscript", this.subscriptActive, toggleMark(schema.marks.subscript)),
-                <div className="richTextMenu-divider" key="divider" />
-            ]}</div>,
+            //!this.collapsed ? this.getDragger() : (null),
+            // !this.Pinned ? (null) : <div key="frag1"> {[
+            //     this.createButton("bold", "Bold", this.boldActive, toggleMark(schema.marks.strong)),
+            //     this.createButton("italic", "Italic", this.italicsActive, toggleMark(schema.marks.em)),
+            //     this.createButton("underline", "Underline", this.underlineActive, toggleMark(schema.marks.underline)),
+            //     this.createButton("strikethrough", "Strikethrough", this.strikethroughActive, toggleMark(schema.marks.strikethrough)),
+            //     this.createButton("superscript", "Superscript", this.superscriptActive, toggleMark(schema.marks.superscript)),
+            //     this.createButton("subscript", "Subscript", this.subscriptActive, toggleMark(schema.marks.subscript)),
+            //     <div className="richTextMenu-divider" key="divider" />
+            // ]}</div>,
+            this.createButton("bold", "Bold", this.boldActive, toggleMark(schema.marks.strong)),
+            this.createButton("italic", "Italic", this.italicsActive, toggleMark(schema.marks.em)),
+            this.createButton("underline", "Underline", this.underlineActive, toggleMark(schema.marks.underline)),
+            this.createButton("strikethrough", "Strikethrough", this.strikethroughActive, toggleMark(schema.marks.strikethrough)),
+            this.createButton("superscript", "Superscript", this.superscriptActive, toggleMark(schema.marks.superscript)),
+            this.createButton("subscript", "Subscript", this.subscriptActive, toggleMark(schema.marks.subscript)),
             this.createColorButton(),
             this.createHighlighterButton(),
             this.createLinkButton(),
@@ -957,16 +964,16 @@ export default class RichTextMenu extends AntimodeMenu {
                 this.createButton("minus", "Horizontal Rule", undefined, this.insertHorizontalRule),
                 <div className="richTextMenu-divider" key="divider 5" />,]}
             </div>
-            <div key="collapser">
-                {/* <div key="collapser">
+            {/* <div key="collapser">
+                {<div key="collapser">
                     <button className="antimodeMenu-button" key="collapse menu" title="Collapse menu" onClick={this.toggleCollapse} style={{ backgroundColor: this.collapsed ? "#121212" : "", width: 25 }}>
                         <FontAwesomeIcon icon="chevron-left" size="lg" style={{ transitionProperty: "transform", transitionDuration: "0.3s", transform: `rotate(${this.collapsed ? 180 : 0}deg)` }} />
                     </button>
-                </div> */}
+                </div> }
                 <button className="antimodeMenu-button" key="pin menu" title="Pin menu" onClick={this.toggleMenuPin} style={{ backgroundColor: this.Pinned ? "#121212" : "", display: this.collapsed ? "none" : undefined }}>
                     <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transitionProperty: "transform", transitionDuration: "0.1s", transform: `rotate(${this.Pinned ? 45 : 0}deg)` }} />
                 </button>
-            </div>
+            </div> */}
         </div>;
 
         return (
diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts
index 0eca6d753..1616500f6 100644
--- a/src/client/views/nodes/formattedText/nodes_rts.ts
+++ b/src/client/views/nodes/formattedText/nodes_rts.ts
@@ -79,14 +79,14 @@ export const nodes: { [index: string]: NodeSpec } = {
         { tag: "h5", attrs: { level: 5 } },
         { tag: "h6", attrs: { level: 6 } }],
         toDOM(node) {
-            var dom = toParagraphDOM(node) as any;
-            var level = node.attrs.level || 1;
+            const dom = toParagraphDOM(node) as any;
+            const level = node.attrs.level || 1;
             dom[0] = 'h' + level;
             return dom;
         },
         getAttrs(dom: any) {
-            var attrs = getParagraphNodeAttrs(dom) as any;
-            var level = Number(dom.nodeName.substring(1)) || 1;
+            const attrs = getParagraphNodeAttrs(dom) as any;
+            const level = Number(dom.nodeName.substring(1)) || 1;
             attrs.level = level;
             return attrs;
         }
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 43e74ff61..85fc63074 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -528,10 +528,10 @@ export namespace Doc {
             const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
             const field = ProxyField.WithoutProxy(() => doc[key]);
             const copyObjectField = async (field: ObjectField) => {
-                const list = await Cast(doc[key], listSpec(Doc));
+                const list = Cast(doc[key], listSpec(Doc));
                 const docs = list && (await DocListCastAsync(list))?.filter(d => d instanceof Doc);
                 if (docs !== undefined && docs.length) {
-                    const clones = await Promise.all(docs.map(async d => await Doc.makeClone(d as Doc, cloneMap, rtfs, exclusions, dontCreate)));
+                    const clones = await Promise.all(docs.map(async d => Doc.makeClone(d, cloneMap, rtfs, exclusions, dontCreate)));
                     !dontCreate && assignKey(new List<Doc>(clones));
                 } else if (doc[key] instanceof Doc) {
                     assignKey(key.includes("layout[") ? undefined : key.startsWith("layout") ? doc[key] as Doc : await Doc.makeClone(doc[key] as Doc, cloneMap, rtfs, exclusions, dontCreate)); // reference documents except copy documents that are expanded teplate fields 
@@ -625,7 +625,7 @@ export namespace Doc {
         Array.from(map.entries()).forEach(f => docs[f[0]] = f[1]);
         const docString = JSON.stringify({ id: doc[Id], docs }, replacer);
 
-        var zip = new JSZip();
+        const zip = new JSZip();
 
         zip.file(doc.title + ".json", docString);
 
diff --git a/src/server/ActionUtilities.ts b/src/server/ActionUtilities.ts
index 60f66c878..fd9bc0c83 100644
--- a/src/server/ActionUtilities.ts
+++ b/src/server/ActionUtilities.ts
@@ -1,11 +1,11 @@
-import { readFile, writeFile, exists, mkdir, unlink, createWriteStream } from 'fs';
-import { ExecOptions } from 'shelljs';
 import { exec } from 'child_process';
-import * as path from 'path';
-import * as rimraf from "rimraf";
-import { yellow, Color } from 'colors';
+import { Color, yellow } from 'colors';
+import { createWriteStream, exists, mkdir, readFile, unlink, writeFile } from 'fs';
 import * as nodemailer from "nodemailer";
 import { MailOptions } from "nodemailer/lib/json-transport";
+import * as path from 'path';
+import * as rimraf from "rimraf";
+import { ExecOptions } from 'shelljs';
 import Mail = require('nodemailer/lib/mailer');
 
 const projectRoot = path.resolve(__dirname, "../../");
diff --git a/src/server/ApiManagers/UtilManager.ts b/src/server/ApiManagers/UtilManager.ts
index e2cd88726..e657866ce 100644
--- a/src/server/ApiManagers/UtilManager.ts
+++ b/src/server/ApiManagers/UtilManager.ts
@@ -6,7 +6,6 @@ import { exec } from 'child_process';
 
 // const recommender = new Recommender();
 // recommender.testModel();
-import executeImport from "../../scraping/buxton/final/BuxtonImporter";
 
 export default class UtilManager extends ApiManager {
 
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index 2bf4c1956..890fb6f6d 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -1,23 +1,22 @@
-import { unlinkSync, createWriteStream, readFileSync, rename, writeFile, existsSync } from 'fs';
-import { Utils } from '../Utils';
-import * as path from 'path';
-import * as sharp from 'sharp';
-import request = require('request-promise');
+import { red } from 'colors';
 import { ExifImage } from 'exif';
-import { Opt } from '../fields/Doc';
-import { AcceptibleMedia, Upload } from './SharedMediaTypes';
-import { filesDirectory, publicDirectory } from '.';
 import { File } from 'formidable';
+import { createWriteStream, existsSync, readFileSync, rename, unlinkSync, writeFile } from 'fs';
+import * as path from 'path';
 import { basename } from "path";
-import { createIfNotExists } from './ActionUtilities';
+import * as sharp from 'sharp';
+import { Stream } from 'stream';
+import { filesDirectory, publicDirectory } from '.';
+import { Opt } from '../fields/Doc';
 import { ParsedPDF } from "../server/PdfTypes";
+import { Utils } from '../Utils';
+import { createIfNotExists } from './ActionUtilities';
+import { clientPathToFile, Directory, pathToDirectory, serverPathToFile } from './ApiManagers/UploadManager';
+import { resolvedServerUrl } from "./server_Initialization";
+import { AcceptibleMedia, Upload } from './SharedMediaTypes';
+import request = require('request-promise');
 const parse = require('pdf-parse');
-import { Directory, serverPathToFile, clientPathToFile, pathToDirectory } from './ApiManagers/UploadManager';
-import { red } from 'colors';
-import { Stream } from 'stream';
-import { resolvedPorts } from './server_Initialization';
 const requestImageSize = require("../client/util/request-image-size");
-import { resolvedServerUrl } from "./server_Initialization";
 
 export enum SizeSuffix {
     Small = "_s",
diff --git a/src/server/GarbageCollector.ts b/src/server/GarbageCollector.ts
index 24745cbb4..a9a3b0481 100644
--- a/src/server/GarbageCollector.ts
+++ b/src/server/GarbageCollector.ts
@@ -1,9 +1,9 @@
-import { Database } from './database';
-
-import * as path from 'path';
 import * as fs from 'fs';
+import * as path from 'path';
+import { Database } from './database';
 import { Search } from './Search';
 
+
 function addDoc(doc: any, ids: string[], files: { [name: string]: string[] }) {
     for (const key in doc) {
         if (!doc.hasOwnProperty(key)) {
diff --git a/src/server/MemoryDatabase.ts b/src/server/MemoryDatabase.ts
index 1f1d702d9..7f477327e 100644
--- a/src/server/MemoryDatabase.ts
+++ b/src/server/MemoryDatabase.ts
@@ -1,6 +1,7 @@
-import { IDatabase, DocumentsCollection } from './IDatabase';
-import { Transferable } from './Message';
+import { DH_CHECK_P_NOT_SAFE_PRIME } from 'constants';
 import * as mongodb from 'mongodb';
+import { DocumentsCollection, IDatabase } from './IDatabase';
+import { Transferable } from './Message';
 
 export class MemoryDatabase implements IDatabase {
 
diff --git a/src/server/Message.ts b/src/server/Message.ts
index ff0381fd3..59b24cd82 100644
--- a/src/server/Message.ts
+++ b/src/server/Message.ts
@@ -1,6 +1,6 @@
-import { Utils } from "../Utils";
 import { Point } from "../pen-gestures/ndollar";
 import { AnalysisResult, ImportResults } from "../scraping/buxton/final/BuxtonImporter";
+import { Utils } from "../Utils";
 
 export class Message<T> {
     private _name: string;
diff --git a/src/server/ProcessFactory.ts b/src/server/ProcessFactory.ts
index acb8b3a99..63682368f 100644
--- a/src/server/ProcessFactory.ts
+++ b/src/server/ProcessFactory.ts
@@ -1,8 +1,8 @@
-import { existsSync, mkdirSync } from "fs";
-import { pathFromRoot, fileDescriptorFromStream } from './ActionUtilities';
-import rimraf = require("rimraf");
 import { ChildProcess, spawn, StdioOptions } from "child_process";
+import { existsSync, mkdirSync } from "fs";
 import { Stream } from "stream";
+import { fileDescriptorFromStream, pathFromRoot } from './ActionUtilities';
+import rimraf = require("rimraf");
 
 export namespace ProcessFactory {
 
diff --git a/src/server/Recommender.ts b/src/server/Recommender.ts
deleted file mode 100644
index 935ec3871..000000000
--- a/src/server/Recommender.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-// //import { Doc } from "../fields/Doc";
-// //import { StrCast } from "../fields/Types";
-// //import { List } from "../fields/List";
-// //import { CognitiveServices } from "../client/cognitive_services/CognitiveServices";
-
-// // var w2v = require('word2vec');
-// var assert = require('assert');
-// 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');
-
-// //http://gnuwin32.sourceforge.net/packages/make.htm
-
-// export class Recommender {
-
-//     private _model: any;
-//     static Instance: Recommender;
-//     private dimension: number = 0;
-//     private choice: string = ""; // Tensorflow or Word2Vec
-
-//     constructor() {
-//         Recommender.Instance = this;
-//     }
-
-//     /***
-//      * Loads pre-trained model from TF
-//      */
-
-//     public async loadTFModel() {
-//         let self = this;
-//         return new Promise(res => {
-//             use.load().then(model => {
-//                 self.choice = "TF";
-//                 self._model = model;
-//                 self.dimension = 512;
-//                 res(model);
-//             });
-//         }
-
-//         );
-//     }
-
-//     /***
-//      * Loads pre-trained model from word2vec
-//      */
-
-//     // private loadModel(): Promise<any> {
-//     //     let self = this;
-//     //     return new Promise(res => {
-//     //         w2v.loadModel("./node_modules/word2vec/examples/fixtures/vectors.txt", function (err: any, model: any) {
-//     //             self.choice = "WV";
-//     //             self._model = model;
-//     //             self.dimension = model.size;
-//     //             res(model);
-//     //         });
-//     //     });
-//     // }
-
-//     /***
-//      * Testing
-//      */
-
-//     public async testModel() {
-//         if (!this._model) {
-//             await this.loadTFModel();
-//         }
-//         if (this._model) {
-//             if (this.choice === "WV") {
-//                 let similarity = this._model.similarity('father', 'mother');
-//             }
-//             else if (this.choice === "TF") {
-//                 const model = this._model as use.UniversalSentenceEncoder;
-//                 // Embed an array of sentences.
-//                 const sentences = [
-//                     'Hello.',
-//                     'How are you?'
-//                 ];
-//                 const embeddings = await this.vectorize(sentences);
-//                 if (embeddings) embeddings.print(true /*verbose*/);
-//                 // model.embed(sentences).then(embeddings => {
-//                 //     // `embeddings` is a 2D tensor consisting of the 512-dimensional embeddings for each sentence.
-//                 //     // So in this example `embeddings` has the shape [2, 512].
-//                 //     embeddings.print(true /* verbose */);
-//                 // });
-//             }
-//         }
-//         else {
-//             console.log("model not found :(");
-//         }
-//     }
-
-//     /***
-//      * Uses model to convert words to vectors
-//      */
-
-//     public async vectorize(text: string[]): Promise<Tensor | undefined> {
-//         if (!this._model) {
-//             await this.loadTFModel();
-//         }
-//         if (this._model) {
-//             if (this.choice === "WV") {
-//                 let word_vecs = this._model.getVectors(text);
-//                 return word_vecs;
-//             }
-//             else if (this.choice === "TF") {
-//                 const model = this._model as use.UniversalSentenceEncoder;
-//                 return new Promise<Tensor>(res => {
-//                     model.embed(text).then(embeddings => {
-//                         res(embeddings);
-//                     });
-//                 });
-
-//             }
-//         }
-//     }
-
-//     // public async trainModel() {
-//     //     w2v.word2vec("./node_modules/word2vec/examples/eng_news-typical_2016_1M-sentences.txt", './node_modules/word2vec/examples/my_phrases.txt', {
-//     //         cbow: 1,
-//     //         size: 200,
-//     //         window: 8,
-//     //         negative: 25,
-//     //         hs: 0,
-//     //         sample: 1e-4,
-//     //         threads: 20,
-//     //         iter: 200,
-//     //         minCount: 2
-//     //     });
-//     // }
-
-// }
diff --git a/src/server/RouteManager.ts b/src/server/RouteManager.ts
index 1a2340afc..78b75d6be 100644
--- a/src/server/RouteManager.ts
+++ b/src/server/RouteManager.ts
@@ -1,8 +1,8 @@
-import RouteSubscriber from "./RouteSubscriber";
-import { DashUserModel } from "./authentication/DashUserModel";
-import { Request, Response, Express } from 'express';
-import { cyan, red, green } from 'colors';
+import { cyan, green, red } from 'colors';
+import { Express, Request, Response } from 'express';
 import { AdminPriviliges } from ".";
+import { DashUserModel } from "./authentication/DashUserModel";
+import RouteSubscriber from "./RouteSubscriber";
 
 export enum Method {
     GET,
diff --git a/src/server/Search.ts b/src/server/Search.ts
index 21064e520..decd1f5b1 100644
--- a/src/server/Search.ts
+++ b/src/server/Search.ts
@@ -1,5 +1,5 @@
-import * as rp from 'request-promise';
 import { red } from 'colors';
+import * as rp from 'request-promise';
 
 const pathTo = (relative: string) => `http://localhost:8983/solr/dash/${relative}`;
 
diff --git a/src/server/database.ts b/src/server/database.ts
index 2372cbcf2..b7aa77f5d 100644
--- a/src/server/database.ts
+++ b/src/server/database.ts
@@ -1,11 +1,11 @@
 import * as mongodb from 'mongodb';
-import { Transferable } from './Message';
+import * as mongoose from 'mongoose';
 import { Opt } from '../fields/Doc';
-import { Utils, emptyFunction } from '../Utils';
+import { emptyFunction, Utils } from '../Utils';
 import { GoogleApiServerUtils } from './apis/google/GoogleApiServerUtils';
-import { IDatabase, DocumentsCollection } from './IDatabase';
+import { DocumentsCollection, IDatabase } from './IDatabase';
 import { MemoryDatabase } from './MemoryDatabase';
-import * as mongoose from 'mongoose';
+import { Transferable } from './Message';
 import { Upload } from './SharedMediaTypes';
 
 export namespace Database {
diff --git a/src/server/downsize.ts b/src/server/downsize.ts
index 5cd709fa3..382994e2d 100644
--- a/src/server/downsize.ts
+++ b/src/server/downsize.ts
@@ -1,5 +1,5 @@
-import * as sharp from 'sharp';
 import * as fs from 'fs';
+import * as sharp from 'sharp';
 
 const folder = "./src/server/public/files/";
 const pngTypes = ["png", "PNG"];
diff --git a/src/server/index.ts b/src/server/index.ts
index 9af4b00bc..9185e3c5e 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -1,29 +1,29 @@
 require('dotenv').config();
-import { GoogleApiServerUtils } from "./apis/google/GoogleApiServerUtils";
+import { yellow } from "colors";
 import * as mobileDetect from 'mobile-detect';
 import * as path from 'path';
-import { Database } from './database';
-import { DashUploadUtils } from './DashUploadUtils';
-import RouteSubscriber from './RouteSubscriber';
-import initializeServer, { resolvedPorts } from './server_Initialization';
-import RouteManager, { Method, _success, _permission_denied, _error, _invalid, PublicHandler } from './RouteManager';
 import * as qs from 'query-string';
-import UtilManager from './ApiManagers/UtilManager';
-import { SearchManager } from './ApiManagers/SearchManager';
-import UserManager from './ApiManagers/UserManager';
-import DownloadManager from './ApiManagers/DownloadManager';
-import { GoogleCredentialsLoader, SSL } from './apis/google/CredentialsLoader';
-import DeleteManager from "./ApiManagers/DeleteManager";
-import PDFManager from "./ApiManagers/PDFManager";
-import UploadManager from "./ApiManagers/UploadManager";
 import { log_execution } from "./ActionUtilities";
+import DeleteManager from "./ApiManagers/DeleteManager";
+import DownloadManager from './ApiManagers/DownloadManager';
 import GeneralGoogleManager from "./ApiManagers/GeneralGoogleManager";
-import HypothesisManager from "./ApiManagers/HypothesisManager";
 import GooglePhotosManager from "./ApiManagers/GooglePhotosManager";
-import { Logger } from "./ProcessFactory";
-import { yellow } from "colors";
+import HypothesisManager from "./ApiManagers/HypothesisManager";
+import PDFManager from "./ApiManagers/PDFManager";
+import { SearchManager } from './ApiManagers/SearchManager';
 import SessionManager from "./ApiManagers/SessionManager";
+import UploadManager from "./ApiManagers/UploadManager";
+import UserManager from './ApiManagers/UserManager';
+import UtilManager from './ApiManagers/UtilManager';
+import { GoogleCredentialsLoader, SSL } from './apis/google/CredentialsLoader';
+import { GoogleApiServerUtils } from "./apis/google/GoogleApiServerUtils";
 import { AppliedSessionAgent } from "./DashSession/Session/agents/applied_session_agent";
+import { DashUploadUtils } from './DashUploadUtils';
+import { Database } from './database';
+import { Logger } from "./ProcessFactory";
+import RouteManager, { Method, PublicHandler } from './RouteManager';
+import RouteSubscriber from './RouteSubscriber';
+import initializeServer, { resolvedPorts } from './server_Initialization';
 
 export const AdminPriviliges: Map<string, boolean> = new Map();
 export const onWindows = process.platform === "win32";
diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts
index 744d4547b..e40f2b8e5 100644
--- a/src/server/server_Initialization.ts
+++ b/src/server/server_Initialization.ts
@@ -1,31 +1,31 @@
+import * as bodyParser from 'body-parser';
+import { blue, yellow } from 'colors';
+import * as cookieParser from 'cookie-parser';
+import * as cors from "cors";
 import * as express from 'express';
-import * as expressValidator from 'express-validator';
 import * as session from 'express-session';
+import * as expressValidator from 'express-validator';
+import * as fs from 'fs';
+import { Server as HttpServer } from "http";
+import { createServer, Server as HttpsServer } from "https";
 import * as passport from 'passport';
-import * as bodyParser from 'body-parser';
-import * as cookieParser from 'cookie-parser';
-import expressFlash = require('express-flash');
-import flash = require('connect-flash');
-import { Database } from './database';
-import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLogin, postReset, postSignup } from './authentication/AuthenticationManager';
-const MongoStore = require('connect-mongo')(session);
-import RouteManager from './RouteManager';
-import { WebSocket } from './websocket';
+import * as request from 'request';
 import * as webpack from 'webpack';
-const config = require('../../webpack.config');
-const compiler = webpack(config);
 import * as wdm from 'webpack-dev-middleware';
 import * as whm from 'webpack-hot-middleware';
-import * as fs from 'fs';
-import * as request from 'request';
-import RouteSubscriber from './RouteSubscriber';
 import { publicDirectory } from '.';
 import { logPort } from './ActionUtilities';
-import { blue, yellow } from 'colors';
-import * as cors from "cors";
-import { createServer, Server as HttpsServer } from "https";
-import { Server as HttpServer } from "http";
 import { SSL } from './apis/google/CredentialsLoader';
+import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLogin, postReset, postSignup } from './authentication/AuthenticationManager';
+import { Database } from './database';
+import RouteManager from './RouteManager';
+import RouteSubscriber from './RouteSubscriber';
+import { WebSocket } from './websocket';
+import expressFlash = require('express-flash');
+import flash = require('connect-flash');
+const MongoStore = require('connect-mongo')(session);
+const config = require('../../webpack.config');
+const compiler = webpack(config);
 
 /* RouteSetter is a wrapper around the server that prevents the server
    from being exposed. */
diff --git a/src/server/websocket.ts b/src/server/websocket.ts
index f63a35e43..d5f89a750 100644
--- a/src/server/websocket.ts
+++ b/src/server/websocket.ts
@@ -1,21 +1,20 @@
-import * as fs from 'fs';
-import { logPort } from './ActionUtilities';
-import { Utils } from "../Utils";
-import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent, RoomMessage } from "./Message";
-import { Client } from "./Client";
-import { Socket } from "socket.io";
-import { Database } from "./database";
-import { Search } from "./Search";
-import * as sio from 'socket.io';
-import YoutubeApi from "./apis/youtube/youtubeApiSample";
-import { GoogleCredentialsLoader, SSL } from "./apis/google/CredentialsLoader";
-import { timeMap } from "./ApiManagers/UserManager";
 import { green } from "colors";
+import * as express from "express";
+import { createServer, Server } from "https";
 import { networkInterfaces } from "os";
+import * as sio from 'socket.io';
+import { Socket } from "socket.io";
 import executeImport from "../scraping/buxton/final/BuxtonImporter";
+import { Utils } from "../Utils";
+import { logPort } from './ActionUtilities';
+import { timeMap } from "./ApiManagers/UserManager";
+import { GoogleCredentialsLoader, SSL } from "./apis/google/CredentialsLoader";
+import YoutubeApi from "./apis/youtube/youtubeApiSample";
+import { Client } from "./Client";
+import { Database } from "./database";
 import { DocumentsCollection } from "./IDatabase";
-import { createServer, Server } from "https";
-import * as express from "express";
+import { Diff, GestureContent, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, Transferable, Types, UpdateMobileInkOverlayPositionContent, YoutubeQueryInput, YoutubeQueryTypes } from "./Message";
+import { Search } from "./Search";
 import { resolvedPorts } from './server_Initialization';
 
 export namespace WebSocket {
-- 
cgit v1.2.3-70-g09d2


From e25afb5fe507ff13cb6e863c07032d9d9dcc864b Mon Sep 17 00:00:00 2001
From: Lionel Han <47760119+IGoByJoe@users.noreply.github.com>
Date: Mon, 3 Aug 2020 12:37:32 -0700
Subject: added timestamps and added delete for markers and changed the way
 markers are rendered

---
 src/client/documents/Documents.ts                  |   2 +-
 src/client/views/nodes/AudioBox.scss               |   1 +
 src/client/views/nodes/AudioBox.tsx                | 113 ++++++++++++-------
 .../views/nodes/formattedText/FormattedTextBox.tsx | 124 ++++++++++++++++-----
 4 files changed, 172 insertions(+), 68 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 88f470576..402f3e82c 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -628,7 +628,7 @@ export namespace Docs {
         }
 
         export function AudioDocument(url: string, options: DocumentOptions = {}) {
-            const instance = InstanceFromProto(Prototypes.get(DocumentType.AUDIO), new AudioField(new URL(url)), { ...options }); // hideLinkButton: false, useLinkSmallAnchor: false,
+            const instance = InstanceFromProto(Prototypes.get(DocumentType.AUDIO), new AudioField(new URL(url)), { useLinkSmallAnchor: true, ...options }); // hideLinkButton: false, useLinkSmallAnchor: false,
             Doc.GetProto(instance).backgroundColor = ComputedField.MakeFunction("this._audioState === 'playing' ? 'green':'gray'");
             return instance;
         }
diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss
index 35ab5da8b..0ea4b37cb 100644
--- a/src/client/views/nodes/AudioBox.scss
+++ b/src/client/views/nodes/AudioBox.scss
@@ -148,6 +148,7 @@
                     width: 100%;
                     height: 100%;
                     overflow: hidden;
+                    z-index: 0;
                 }
 
                 .audiobox-linker,
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 3d1932883..7c90547ef 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -75,6 +75,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     _markers: Array<any> = [];
     _first: boolean = false;
     _buckets: Array<number> = new Array();
+    _count: Array<any> = [];
 
     private _isPointerDown = false;
     private _currMarker: any;
@@ -516,53 +517,74 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         return false;
     }
 
+    markers = () => {
+        const increment = NumCast(this.layoutDoc.duration) / 500;
+        this._count = [];
+        for (let i = 0; i < 500; i++) {
+            this._count.push([increment * i, 0])
+        }
+
+    }
+
     // Probably need a better way to format
-    isOverlap = (m: any, i: number) => {
-        console.log("called");
-        let counter = 0;
+    // isOverlap = (m: any, i: number) => {
+    //     console.log("called");
+    //     let counter = 0;
 
+    //     if (this._first) {
+    //         this._markers = [];
+    //         this._first = false;
+    //     }
+    //     for (let i = 0; i < this._markers.length; i++) {
+    //         if ((m.audioEnd > this._markers[i].audioStart && m.audioStart < this._markers[i].audioEnd)) {
+    //             counter++;
+    //             console.log(counter);
+    //         }
+    //     }
+
+    //     if (this.dataDoc.markerAmount < counter) {
+    //         this.dataDoc.markerAmount = counter;
+    //     }
+
+    //     this._markers.push(m);
+
+    //     return counter;
+    // }
+
+    isOverlap = (m: any) => {
         if (this._first) {
-            this._markers = [];
             this._first = false;
-        }
-        for (let i = 0; i < this._markers.length; i++) {
-            if ((m.audioEnd > this._markers[i].audioStart && m.audioStart < this._markers[i].audioEnd)) {
-                counter++;
-                console.log(counter);
-            }
+            this.markers();
+            console.log(this._count);
         }
 
-        if (this.dataDoc.markerAmount < counter) {
-            this.dataDoc.markerAmount = counter;
-        }
 
-        this._markers.push(m);
+        let max = 0
 
-        return counter;
-    }
+        for (let i = 0; i < 500; i++) {
+            if (this._count[i][0] >= m.audioStart && this._count[i][0] <= m.audioEnd) {
+                this._count[i][1]++;
 
-    // isOverlap = (m: any) => {
-    //     if (this._markers.length < 1) {
-    //         this._markers = new Array(Math.round(this.dataDoc.duration)).fill(0);
-    //     }
-    //     console.log(this._markers);
-    //     let max = 0
+                if (this._count[i][1] > max) {
+                    max = this._count[i][1];
+                }
+            }
 
-    //     for (let i = Math.round(m.audioStart); i <= Math.round(m.audioEnd); i++) {
-    //         this._markers[i] = this._markers[i] + 1;
-    //         console.log(this._markers[i]);
 
-    //         if (this._markers[i] > max) {
-    //             max = this._markers[i];
-    //         }
-    //     }
+        }
 
-    //     console.log(max);
-    //     if (this.dataDoc.markerAmount < max) {
-    //         this.dataDoc.markerAmount = max;
-    //     }
-    //     return max
-    // }
+        for (let i = 0; i < 500; i++) {
+            if (this._count[i][0] >= m.audioStart && this._count[i][0] <= m.audioEnd) {
+                this._count[i][1] = max;
+            }
+
+        }
+
+        if (this.dataDoc.markerAmount < max) {
+            this.dataDoc.markerAmount = max;
+        }
+        return max - 1
+    }
 
     formatTime = (time: number) => {
         const hours = Math.floor(time / 60 / 60);
@@ -609,6 +631,13 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         this._first = true;
     }
 
+    @computed get height() {
+        console.log(this.layoutDoc._height);
+        if (this.layoutDoc._height) {
+            return 0.8 * this.layoutDoc._height
+        }
+    }
+
     render() {
         //trace();
         const interactive = this.active() ? "-interactive" : "";
@@ -673,14 +702,14 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                     this._hold ? this.end(this._ele!.currentTime) : this.start(this._ele!.currentTime);
                                 }
                             }}>
-                            <div className="waveform" style={{ height: `${100}%`, width: "100%", bottom: "0px" }}>
+                            <div className="waveform" id="waveform" style={{ height: `${100}%`, width: "100%", bottom: "0px" }}>
                                 {console.log(this.peaks)}
                                 <Waveform
                                     color={"#000000"}
-                                    height={20}
+                                    height={this.height}
                                     barWidth={0.1}
                                     pos={this.layoutDoc.currentTimecode}
-                                    duration={this.layoutDoc.duration}
+                                    duration={this.dataDoc.duration}
                                     peaks={this._buckets.length === 100 ? this._buckets : undefined}
                                     progressColor={"#0000ff"} />
                             </div>
@@ -690,7 +719,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                 (!m.isLabel) ?
                                     (this.layoutDoc.hideMarkers) ? (null) :
                                         rect =
-                                        <div className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container1"} title={`${this.formatTime(Math.round(NumCast(m.audioStart)))}` + " - " + `${this.formatTime(Math.round(NumCast(m.audioEnd)))}`} key={i} id={"audiobox-marker-container1"} style={{ left: `${NumCast(m.audioStart) / NumCast(this.dataDoc.duration, 1) * 100}%`, width: `${(NumCast(m.audioEnd) - NumCast(m.audioStart)) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: `${1 / (this.dataDoc.markerAmount + 2) * 100}%`, top: `${this.isOverlap(m, i) * 1 / (this.dataDoc.markerAmount + 2) * 100}%` }} onClick={e => { this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)); e.stopPropagation() }} >
+                                        <div className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container1"} title={`${this.formatTime(Math.round(NumCast(m.audioStart)))}` + " - " + `${this.formatTime(Math.round(NumCast(m.audioEnd)))}`} key={i} id={"audiobox-marker-container1"} style={{ left: `${NumCast(m.audioStart) / NumCast(this.dataDoc.duration, 1) * 100}%`, width: `${(NumCast(m.audioEnd) - NumCast(m.audioStart)) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: `${1 / (this.dataDoc.markerAmount + 1) * 100}%`, top: `${this.isOverlap(m) * 1 / (this.dataDoc.markerAmount + 1) * 100}%` }} onClick={e => { this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)); e.stopPropagation() }} >
                                             <div className="left-resizer" onPointerDown={e => this.onPointerDown(e, m, true)}></div>
                                             <DocumentView {...this.props}
                                                 Document={m}
@@ -700,7 +729,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                                 rootSelected={returnFalse}
                                                 LayoutTemplate={undefined}
                                                 ContainingCollectionDoc={this.props.Document}
-                                                removeDocument={undefined}
+                                                removeDocument={this.removeDocument}
                                                 parentActive={returnTrue}
                                                 onClick={this.layoutDoc.playOnClick ? this.rangeScript : undefined}
                                                 ignoreAutoHeight={false}
@@ -722,7 +751,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                                 rootSelected={returnFalse}
                                                 LayoutTemplate={undefined}
                                                 ContainingCollectionDoc={this.props.Document}
-                                                removeDocument={undefined}
+                                                removeDocument={this.removeDocument}
                                                 parentActive={returnTrue}
                                                 onClick={this.layoutDoc.playOnClick ? this.labelScript : undefined}
                                                 ignoreAutoHeight={false}
@@ -776,7 +805,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                             {this.formatTime(Math.round(NumCast(this.layoutDoc.currentTimecode)))}
                         </div>
                         <div className="total-time">
-                            {this.formatTime(Math.round(NumCast(this.layoutDoc.duration)))}
+                            {this.formatTime(Math.round(NumCast(this.dataDoc.duration)))}
                         </div>
                     </div>
                 </div>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index b1d9be73b..91940466f 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -2,7 +2,7 @@ import { library } from '@fortawesome/fontawesome-svg-core';
 import { faEdit, faSmile, faTextHeight, faUpload } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { isEqual } from "lodash";
-import { action, computed, IReactionDisposer, Lambda, observable, reaction, runInAction } from "mobx";
+import { action, computed, IReactionDisposer, Lambda, observable, reaction, runInAction, trace } from "mobx";
 import { observer } from "mobx-react";
 import { baseKeymap, selectAll } from "prosemirror-commands";
 import { history } from "prosemirror-history";
@@ -93,6 +93,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     private _undoTyping?: UndoManager.Batch;
     private _disposers: { [name: string]: IReactionDisposer } = {};
     private _dropDisposer?: DragManager.DragDropDisposer;
+    private _first: Boolean = true;
+    private _recordingStart: number = 0;
+    private _currentTime: number = 0;
+    private _linkTime: number | null = null;
+    private _pause: boolean = false;
 
     @computed get _recording() { return this.dataDoc.audioState === "recording"; }
     set _recording(value) { this.dataDoc.audioState = value ? "recording" : undefined; }
@@ -140,6 +145,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         super(props);
         FormattedTextBox.Instance = this;
         this.updateHighlights();
+        this._recordingStart = Date.now();
+        this.layoutDoc._timeStampOnEnter = true;
     }
 
     public get CurrentDiv(): HTMLDivElement { return this._ref.current!; }
@@ -197,9 +204,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     }
 
     dispatchTransaction = (tx: Transaction) => {
+        let timeStamp;
+        clearTimeout(timeStamp);
+        console.log("hi");
         if (this._editorView) {
+
             const metadata = tx.selection.$from.marks().find((m: Mark) => m.type === schema.marks.metadata);
             if (metadata) {
+
                 const range = tx.selection.$from.blockRange(tx.selection.$to);
                 let text = range ? tx.doc.textBetween(range.start, range.end) : "";
                 let textEndSelection = tx.selection.to;
@@ -221,6 +233,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     this.dataDoc[key] = value;
                 }
             }
+
             const state = this._editorView.state.apply(tx);
             this._editorView.updateState(state);
             (tx.storedMarks && !this._editorView.state.storedMarks) && (this._editorView.state.storedMarks = tx.storedMarks);
@@ -234,19 +247,33 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             const json = JSON.stringify(state.toJSON());
             let unchanged = true;
             const effectiveAcl = GetEffectiveAcl(this.dataDoc);
+
+
             if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) {
                 if (!this._applyingChange && json.replace(/"selection":.*/, "") !== curProto?.Data.replace(/"selection":.*/, "")) {
                     this._applyingChange = true;
                     (curText !== Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text) && (this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())));
                     if ((!curTemp && !curProto) || curText || curLayout?.Data.includes("dash")) { // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
                         if (json.replace(/"selection":.*/, "") !== curLayout?.Data.replace(/"selection":.*/, "")) {
+                            console.log("type");
+                            if (!this._pause && !this.layoutDoc._timeStampOnEnter) {
+                                console.log("started");
+                                timeStamp = setTimeout(() => this.pause(), 10 * 1000);
+                            }
+
+                            if (this._pause) {
+                                this._pause = false;
+                                this.insertTime();
+                            }
                             !curText && tx.storedMarks?.map(m => m.type.name === "pFontSize" && (Doc.UserDoc().fontSize = this.layoutDoc._fontSize = m.attrs.fontSize));
                             !curText && tx.storedMarks?.map(m => m.type.name === "pFontFamily" && (Doc.UserDoc().fontFamily = this.layoutDoc._fontFamily = m.attrs.fontFamily));
                             this.dataDoc[this.props.fieldKey] = new RichTextField(json, curText);
                             this.dataDoc[this.props.fieldKey + "-noTemplate"] = (curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited
                             ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, self: this.rootDoc, text: curText });
                             unchanged = false;
+
                         }
+
                     } else { // if we've deleted all the text in a note driven by a template, then restore the template data
                         this.dataDoc[this.props.fieldKey] = undefined;
                         this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse((curProto || curTemp).Data)));
@@ -260,6 +287,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     }
                 }
             } else {
+
                 const json = JSON.parse(Cast(this.dataDoc[this.fieldKey], RichTextField)?.Data!);
                 json.selection = state.toJSON().selection;
                 this._editorView.updateState(EditorState.fromJSON(this.config, json));
@@ -267,6 +295,66 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         }
     }
 
+    pause = () => this._pause = true;
+
+    formatTime = (time: number) => {
+        const hours = Math.floor(time / 60 / 60);
+        const minutes = Math.floor(time / 60) - (hours * 60);
+        const seconds = time % 60;
+
+        return hours.toString().padStart(2, '0') + ':' + minutes.toString().padStart(2, '0') + ':' + seconds.toString().padStart(2, '0');
+    }
+
+    insertTime = () => {
+        let linkTime;
+        if (this._first) {
+            this._first = false;
+            DocListCast(this.dataDoc.links).map((l, i) => {
+                let la1 = l.anchor1 as Doc;
+                let la2 = l.anchor2 as Doc;
+                this._linkTime = NumCast(l.anchor2_timecode);
+                if (Doc.AreProtosEqual(la2, this.dataDoc)) {
+                    la1 = l.anchor2 as Doc;
+                    la2 = l.anchor1 as Doc;
+                    this._linkTime = NumCast(l.anchor1_timecode);
+                }
+
+            })
+
+
+
+        }
+        this._currentTime = Date.now();
+        let time;
+        console.log(this._linkTime);
+        this._linkTime ? time = this.formatTime(Math.round(this._linkTime + this._currentTime / 1000 - this._recordingStart / 1000)) : time = null;
+
+        if (this._editorView) {
+            const state = this._editorView.state;
+            const now = Date.now();
+            let mark = schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(now / 1000) });
+            if (!this._break && state.selection.to !== state.selection.from) {
+                for (let i = state.selection.from; i <= state.selection.to; i++) {
+                    const pos = state.doc.resolve(i);
+                    const um = Array.from(pos.marks()).find(m => m.type === schema.marks.user_mark);
+                    if (um) {
+                        mark = um;
+                        break;
+                    }
+                }
+            }
+            if (time) {
+                let value = "";
+                this._break = false;
+                value = this.layoutDoc._timeStampOnEnter ? "[" + time + "] " : "\n" + "[" + time + "] ";
+                console.log(value);
+                const from = state.selection.from;
+                const inserted = state.tr.insertText(value).addMark(from, from + value.length + 1, mark);
+                this._editorView.dispatch(this._editorView.state.tr.insertText(value));
+            }
+        }
+    }
+
     updateTitle = () => {
         if ((this.props.Document.isTemplateForField === "text" || !this.props.Document.isTemplateForField) && // only update the title if the data document's data field is changing
             StrCast(this.dataDoc.title).startsWith("-") && this._editorView && !this.rootDoc.customTitle) {
@@ -501,6 +589,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         uicontrols.push({ description: `${this.layoutDoc._showSidebar ? "Hide" : "Show"} Sidebar`, event: () => this.layoutDoc._showSidebar = !this.layoutDoc._showSidebar, icon: "expand-arrows-alt" });
         uicontrols.push({ description: `${this.layoutDoc._showAudio ? "Hide" : "Show"} Dictation Icon`, event: () => this.layoutDoc._showAudio = !this.layoutDoc._showAudio, icon: "expand-arrows-alt" });
         uicontrols.push({ description: "Show Highlights...", noexpand: true, subitems: highlighting, icon: "hand-point-right" });
+        uicontrols.push({ description: `Create TimeStamp When ${this.layoutDoc._timeStampOnEnter ? "Pause" : "Enter"}`, event: () => this.layoutDoc._timeStampOnEnter = !this.layoutDoc._timeStampOnEnter, icon: "expand-arrows-alt" });
         !Doc.UserDoc().noviceMode && uicontrols.push({
             description: "Broadcast Message", event: () => DocServer.GetRefField("rtfProto").then(proto =>
                 proto instanceof Doc && (proto.BROADCAST_MESSAGE = Cast(this.rootDoc[this.fieldKey], RichTextField)?.Text)), icon: "expand-arrows-alt"
@@ -594,6 +683,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             const recordingStart = DateCast(this.props.Document.recordingStart).date.getTime();
             this._break = false;
             value = "" + (mark.attrs.modified * 1000 - recordingStart) / 1000 + value;
+            console.log(value);
             const from = state.selection.from;
             const inserted = state.tr.insertText(value).addMark(from, from + value.length + 1, mark);
             this._editorView.dispatch(inserted.setSelection(TextSelection.create(inserted.doc, from, from + value.length + 1)));
@@ -1295,30 +1385,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         }
         e.stopPropagation();
         if (e.key === "Tab" || e.key === "Enter") {
-            // console.log(this._recording);
-            // if (this._editorView) {
-            //     const state = this._editorView.state;
-            //     const now = Date.now();
-            //     let mark = schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(now / 1000) });
-            //     if (!this._break && state.selection.to !== state.selection.from) {
-            //         for (let i = state.selection.from; i <= state.selection.to; i++) {
-            //             const pos = state.doc.resolve(i);
-            //             const um = Array.from(pos.marks()).find(m => m.type === schema.marks.user_mark);
-            //             if (um) {
-            //                 mark = um;
-            //                 break;
-            //             }
-            //         }
-            //     }
-            //     const recordingStart = DateCast(this.props.Document.recordingStart).date.getTime();
-            //     this._break = false;
-            //     let value = "" + (mark.attrs.modified * 1000 - recordingStart) / 1000;
-            //     //let value = "[0:02]";
-            //     const from = state.selection.from;
-            //     const inserted = state.tr.insertText(value).addMark(from, from + value.length + 1, mark);
-
-            //     this._editorView.dispatch(inserted.setSelection(TextSelection.create(inserted.doc, from, from + value.length + 1)));
-            // }
+            if (e.key === "Enter" && this.layoutDoc._timeStampOnEnter) {
+                this.insertTime();
+            }
             e.preventDefault();
         }
         if (e.key === " " || this._lastTimedMark?.attrs.userid !== Doc.CurrentUserEmail) {
@@ -1371,6 +1440,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     @computed get sidebarColor() { return StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "transparent")); }
     render() {
         TraceMobx();
+        trace();
+        // if (this.props.Document.recordingStart) {
+        //     console.log(DateCast(this.props.Document.recordingStart).date.getTime());
+        // }
+
         const scale = this.props.ContentScaling() * NumCast(this.layoutDoc._viewScale, 1);
         const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : "";
         const interactive = Doc.GetSelectedTool() === InkTool.None && !this.layoutDoc.isBackground;
-- 
cgit v1.2.3-70-g09d2


From 5afb1157ee888a46df3074ac1445966f514aa372 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 4 Aug 2020 00:40:35 -0400
Subject: fixed joe k;lm

---
 src/client/views/nodes/formattedText/FormattedTextBox.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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

diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index e95a4ccd2..79cf5c5fd 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -270,7 +270,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         if ((this.props.Document.isTemplateForField === "text" || !this.props.Document.isTemplateForField) && // only update the title if the data document's data field is changing
             StrCast(this.dataDoc.title).startsWith("-") && this._editorView && !this.rootDoc.customTitle) {
             let node = this._editorView.state.doc;
-            while (node.firstChild) node = node.firstChild;
+            while (node.firstChild && node.firstChild.type.name !== "text") node = node.firstChild;
             const str = node.textContent;
             const titlestr = str.substr(0, Math.min(40, str.length));
             this.dataDoc.title = "-" + titlestr + (str.length > 40 ? "..." : "");
-- 
cgit v1.2.3-70-g09d2


From e83fd812ed3798a7e7c22ad132a2f9e8dccaa76c Mon Sep 17 00:00:00 2001
From: Andy Rickert <andrew_rickert@brown.edu>
Date: Tue, 4 Aug 2020 22:05:30 -0400
Subject: changes

---
 src/client/documents/Documents.ts                  |  14 +-
 src/client/util/CurrentUserUtils.ts                |  12 +-
 src/client/views/SearchDocBox.tsx                  | 428 ----------------
 .../views/collections/CollectionSchemaCells.tsx    |  84 +++-
 .../views/collections/CollectionSchemaHeaders.tsx  |   8 +-
 .../views/collections/CollectionSchemaView.scss    |   2 +-
 src/client/views/collections/CollectionSubView.tsx |  53 +-
 src/client/views/collections/SchemaTable.tsx       |  47 +-
 .../collectionFreeForm/PropertiesView.tsx          |   2 +-
 src/client/views/nodes/DocumentContentsView.tsx    |   3 +-
 src/client/views/nodes/LabelBox.tsx                |   2 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |   1 -
 src/client/views/search/SearchBox.tsx              | 419 +++++-----------
 src/client/views/search/SearchItem.scss            | 186 -------
 src/client/views/search/SearchItem.tsx             | 556 ---------------------
 15 files changed, 300 insertions(+), 1517 deletions(-)
 delete mode 100644 src/client/views/SearchDocBox.tsx
 delete mode 100644 src/client/views/search/SearchItem.scss
 delete mode 100644 src/client/views/search/SearchItem.tsx

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index e6eaaad60..b809a73b7 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -22,8 +22,7 @@ import { LinkManager } from "../util/LinkManager";
 import { Scripting } from "../util/Scripting";
 import { UndoManager } from "../util/UndoManager";
 import { DocumentType } from "./DocumentTypes";
-import { SearchItem } from "../views/search/SearchItem";
-import { SearchBox, filterData } from "../views/search/SearchBox";
+import { SearchBox } from "../views/search/SearchBox";
 import { CollectionDockingView } from "../views/collections/CollectionDockingView";
 import { CollectionView, CollectionViewType } from "../views/collections/CollectionView";
 import { ContextMenu } from "../views/ContextMenu";
@@ -48,7 +47,6 @@ import { VideoBox } from "../views/nodes/VideoBox";
 import { WebBox } from "../views/nodes/WebBox";
 import { PresElementBox } from "../views/presentationview/PresElementBox";
 import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
-import { DocumentType } from "./DocumentTypes";
 import { Networking } from "../Network";
 import { Upload } from "../../server/SharedMediaTypes";
 const path = require('path');
@@ -191,8 +189,7 @@ 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
-    searchQuery?: string, // for quersyBox
-    filterQuery?: filterData,
+    searchQuery?: string; // for quersyBox
     linearViewIsExpanded?: boolean; // is linear view expanded
     border?: string; //for searchbox
     hovercolor?: string;
@@ -316,9 +313,6 @@ export namespace Docs {
             [DocumentType.PRESELEMENT, {
                 layout: { view: PresElementBox, dataField: defaultDataKey }
             }],
-            [DocumentType.SEARCHITEM, {
-                layout: { view: SearchItem, dataField: defaultDataKey }
-            }],
             [DocumentType.INK, {
                 layout: { view: InkingStroke, dataField: defaultDataKey },
                 options: { backgroundColor: "transparent" }
@@ -803,10 +797,6 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.PRESELEMENT), undefined, { ...(options || {}) });
         }
 
-        export function SearchItemBoxDocument(options?: DocumentOptions) {
-            return InstanceFromProto(Prototypes.get(DocumentType.SEARCHITEM), undefined, { ...(options || {}) });
-        }
-
         export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) {
             const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _viewType: CollectionViewType.Docking, dockingConfig: config }, id);
             Doc.GetProto(inst).data = new List<Doc>(documents);
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 84cd4823b..cd8c09a0e 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -543,7 +543,7 @@ export class CurrentUserUtils {
                     btn.color = "white";
                     btn._backgroundColor = "";
                 }));
-            })
+            });
         });
         return doc.menuStack as Doc;
     }
@@ -761,16 +761,6 @@ export class CurrentUserUtils {
         }
     }
 
-    static setupSidebarContainer(doc: Doc) {
-        if (doc["sidebar"] === undefined) {
-            const sidebarContainer = new Doc();
-            sidebarContainer._chromeStatus = "disabled";
-            sidebarContainer.onClick = ScriptField.MakeScript("freezeSidebar()");
-            doc["sidebar"] = new PrefetchProxy(sidebarContainer);
-        }
-        return doc["sidebar"] as Doc;
-    }
-
     // setup the list of sidebar mode buttons which determine what is displayed in the sidebar
     static async setupSidebarButtons(doc: Doc) {
         await CurrentUserUtils.setupToolsBtnPanel(doc);
diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
deleted file mode 100644
index 084f952a3..000000000
--- a/src/client/views/SearchDocBox.tsx
+++ /dev/null
@@ -1,428 +0,0 @@
-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 "./SearchBoxDoc.scss";
-import { Doc, DocListCast } from "../../fields/Doc";
-import { Id } from "../../fields/FieldSymbols";
-import { BoolCast, Cast, NumCast, StrCast } from "../../fields/Types";
-import { returnFalse, returnZero } from "../../Utils";
-import { Docs } from "../documents/Documents";
-import { SearchUtil } from "../util/SearchUtil";
-import { EditableView } from "./EditableView";
-import { ContentFittingDocumentView } from "./nodes/ContentFittingDocumentView";
-import { FieldView, FieldViewProps } from "./nodes/FieldView";
-import { FilterBox } from "./search/FilterBox";
-import { SearchItem } from "./search/SearchItem";
-import React = require("react");
-
-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> {
-
-    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);
-        this.editingMetadata = this.editingMetadata || false;
-        //SearchBox.Instance = this;
-        this.resultsScrolled = this.resultsScrolled.bind(this);
-    }
-
-
-    @computed
-    private get editingMetadata() {
-        return BoolCast(this.props.Document.editingMetadata);
-    }
-
-    private set editingMetadata(value: boolean) {
-        this.props.Document.editingMetadata = value;
-    }
-
-    static readonly buffer = 20;
-
-    componentDidMount() {
-        runInAction(() => {
-            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 = async (newKey: string) => {
-        this.query = newKey;
-        if (newKey.length > 1) {
-            const newdocs = await this.getAllResults(this.query);
-            const things = newdocs.docs;
-            runInAction(() => {
-                this.content = Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query });
-            });
-        }
-
-
-        //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;
-    }
-
-    @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) => {
-        if (e.key === "Enter") {
-            const newdocs = await this.getAllResults(this.query);
-            this.content = Docs.Create.TreeDocument(newdocs.docs, { _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);
-        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.QueryDocument({ _width: 200, _height: 400, searchText: this._searchString, title: `Query 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;
-        return !this.content ? (null) : (
-            <div style={{ pointerEvents: "all" }}>
-                <ContentFittingDocumentView {...this.props}
-                    Document={this.content}
-                    rootSelected={returnFalse}
-                    bringToFront={returnFalse}
-                    ContainingCollectionDoc={undefined}
-                    ContainingCollectionView={undefined}
-                    NativeWidth={returnZero}
-                    NativeHeight={returnZero}
-                    parentActive={this.props.active}
-                    ScreenToLocalTransform={this.props.ScreenToLocalTransform}>
-                </ContentFittingDocumentView>
-                <div
-                    style={{
-                        position: "absolute",
-                        right: 0,
-                        width: 20,
-                        height: 20,
-                        background: "black",
-                        pointerEvents: "all",
-                        opacity: 1,
-                        transition: "0.4s opacity ease",
-                        zIndex: 99,
-                        top: 0,
-                    }}
-                    title={"Add Metadata"}
-                    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
-                        contents={this.query}
-                        SetValue={this.updateKey}
-                        GetValue={() => ""}
-                    />
-                </div>
-            </div >
-        );
-    }
-
-}
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index ecd20eb06..6e19bb029 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -242,7 +242,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
         //     </div>
         // );   
         trace();
-        let positions = [];
+        const positions = [];
         if (StrCast(this.props.Document._searchString) !== "") {
             const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
             let term = "";
@@ -257,7 +257,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
                     term = String(NumCast(cfield));
                 }
             }
-            let search = StrCast(this.props.Document._searchString)
+            let search = StrCast(this.props.Document._searchString);
             let start = term.indexOf(search) as number;
             let tally = 0;
             if (start !== -1) {
@@ -873,3 +873,83 @@ export class CollectionSchemaCheckboxCell extends CollectionSchemaCell {
         );
     }
 }
+
+
+@observer
+export class CollectionSchemaButtons extends CollectionSchemaCell {
+
+    render() {
+        // const reference = React.createRef<HTMLDivElement>();
+        // const onItemDown = (e: React.PointerEvent) => {
+        //     (!this.props.CollectionView || !this.props.CollectionView.props.isSelected() ? undefined :
+        //         SetupDrag(reference, () => this._document, this.props.moveDocument, this.props.Document.schemaDoc ? "copy" : undefined)(e));
+        // };
+        let doc = this.props.rowProps.original;
+        let buttons = <div style={{
+            paddingTop: 8,
+            paddingLeft: 3,
+        }}><button onClick={() => {
+            console.log(doc);
+            console.log(doc.searchMatch);
+            doc.searchMatch = false;
+            console.log(doc.searchMatch);
+            setTimeout(() => doc.searchMatch = true, 0);
+            console.log(doc.searchMatch);
+            doc.searchIndex = NumCast(doc.searchIndex);
+        }} style={{ padding: 2, left: 77 }}>
+                <FontAwesomeIcon icon="arrow-up" size="sm" />
+            </button>
+            <button onClick={() => {
+                {
+                    console.log(doc);
+                    console.log(doc.searchMatch2);
+                    doc.searchMatch2 = false;
+                    console.log(doc.searchMatch2);
+                    setTimeout(() => doc.searchMatch2 = true, 0);
+                    console.log(doc.searchMatch2);
+                    doc.searchIndex = NumCast(doc.searchIndex);
+                }
+            }} style={{ padding: 2 }}>
+                <FontAwesomeIcon icon="arrow-down" size="sm" />
+            </button></div>;
+        const type = StrCast(doc.type);
+        console.log(StrCast(doc.type));
+        if (type === "pdf") {
+            buttons = <div><button
+                style={{
+                    position: "relative",
+                    height: 30,
+                    width: 28,
+                    left: 1,
+                }}
+
+                onClick={() => {
+                    console.log(doc);
+                    console.log(doc.searchMatch);
+                    doc.searchMatch = false;
+                    console.log(doc.searchMatch);
+                    setTimeout(() => doc.searchMatch = true, 0);
+                    console.log(doc.searchMatch);
+                    doc.searchIndex = NumCast(doc.searchIndex);
+                }}>
+                <FontAwesomeIcon icon="arrow-down" size="sm" />
+            </button></div >
+        }
+        else if (type !== "rtf") {
+            console.log("sad");
+            buttons = undefined;
+        }
+
+        if (BoolCast(this.props.Document._searchDoc) === true) {
+
+        }
+        else {
+            buttons = undefined;
+        }
+
+        return (
+            <div> {buttons}</div>
+        );
+    }
+}
+
diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx
index 5d7ab2c61..e65adcf76 100644
--- a/src/client/views/collections/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/CollectionSchemaHeaders.tsx
@@ -302,7 +302,7 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
     @action
     onSelect = (key: string): void => {
         if (key.slice(0, this._key.length) === this._key && this._key !== key) {
-            let filter = key.slice(this._key.length - key.length);
+            const filter = key.slice(this._key.length - key.length);
             this.props.onSelect(this._key, this._key, this.props.addNew, filter);
         }
         else {
@@ -395,12 +395,10 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
 
     renderFilterOptions = (): JSX.Element[] | JSX.Element => {
         if (!this._isOpen) return <></>;
-
         const keyOptions: string[] = [];
-        console.log(this._searchTerm.slice(this._key.length))
-        let temp = this._searchTerm.slice(this._key.length);
+        const temp = this._searchTerm.slice(this._key.length);
         this.props.docs?.forEach((doc) => {
-            let key = StrCast(doc[this._key]);
+            const key = StrCast(doc[this._key]);
             if (keyOptions.includes(key) === false && key.includes(temp)) {
                 keyOptions.push(key);
             }
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
index 93878d799..2dcd6d6c0 100644
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ b/src/client/views/collections/CollectionSchemaView.scss
@@ -93,7 +93,7 @@
     }
 
     .rt-tbody {
-        width: calc(100% - 2px);
+        width: 100%;
         direction: rtl;
         overflow: visible;
     }
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 88241f519..bf3129a8a 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -130,9 +130,60 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
             let childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
 
             const searchDocs = DocListCast(this.props.Document._searchDocs);
+            // if (searchDocs !== undefined && searchDocs.length > 0) {
+            //     let newdocs: Doc[] = [];
+            //     childDocs.forEach((el) => {
+            //         searchDocs.includes(el) ? newdocs.push(el) : undefined;
+            //     });
+            //     childDocs = newdocs;
+            // }
+
+            let docsforFilter: Doc[] = childDocs;
             if (searchDocs !== undefined && searchDocs.length > 0) {
-                childDocs = searchDocs;
+                docsforFilter = [];
+                // let newdocs: Doc[] = [];
+                // let newarray: Doc[] = [];
+                //while (childDocs.length > 0) {
+                //newarray = [];
+                childDocs.forEach((d) => {
+                    if (d.data !== undefined) {
+                        console.log(d);
+                        let newdocs = DocListCast(d.data);
+                        if (newdocs.length > 0) {
+                            let vibecheck = false;
+
+                            let newarray: Doc[] = [];
+
+                            while (newdocs.length > 0) {
+                                newarray = [];
+                                newdocs.forEach((t) => {
+                                    if (d.data !== undefined) {
+                                        let newdocs = DocListCast(t.data);
+                                        newdocs.forEach((newdoc) => {
+                                            newarray.push(newdoc);
+                                        });
+                                    }
+                                    if (searchDocs.includes(t)) {
+                                        vibecheck = true;
+                                    }
+                                });
+                                newdocs = newarray;
+                            }
+                            if (vibecheck === true) {
+                                docsforFilter.push(d);
+                            }
+                        }
+                    }
+                    if (searchDocs.includes(d)) {
+                        docsforFilter.push(d);
+                    }
+                });
+                //childDocs = newarray;
+                //}
             }
+            childDocs = docsforFilter;
+
+
             const docFilters = this.docFilters();
             const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
 
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index 9d02807fd..8b7717ad1 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -19,7 +19,7 @@ import { undoBatch } from "../../util/UndoManager";
 import { COLLECTION_BORDER_WIDTH } from '../../views/globalCssVariables.scss';
 import { ContextMenu } from "../ContextMenu";
 import '../DocumentDecorations.scss';
-import { CellProps, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDocCell, CollectionSchemaNumberCell, CollectionSchemaStringCell, CollectionSchemaImageCell, CollectionSchemaListCell, CollectionSchemaDateCell } from "./CollectionSchemaCells";
+import { CellProps, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDocCell, CollectionSchemaNumberCell, CollectionSchemaStringCell, CollectionSchemaImageCell, CollectionSchemaListCell, CollectionSchemaDateCell, CollectionSchemaButtons } from "./CollectionSchemaCells";
 import { CollectionSchemaAddColumnHeader, KeysDropdown } from "./CollectionSchemaHeaders";
 import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC";
 import "./CollectionSchemaView.scss";
@@ -160,7 +160,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
         const focusedCol = this._focusedCell.col;
         const isEditable = !this.props.headerIsEditing;
 
-        if (this.childDocs.reduce((found, doc) => found || doc.type === "collection", false)) {
+        if (this.childDocs.reduce((found, doc) => found || doc.type === "nnnnn", false)) {
             columns.push(
                 {
                     expander: true,
@@ -283,12 +283,34 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
             Header: <CollectionSchemaAddColumnHeader createColumn={this.createColumn} />,
             accessor: (doc: Doc) => 0,
             id: "add",
-            Cell: (rowProps: CellInfo) => <div> <button onClick={(e) => this.nextHighlight(e, this.props.Document)} style={{ padding: 2, left: 77 }}>
-                <FontAwesomeIcon icon="arrow-up" size="sm" />
-            </button>
-                <button onClick={(e) => this.nextHighlight2(e, this.props.Document)} style={{ padding: 2, left: 87 }}>
-                    <FontAwesomeIcon icon="arrow-down" size="sm" />
-                </button></div>,
+            Cell: (rowProps: CellInfo) => {
+                const rowIndex = rowProps.index;
+                const columnIndex = this.props.columns.map(c => c.heading).indexOf(rowProps.column.id!);
+                const isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused;
+                const props: CellProps = {
+                    row: rowIndex,
+                    col: columnIndex,
+                    rowProps: rowProps,
+                    isFocused: isFocused,
+                    changeFocusedCellByIndex: this.changeFocusedCellByIndex,
+                    CollectionView: this.props.CollectionView,
+                    ContainingCollection: this.props.ContainingCollectionView,
+                    Document: this.props.Document,
+                    fieldKey: this.props.fieldKey,
+                    renderDepth: this.props.renderDepth,
+                    addDocTab: this.props.addDocTab,
+                    pinToPres: this.props.pinToPres,
+                    moveDocument: this.props.moveDocument,
+                    setIsEditing: this.setCellIsEditing,
+                    isEditable: isEditable,
+                    setPreviewDoc: this.props.setPreviewDoc,
+                    setComputed: this.setComputed,
+                    getField: this.getField,
+                    showDoc: this.showDoc,
+                };
+
+                return <CollectionSchemaButtons {...props} />;
+            },
             width: 28,
             resizable: false
         });
@@ -301,16 +323,17 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     nextHighlight = (e: React.MouseEvent, doc: Doc) => {
         e.preventDefault();
         e.stopPropagation();
-
         doc.searchMatch = false;
+        console.log(doc.searchMatch);
         setTimeout(() => doc.searchMatch = true, 0);
+        console.log(doc.searchMatch);
+
         doc.searchIndex = NumCast(doc.searchIndex);
     }
 
     @action
-    nextHighlight2 = (e: React.MouseEvent, doc: Doc) => {
-        e.preventDefault();
-        e.stopPropagation();
+    nextHighlight2 = (doc: Doc) => {
+
         doc.searchMatch2 = false;
         setTimeout(() => doc.searchMatch2 = true, 0);
         doc.searchIndex = NumCast(doc.searchIndex);
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index f5e0cd077..031dbf884 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -539,7 +539,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
     getField(key: string) {
         //if (this.selectedDoc) {
-        return Field.toString(this.selectedDoc[key] as Field);
+        return Field.toString(this.selectedDoc![key] as Field);
         // } else {
         //     return undefined as Opt<string>;
         // }
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index c724ba50b..1282bbee5 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -25,7 +25,6 @@ import { KeyValueBox } from "./KeyValueBox";
 import { PDFBox } from "./PDFBox";
 import { PresBox } from "./PresBox";
 import { SearchBox } from "../search/SearchBox";
-import { SearchItem } from "../search/SearchItem"
 import { ColorBox } from "./ColorBox";
 import { DashWebRTCVideo } from "../webcam/DashWebRTCVideo";
 import { LinkAnchorBox } from "./LinkAnchorBox";
@@ -192,7 +191,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
                 components={{
                     FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, LabelBox, SliderBox, FieldView,
                     CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
-                    PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, SearchBox, SearchItem,
+                    PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, SearchBox,
                     ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, DocHolderBox, LinkBox, ScriptingBox,
                     ScreenshotBox, HTMLtag, ComparisonBox
                 }}
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 302d66cc5..10a164158 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -70,7 +70,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps, LabelDocument
         const missingParams = params?.filter(p => !this.paramsDoc[p]);
         params?.map(p => DocListCast(this.paramsDoc[p])); // bcz: really hacky form of prefetching ... 
         return (
-            <div className="labelBox-outerDiv" onClick={() => runInAction(() => { this.clicked = !this.clicked; this.clicked ? this.backColor = StrCast(this.layoutDoc.hovercolor) : this.backColor = "unset" })} onMouseLeave={() => runInAction(() => { !this.clicked ? this.backColor = "unset" : null })}
+            <div className="labelBox-outerDiv" onClick={() => runInAction(() => { this.clicked = !this.clicked; this.clicked ? this.backColor = StrCast(this.layoutDoc.hovercolor) : this.backColor = "unset"; })} onMouseLeave={() => runInAction(() => { !this.clicked ? this.backColor = "unset" : null; })}
                 onMouseOver={() => runInAction(() => { this.backColor = StrCast(this.layoutDoc.hovercolor); })} ref={this.createDropTarget} onContextMenu={this.specificContextMenu}
                 style={{ boxShadow: this.layoutDoc.opacity ? StrCast(this.layoutDoc.boxShadow) : "" }}>
                 <div className="labelBox-mainButton" style={{
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 79cf5c5fd..b21596493 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -309,7 +309,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
             this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
 
-            console.log(this._searchIndex, length);
             if (this._searchIndex > 1) {
                 this._searchIndex += -2;
             }
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index b76955815..acdd8d047 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -39,14 +39,6 @@ export enum Keys {
     TEXT = "text"
 }
 
-export interface filterData {
-    deletedDocsStatus: boolean;
-    authorFieldStatus: boolean;
-    titleFieldStatus: boolean;
-    basicWordStatus: boolean;
-    icons: string[];
-}
-
 type SearchBoxDocument = makeInterface<[typeof documentSchema, typeof searchSchema]>;
 const SearchBoxDocument = makeInterface(documentSchema, searchSchema);
 
@@ -89,55 +81,16 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
     @observable private newAssign: boolean = true;
 
     constructor(props: any) {
-
         super(props);
         SearchBox.Instance = this;
-        if (!_scriptingGlobals.hasOwnProperty("handleNodeChange")) {
-            Scripting.addGlobal(this.handleNodeChange);
-        }
-        if (!_scriptingGlobals.hasOwnProperty("handleKeyChange")) {
-            Scripting.addGlobal(this.handleKeyChange);
-        }
-        if (!_scriptingGlobals.hasOwnProperty("handleWordQueryChange")) {
-            Scripting.addGlobal(this.handleWordQueryChange);
-        }
-        if (!_scriptingGlobals.hasOwnProperty("updateIcon")) {
-            Scripting.addGlobal(this.updateIcon);
-        }
-        if (!_scriptingGlobals.hasOwnProperty("updateTitleStatus")) {
-            Scripting.addGlobal(this.updateTitleStatus);
-        }
-        if (!_scriptingGlobals.hasOwnProperty("updateAuthorStatus")) {
-            Scripting.addGlobal(this.updateAuthorStatus);
-        }
-        if (!_scriptingGlobals.hasOwnProperty("updateDeletedStatus")) {
-            Scripting.addGlobal(this.updateDeletedStatus);
-        }
-
-
         this.resultsScrolled = this.resultsScrolled.bind(this);
 
-        // new PrefetchProxy(Docs.Create.SearchItemBoxDocument({
-        //     title: "search item template",
-        //     backgroundColor: "transparent", _xMargin: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data"
-        // }));
-
-
-        // if (!this.searchItemTemplate) { // create exactly one presElmentBox template to use by any and all presentations.
-        //     Doc.UserDoc().searchItemTemplate = new PrefetchProxy(Docs.Create.SearchItemBoxDocument({ title: "search item template", backgroundColor: "transparent", _xMargin: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data" }));
-        //     // this script will be called by each presElement to get rendering-specific info that the PresBox knows about but which isn't written to the PresElement
-        //     // this is a design choice -- we could write this data to the presElements which would require a reaction to keep it up to date, and it would prevent
-        //     // the preselement docs from being part of multiple presentations since they would all have the same field, or we'd have to keep per-presentation data
-        //     // stored on each pres element.  
-        //     (this.searchItemTemplate as Doc).lookupField = ScriptField.MakeFunction("lookupSearchBoxField(container, field, data)",
-        //         { field: "string", data: Doc.name, container: Doc.name });
-        // }
     }
     @observable setupButtons = false;
     componentDidMount = () => {
-        if (this.setupButtons == false) {
+        if (this.setupButtons === false) {
 
-            runInAction(() => this.setupButtons == true);
+            runInAction(() => this.setupButtons = true);
         }
         if (this.inputRef.current) {
             this.inputRef.current.focus();
@@ -163,7 +116,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
 
 
     @action
-    getViews = (doc: Doc) => SearchUtil.GetViewsOfDocument(doc)
+    getViews = (doc: Doc) => SearchUtil.GetViewsOfDocument(doc);
 
 
     @observable newsearchstring: string = "";
@@ -203,9 +156,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
     enter = (e: React.KeyboardEvent) => {
         if (e.key === "Enter") {
             this.layoutDoc._searchString = this.newsearchstring;
-            // if (this._icons !== this._allIcons) {
-            //     runInAction(() => { this.expandedBucket = false });
-            // }
+
             if (StrCast(this.layoutDoc._searchString) !== "") {
                 console.log("OPEN");
                 runInAction(() => { this.open = true });
@@ -213,11 +164,8 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             else {
                 console.log("CLOSE");
                 runInAction(() => { this.open = false });
-
             }
             this.submitSearch();
-
-
         }
     }
 
@@ -365,46 +313,58 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                 this.props.Document.selectedDoc = selectedCollection.props.Document;
             }
             let docs = DocListCast(selectedCollection.dataDoc[Doc.LayoutFieldKey(selectedCollection.dataDoc)]);
-            let found: [Doc, string[], string[]][] = [];
-            let docsforFilter: Doc[] = []
+            const found: [Doc, string[], string[]][] = [];
+            const docsforFilter: Doc[] = []
             let newarray: Doc[] = [];
 
             while (docs.length > 0) {
                 newarray = [];
                 docs.forEach((d) => {
-                    if (d.data != undefined) {
+                    if (d.data !== undefined) {
                         let newdocs = DocListCast(d.data);
                         newdocs.forEach((newdoc) => {
                             newarray.push(newdoc);
 
                         });
                     }
-
-
-                    let hlights: string[] = [];
-
+                    const hlights: string[] = [];
                     const protos = Doc.GetAllPrototypes(d);
-                    let proto = protos[protos.length - 1];
                     protos.forEach(proto => {
                         Object.keys(proto).forEach(key => {
-                            // console.log(key, d[key]);
                             if (StrCast(d[key]).includes(query) && !hlights.includes(key)) {
                                 hlights.push(key);
                             }
-                        })
+                        });
                     });
                     if (hlights.length > 0) {
                         found.push([d, hlights, []]);
                         docsforFilter.push(d);
-                    };
+                    }
                 });
                 docs = newarray;
             }
             this._results = found;
             this.docsforfilter = docsforFilter;
             if (this.filter === true) {
-                console.log(docsforFilter);
                 selectedCollection.props.Document._searchDocs = new List<Doc>(docsforFilter);
+                docs = DocListCast(selectedCollection.dataDoc[Doc.LayoutFieldKey(selectedCollection.dataDoc)]);
+                while (docs.length > 0) {
+                    console.log("HIT");
+                    newarray = [];
+                    docs.forEach((d) => {
+                        if (d.data !== undefined) {
+                            console.log(d._searchDocs);
+                            d._searchDocs = new List<Doc>(docsforFilter);
+                            console.log(d);
+                            console.log(d._searchDocs);
+                            let newdocs = DocListCast(d.data);
+                            newdocs.forEach((newdoc) => {
+                                newarray.push(newdoc);
+                            });
+                        }
+                    });
+                    docs = newarray;
+                }
             }
             this._numTotalResults = found.length;
         }
@@ -468,7 +428,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
 
     @action
     submitSearch = async (reset?: boolean) => {
-        this.checkIcons();
         if (reset) {
             this.layoutDoc._searchString = "";
         }
@@ -644,13 +603,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                 y += 300;
             }
         }
-        const filter: filterData = {
-            deletedDocsStatus: this._deletedDocsStatus,
-            authorFieldStatus: this._authorFieldStatus,
-            titleFieldStatus: this._titleFieldStatus,
-            basicWordStatus: this._basicWordStatus,
-            icons: this._icons,
-        }
         return Docs.Create.SearchDocument({ _autoHeight: true, _viewType: CollectionViewType.Schema, title: StrCast(this.layoutDoc._searchString), searchQuery: StrCast(this.layoutDoc._searchString) });
     }
 
@@ -693,7 +645,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         const endIndex = 30;
         //this._endIndex = endIndex === -1 ? 12 : endIndex;
         this._endIndex = 30;
-        let headers = new Set<string>(["title", "author", "text", "lastModified"]);
+        const headers = new Set<string>(["title", "author", "lastModified", "text"]);
         if ((this._numTotalResults === 0 || this._results.length === 0) && this._openNoResults) {
             if (this.noresults === "") {
                 this.noresults = "No search results :(";
@@ -734,7 +686,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                         if (i < this._results.length) result = this._results[i];
                         if (result) {
                             const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
-                            let lines = new List<string>(result[2]);
+                            const lines = new List<string>(result[2]);
                             console.log(lines);
                             result[0].lines = lines;
                             result[0].highlighting = highlights.join(", ");
@@ -751,7 +703,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                         result = this._results[i];
                         if (result) {
                             const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
-                            let lines = new List<string>(result[2]);
+                            const lines = new List<string>(result[2]);
                             highlights.forEach((item) => headers.add(item));
                             console.log(lines);
                             result[0].lines = lines;
@@ -769,9 +721,9 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                 }
             }
         }
-        let schemaheaders: SchemaHeaderField[] = [];
+        const schemaheaders: SchemaHeaderField[] = [];
         this.headerscale = headers.size;
-        headers.forEach((item) => schemaheaders.push(new SchemaHeaderField(item, "#f1efeb")))
+        headers.forEach((item) => schemaheaders.push(new SchemaHeaderField(item, "#f1efeb")));
         this.headercount = schemaheaders.length;
         this.props.Document._schemaHeaders = new List<SchemaHeaderField>(schemaheaders);
         if (this._maxSearchIndex >= this._numTotalResults) {
@@ -784,8 +736,8 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
     @observable headerscale: number = 0;
 
     findCommonElements(arr2: string[]) {
-        let arr1 = ["layout", "data"];
-        return arr1.some(item => arr2.includes(item))
+        const arr1 = ["layout", "data"];
+        return arr1.some(item => arr2.includes(item));
     }
 
     @computed
@@ -794,210 +746,10 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
     @computed
     get resultHeight() { return this._numTotalResults * 70; }
 
-    //if true, any keywords can be used. if false, all keywords are required.
-    @action.bound
-    handleWordQueryChange = async () => {
-        this._collectionStatus = !this._collectionStatus;
-        if (this._collectionStatus) {
-            let doc = await Cast(this.props.Document.keywords, Doc)
-            doc!.backgroundColor = "grey";
-
-        }
-        else {
-            let doc = await Cast(this.props.Document.keywords, Doc)
-            doc!.backgroundColor = "black";
-        }
-    }
-
-    @action.bound
-    handleNodeChange = async () => {
-        this._nodeStatus = !this._nodeStatus;
-
-        if (this._nodeStatus) {
-            this.expandSection(`node${this.props.Document[Id]}`);
-            let doc = await Cast(this.props.Document.nodes, Doc)
-            doc!.backgroundColor = "grey";
-
-        }
-        else {
-            this.collapseSection(`node${this.props.Document[Id]}`);
-            let doc = await Cast(this.props.Document.nodes, Doc)
-            doc!.backgroundColor = "black";
-        }
-    }
-
-    @action.bound
-    handleKeyChange = async () => {
-        this._keyStatus = !this._keyStatus;
-        if (this._keyStatus) {
-            this.expandSection(`key${this.props.Document[Id]}`);
-            let doc = await Cast(this.props.Document.keys, Doc)
-            doc!.backgroundColor = "grey";
-        }
-        else {
-            this.collapseSection(`key${this.props.Document[Id]}`);
-            let doc = await Cast(this.props.Document.keys, Doc)
-            doc!.backgroundColor = "black";
-        }
-    }
-
-    @action.bound
-    handleFilterChange = () => {
-        this._filterOpen = !this._filterOpen;
-        if (this._filterOpen) {
-            this.expandSection(`filterhead${this.props.Document[Id]}`);
-            document.getElementById(`filterhead${this.props.Document[Id]}`)!.style.padding = "5";
-            console.log(this.props.Document[Id])
-        }
-        else {
-            this.collapseSection(`filterhead${this.props.Document[Id]}`);
-
-
-        }
-    }
-
-    @computed
-    get menuHeight() {
-        return document.getElementById("hi")?.clientHeight;
-    }
-
-
-    collapseSection(thing: string) {
-        const id = this.props.Document[Id];
-        const element = document.getElementById(thing)!;
-        // get the height of the element's inner content, regardless of its actual size
-        const sectionHeight = element.scrollHeight;
-
-        // temporarily disable all css transitions
-        const 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${id}` ? document.getElementById(`filterhead${id}`)!.style.padding = "0" : null;
-            });
-        });
-
-        // mark the section as "currently collapsed"
-        element.setAttribute('data-collapsed', 'true');
-    }
-
-    expandSection(thing: string) {
-        const element = document.getElementById(thing)!;
-        // get the height of the element's inner content, regardless of its actual size
-        const sectionHeight = element.scrollHeight;
-
-        // have the element transition to the height of its inner content
-        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
-            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) {
-        const element = document.getElementById(thing)!;
-        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;
-    }
-
-    @action.bound
-    updateTitleStatus = async () => {
-        this._titleFieldStatus = !this._titleFieldStatus;
-        if (this._titleFieldStatus) {
-            let doc = await Cast(this.props.Document.title, Doc)
-            doc!.backgroundColor = "grey";
-        }
-        else {
-            let doc = await Cast(this.props.Document.title, Doc)
-            doc!.backgroundColor = "black";
-        }
-    }
-
-    @action.bound
-    updateAuthorStatus = async () => {
-        this._authorFieldStatus = !this._authorFieldStatus;
-        if (this._authorFieldStatus) {
-            let doc = await Cast(this.props.Document.author, Doc)
-            doc!.backgroundColor = "grey";
-        }
-        else {
-            let doc = await Cast(this.props.Document.author, Doc)
-            doc!.backgroundColor = "black";
-        }
-    }
-
-    @action.bound
-    updateDeletedStatus = async () => {
-        this._deletedDocsStatus = !this._deletedDocsStatus;
-        if (this._deletedDocsStatus) {
-            let doc = await Cast(this.props.Document.deleted, Doc)
-            doc!.backgroundColor = "grey";
-        }
-        else {
-            let doc = await Cast(this.props.Document.deleted, Doc)
-            doc!.backgroundColor = "black";
-        }
-    }
-
     addButtonDoc = (doc: Doc) => Doc.AddDocToList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", doc);
     remButtonDoc = (doc: Doc) => Doc.RemoveDocFromList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", doc);
     moveButtonDoc = (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => this.remButtonDoc(doc) && addDocument(doc);
 
-    @action.bound
-    updateIcon = async (icon: string) => {
-        if (this._icons.includes(icon)) {
-            _.pull(this._icons, icon);
-            let cap = icon.charAt(0).toUpperCase() + icon.slice(1)
-            console.log(cap);
-            let doc = await Cast(this.props.Document[cap], Doc)
-            doc!.backgroundColor = "black";
-        }
-        else {
-            this._icons.push(icon);
-            let cap = icon.charAt(0).toUpperCase() + icon.slice(1)
-            let doc = await Cast(this.props.Document[cap], Doc)
-            doc!.backgroundColor = "grey";
-        }
-    }
-
-    @action.bound
-    checkIcons = async () => {
-        for (let i = 0; i < this._allIcons.length; i++) {
-
-            let cap = this._allIcons[i].charAt(0).toUpperCase() + this._allIcons[i].slice(1)
-            let doc = await Cast(this.props.Document[cap], Doc)
-            if (this._icons.includes(this._allIcons[i])) {
-                doc!.backgroundColor = "grey";
-            }
-            else {
-                doc!.backgroundColor = "black";
-            }
-        }
-    }
-
     @computed get searchItemTemplate() { return Cast(Doc.UserDoc().searchItemTemplate, Doc, null); }
 
     getTransform = () => {
@@ -1016,16 +768,15 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
 
     @observable filter = false;
 
-
     //Make id layour document
     render() {
         this.props.Document._chromeStatus === "disabled";
         this.props.Document._searchDoc = true;
-        let cols = Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []).length;
+        const cols = Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []).length;
         let length = 0;
         cols > 5 ? length = 1076 : length = cols * 205 + 51;
         let height = 0;
-        let rows = this.children;
+        const rows = this.children;
         rows > 8 ? height = 31 + 31 * 8 : height = 31 * rows + 31;
         return (
             <div style={{ pointerEvents: "all" }} className="searchBox-container">
@@ -1045,10 +796,52 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                                 this.filter = !this.filter && !this.scale;
                                 if (this.filter === true && this.currentSelectedCollection !== undefined) {
                                     this.currentSelectedCollection.props.Document._searchDocs = new List<Doc>(this.docsforfilter);
+                                    let newarray: Doc[] = [];
+                                    let docs: Doc[] = [];
+                                    docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]);
+                                    while (docs.length > 0) {
+                                        console.log("HIT");
+                                        newarray = [];
+                                        docs.forEach((d) => {
+                                            if (d.data !== undefined) {
+                                                console.log(d._searchDocs);
+                                                d._searchDocs = new List<Doc>(this.docsforfilter);
+                                                console.log(d);
+                                                console.log(d._searchDocs);
+                                                let newdocs = DocListCast(d.data);
+                                                newdocs.forEach((newdoc) => {
+                                                    newarray.push(newdoc);
+                                                });
+                                            }
+                                        });
+                                        docs = newarray;
+                                    }
+
                                     this.currentSelectedCollection.props.Document._docFilters = new List<string>(Cast(this.props.Document._docFilters, listSpec("string"), []));
                                     this.props.Document.selectedDoc = this.currentSelectedCollection.props.Document;
                                 }
                                 else if (this.filter === false && this.currentSelectedCollection !== undefined) {
+                                    let newarray: Doc[] = [];
+                                    let docs: Doc[] = [];
+                                    docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]);
+                                    while (docs.length > 0) {
+                                        console.log("HIT");
+                                        newarray = [];
+                                        docs.forEach((d) => {
+                                            if (d.data !== undefined) {
+                                                console.log(d._searchDocs);
+                                                d._searchDocs = new List<Doc>();
+                                                console.log(d);
+                                                console.log(d._searchDocs);
+                                                let newdocs = DocListCast(d.data);
+                                                newdocs.forEach((newdoc) => {
+                                                    newarray.push(newdoc);
+                                                });
+                                            }
+                                        });
+                                        docs = newarray;
+                                    }
+
                                     this.currentSelectedCollection.props.Document._searchDocs = new List<Doc>([]);
                                     this.currentSelectedCollection.props.Document._docFilters = undefined;
                                     this.props.Document.selectedDoc = undefined;
@@ -1075,12 +868,32 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                                                     this.scale = !this.scale;
                                                     this.dataDoc[this.fieldKey] = new List<Doc>([]);
                                                     if (this.currentSelectedCollection !== undefined) {
+                                                        let newarray: Doc[] = [];
+                                                        let docs: Doc[] = [];
+                                                        docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]);
+                                                        while (docs.length > 0) {
+                                                            console.log("HIT");
+                                                            newarray = [];
+                                                            docs.forEach((d) => {
+                                                                if (d.data !== undefined) {
+                                                                    console.log(d._searchDocs);
+                                                                    d._searchDocs = new List<Doc>();
+                                                                    console.log(d);
+                                                                    console.log(d._searchDocs);
+                                                                    let newdocs = DocListCast(d.data);
+                                                                    newdocs.forEach((newdoc) => {
+                                                                        newarray.push(newdoc);
+                                                                    });
+                                                                }
+                                                            });
+                                                            docs = newarray;
+                                                        }
                                                         this.currentSelectedCollection.props.Document._docFilters = undefined;
                                                         this.currentSelectedCollection.props.Document._searchDocs = undefined;
                                                         this.currentSelectedCollection = undefined;
                                                     }
                                                     this.submitSearch();
-                                                })
+                                                });
                                             }} />
                                         Collection
                                     </label>
@@ -1093,12 +906,32 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                                                     this.dataDoc[this.fieldKey] = new List<Doc>([]);
                                                     this.filter = false;
                                                     if (this.currentSelectedCollection !== undefined) {
+                                                        let newarray: Doc[] = [];
+                                                        let docs: Doc[] = [];
+                                                        docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]);
+                                                        while (docs.length > 0) {
+                                                            console.log("HIT");
+                                                            newarray = [];
+                                                            docs.forEach((d) => {
+                                                                if (d.data !== undefined) {
+                                                                    console.log(d._searchDocs);
+                                                                    d._searchDocs = new List<Doc>();
+                                                                    console.log(d);
+                                                                    console.log(d._searchDocs);
+                                                                    let newdocs = DocListCast(d.data);
+                                                                    newdocs.forEach((newdoc) => {
+                                                                        newarray.push(newdoc);
+                                                                    });
+                                                                }
+                                                            });
+                                                            docs = newarray;
+                                                        }
                                                         this.currentSelectedCollection.props.Document._docFilters = undefined;
                                                         this.currentSelectedCollection.props.Document._searchDocs = undefined;
                                                         this.currentSelectedCollection = undefined;
                                                     }
                                                     this.submitSearch();
-                                                })
+                                                });
                                             }} />
                                             DB
                                     </label>
@@ -1140,13 +973,3 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         );
     }
 }
-
-Scripting.addGlobal(function lookupSearchBoxField(container: Doc, field: string, data: Doc) {
-    // if (field === 'indexInPres') return DocListCast(container[StrCast(container.presentationFieldKey)]).indexOf(data);
-    // if (field === 'presCollapsedHeight') return container._viewType === CollectionViewType.Schema ? 50 : 46;
-    // if (field === 'presStatus') return container.presStatus;
-    // if (field === '_itemIndex') return container._itemIndex;
-    if (field == "query") return container._searchString;
-    return undefined;
-});
-
diff --git a/src/client/views/search/SearchItem.scss b/src/client/views/search/SearchItem.scss
deleted file mode 100644
index 5ce022d41..000000000
--- a/src/client/views/search/SearchItem.scss
+++ /dev/null
@@ -1,186 +0,0 @@
-@import "../globalCssVariables";
-
-.searchItem-overview {
-    display: flex;
-    flex-direction: reverse;
-    justify-content: flex-end;
-    z-index: 0;
-}
-
-.searchBox-placeholder,
-.searchItem-overview .searchItem {
-    width: 100%;
-    background: $light-color-secondary;
-    padding: 8px;
-    min-height: 46px;
-    height:46px;
-    max-height: 150px;
-    height: auto;
-    z-index: 0;
-    display: flex;
-    overflow: visible;
-    box-shadow: rgb(156, 147, 150) 0.2vw 0.2vw 0.8vw;
-
-    .searchItem-body {
-        display: flex;
-        flex-direction: row;
-        width: 100%;
-
-        .searchItem-title-container {
-            width: 100%;
-            overflow: hidden;
-
-            .searchItem-title {
-                text-transform: uppercase;
-                text-align: left;
-                width: 100%;
-                font-weight: bold;
-            }
-        }
-
-        .searchItem-info {
-            display: flex;
-            justify-content: flex-end;
-
-            .icon-icons {
-                width: 50px
-            }
-
-            .icon-live {
-                width: 175px;
-                height: 0px;
-            }
-
-            .icon-icons {
-                height:auto;
-            }
-            .icon-icons,
-            .icon-live {
-                margin: auto;
-                overflow: visible;
-
-                .searchItem-type {
-                    display: inline-block;
-                    width: 100%;
-                    position: absolute;
-                    justify-content: center;
-                    align-items: center;
-                    position: relative;
-                    margin-right: 5px;
-                }
-
-                .pdfBox-cont {
-                    overflow: hidden;
-
-                    img {
-                        width: 100% !important;
-                        height: auto !important;
-                    }
-                }
-
-                .searchItem-type:hover+.searchItem-label {
-                    opacity: 1;
-                }
-
-                .searchItem-label {
-                    font-size: 10;
-                    position: relative;
-                    right: 0px;
-                    text-transform: capitalize;
-                    opacity: 0;
-                    -webkit-transition: opacity 0.2s ease-in-out;
-                    -moz-transition: opacity 0.2s ease-in-out;
-                    -o-transition: opacity 0.2s ease-in-out;
-                    transition: opacity 0.2s ease-in-out;
-                }
-            }
-
-            .icon-live:hover {
-                .pdfBox-cont {
-                    img {
-                        width: 100% !important;
-                    }
-                }
-            }
-        }
-
-        .searchItem-info:hover {
-            width: 60%;
-        }
-    }
-}
-
-.searchItem:hover~.searchBox-instances,
-.searchBox-instances:hover,
-.searchBox-instances:active {
-    opacity: 1;
-    background: $lighter-alt-accent;
-}
-
-.searchItem:hover {
-    transition: all 0.2s;
-    background: $lighter-alt-accent;
-}
-
-.searchItem-highlighting {
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: pre;
-}
-
-.searchBox-instances {
-    opacity: 1;
-    width:40px;
-    height:40px;
-    background: gray;
-    transition: all 0.2s ease;
-    color: black;
-    overflow: hidden;
-    right:-100;
-    display:inline-block;
-}
-
-
-.searchItem-overview:hover {
-    z-index: 1;
-}
-
-.searchBox-placeholder {
-    min-height: 46px;
-    margin-left: 150px;
-    width: calc(100% - 150px);
-    text-transform: uppercase;
-    text-align: left;
-    font-weight: bold;
-}
-
-.collection {
-    display: flex;
-}
-
-.collection-item {
-    width: 35px;
-}
-
-.bucket-title{
-    width:auto;
-    padding: 5px;
-    height: auto;
-    top: -18;
-    z-index: 55;
-    position: absolute;
-}
-
-.bucket-expand{
-    bottom: 0;
-    position: absolute;
-    width: 100%;
-    height: 15;
-    transform:none;
-    .bucket-expand:hover{
-        transform:none;
-    }
-    button:hover{
-        transform:none;
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
deleted file mode 100644
index b61ed450f..000000000
--- a/src/client/views/search/SearchItem.tsx
+++ /dev/null
@@ -1,556 +0,0 @@
-import React = require("react");
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faCaretUp, faChartBar, faFile, faFilePdf, faFilm, faFingerprint, faGlobeAsia, faImage, faLink, faMusic, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, observable, runInAction, IReactionDisposer, reaction } from "mobx";
-import { observer } from "mobx-react";
-import { Doc, DocCastAsync } from "../../../fields/Doc";
-import { Id } from "../../../fields/FieldSymbols";
-import { Cast, NumCast, StrCast } from "../../../fields/Types";
-import { emptyFunction, emptyPath, returnFalse, Utils, returnTrue, returnOne, returnZero, returnEmptyString, returnEmptyFilter } from "../../../Utils";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { DocumentManager } from "../../util/DocumentManager";
-import { DragManager, SetupDrag } from "../../util/DragManager";
-import { SearchUtil } from "../../util/SearchUtil";
-import { Transform } from "../../util/Transform";
-import { SEARCH_THUMBNAIL_SIZE } from "../../views/globalCssVariables.scss";
-import { CollectionDockingView } from "../collections/CollectionDockingView";
-import { CollectionViewType, CollectionView } from "../collections/CollectionView";
-import { ParentDocSelector } from "../collections/ParentDocumentSelector";
-import { ContextMenu } from "../ContextMenu";
-import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
-import { SearchBox } from "./SearchBox";
-import "./SearchItem.scss";
-import "./SelectorContextMenu.scss";
-import { FieldViewProps, FieldView } from "../nodes/FieldView";
-import { ViewBoxBaseComponent } from "../DocComponent";
-import { makeInterface, createSchema, listSpec } from "../../../fields/Schema";
-import { documentSchema } from "../../../fields/documentSchemas";
-import { PrefetchProxy } from "../../../fields/Proxy";
-import { Docs } from "../../documents/Documents";
-import { ScriptField } from "../../../fields/ScriptField";
-import { CollectionStackingView } from "../collections/CollectionStackingView";
-
-export interface SearchItemProps {
-    doc: Doc;
-    query: string;
-    highlighting: string[];
-    lines: string[];
-}
-
-library.add(faCaretUp);
-library.add(faObjectGroup);
-library.add(faStickyNote);
-library.add(faFile);
-library.add(faFilePdf);
-library.add(faFilm);
-library.add(faMusic);
-library.add(faLink);
-library.add(faChartBar);
-library.add(faGlobeAsia, faFingerprint);
-
-@observer
-export class SelectorContextMenu extends React.Component<SearchItemProps> {
-    @observable private _docs: { col: Doc, target: Doc }[] = [];
-    @observable private _otherDocs: { col: Doc, target: Doc }[] = [];
-
-    constructor(props: SearchItemProps) {
-        super(props);
-        this.fetchDocuments();
-    }
-
-    async fetchDocuments() {
-        const aliases = (await SearchUtil.GetViewsOfDocument(this.props.doc)).filter(doc => doc !== this.props.doc);
-        const { docs } = await SearchUtil.Search("", true, { fq: `data_l:"${this.props.doc[Id]}"` });
-        const map: Map<Doc, Doc> = new Map;
-        const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search("", true, { fq: `data_l:"${doc[Id]}"` }).then(result => result.docs)));
-        allDocs.forEach((docs, index) => docs.forEach(doc => map.set(doc, aliases[index])));
-        docs.forEach(doc => map.delete(doc));
-        runInAction(() => {
-            this._docs = docs.filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance.props.Document)).map(doc => ({ col: doc, target: this.props.doc }));
-            this._otherDocs = Array.from(map.entries()).filter(entry => !Doc.AreProtosEqual(entry[0], CollectionDockingView.Instance.props.Document)).map(([col, target]) => ({ col, target }));
-
-        });
-    }
-
-    getOnClick({ col, target }: { col: Doc, target: Doc }) {
-        return () => {
-            col = Doc.IsPrototype(col) ? Doc.MakeDelegate(col) : col;
-            if (col._viewType === CollectionViewType.Freeform) {
-                const newPanX = NumCast(target.x) + NumCast(target._width) / 2;
-                const newPanY = NumCast(target.y) + NumCast(target._height) / 2;
-                col._panX = newPanX;
-                col._panY = newPanY;
-            }
-            CollectionDockingView.AddRightSplit(col);
-        };
-    }
-    render() {
-        return (
-            <div className="parents">
-                <p className="contexts">Contexts:</p>
-                {[...this._docs, ...this._otherDocs].map(doc => {
-                    const item = React.createRef<HTMLDivElement>();
-                    return <div className="collection" key={doc.col[Id] + doc.target[Id]} ref={item}>
-                        <div className="collection-item" onPointerDown={
-                            SetupDrag(item, () => doc.col, undefined, undefined, () => SearchBox.Instance.closeSearch())}>
-                            <FontAwesomeIcon icon={faStickyNote} />
-                        </div>
-                        <a onClick={this.getOnClick(doc)}>{doc.col.title}</a>
-                    </div>;
-                })}
-            </div>
-        );
-    }
-}
-
-export interface LinkMenuProps {
-    doc1: Doc;
-    doc2: Doc;
-}
-
-@observer
-export class LinkContextMenu extends React.Component<LinkMenuProps> {
-
-    highlightDoc = (doc: Doc) => () => Doc.BrushDoc(doc);
-
-    unHighlightDoc = (doc: Doc) => () => Doc.UnBrushDoc(doc);
-
-    getOnClick = (col: Doc) => () => CollectionDockingView.AddRightSplit(col);
-
-    render() {
-        return (
-            <div className="parents">
-                <p className="contexts">Anchors:</p>
-                <div className="collection"><a onMouseEnter={this.highlightDoc(this.props.doc1)} onMouseLeave={this.unHighlightDoc(this.props.doc1)} onClick={this.getOnClick(this.props.doc1)}>Doc 1: {this.props.doc2.title}</a></div>
-                <div><a onMouseEnter={this.highlightDoc(this.props.doc2)} onMouseLeave={this.unHighlightDoc(this.props.doc2)} onClick={this.getOnClick(this.props.doc2)}>Doc 2: {this.props.doc1.title}</a></div>
-            </div>
-        );
-    }
-
-}
-
-
-type SearchSchema = makeInterface<[typeof documentSchema]>;
-
-export const SearchSchema = createSchema({
-    targetDoc: Doc,
-});
-
-const SearchDocument = makeInterface(documentSchema);
-
-
-
-@observer
-export class SearchItem extends ViewBoxBaseComponent<FieldViewProps, SearchSchema>(SearchDocument) {
-
-    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SearchItem, fieldKey); }
-
-    constructor(props: any) {
-        super(props);
-        //this.rootDoc._viewType= CollectionViewType.Stacking;
-        this.props.Document._height = 46;
-        if (!this.searchItemTemplate) { // create exactly one presElmentBox template to use by any and all presentations.
-            Doc.UserDoc().searchItemTemplate = new PrefetchProxy(Docs.Create.SearchItemBoxDocument({ title: "search item template", backgroundColor: "transparent", _xMargin: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data" }));
-            // this script will be called by each presElement to get rendering-specific info that the PresBox knows about but which isn't written to the PresElement
-            // this is a design choice -- we could write this data to the presElements which would require a reaction to keep it up to date, and it would prevent
-            // the preselement docs from being part of multiple presentations since they would all have the same field, or we'd have to keep per-presentation data
-            // stored on each pres element.  
-            (this.searchItemTemplate as Doc).lookupField = ScriptField.MakeFunction("lookupSearchBoxField(container, field, data)",
-                { field: "string", data: Doc.name, container: Doc.name });
-        }
-
-    }
-
-    @observable _selected: boolean = false;
-
-    onClick = () => {
-        DocumentManager.Instance.jumpToDocument(this.rootDoc, false);
-    }
-    @observable _useIcons = true;
-    @observable _displayDim = 50;
-
-    @computed get query() { return StrCast(this.lookupField("query")); }
-
-    private _oldHeight: number = 46;
-
-    componentDidMount() {
-        let parent: Doc | undefined = undefined;
-        let height = 0;
-        if (this.rootDoc.parent) {
-            parent = Cast(this.rootDoc.parent, Doc, null);
-            if (parent !== undefined) {
-                height = (NumCast(parent._height));
-            }
-        }
-
-        this._reactionDisposer2 = reaction(
-            () => this._useIcons,
-            el => {
-                if (this.rootDoc.parent) {
-                    parent = Cast(this.rootDoc.parent, Doc, null) as Doc;
-                    height = (NumCast(parent._height));
-                };
-                console.log(height);
-                console.log(this._oldHeight);
-                setTimeout(() => {
-                    this._mainRef.current?.getBoundingClientRect() ? this.props.Document._height = this._mainRef.current?.getBoundingClientRect().height : null;
-                    parent !== undefined ? this._mainRef.current?.getBoundingClientRect() ? parent._height = -this._oldHeight + height + this._mainRef.current?.getBoundingClientRect().height : null : null;
-                    this._mainRef.current?.getBoundingClientRect() ? this._oldHeight = this._mainRef.current?.getBoundingClientRect().height : null;
-                    // this._oldHeight 55? this._oldHeight =55:null;
-                }, 1);
-            }
-        );
-
-        this._reactionDisposer3 = reaction(
-            () => this._displayLines,
-            el => {
-                if (this.rootDoc.parent) {
-                    parent = Cast(this.rootDoc.parent, Doc, null) as Doc;
-                    height = (NumCast(parent._height));
-                };
-                setTimeout(() => {
-                    this._mainRef.current?.getBoundingClientRect() ? this.props.Document._height = this._mainRef.current?.getBoundingClientRect().height : null;
-                    parent !== undefined ? this._mainRef.current?.getBoundingClientRect() ? parent._height = -this._oldHeight + height + this._mainRef.current?.getBoundingClientRect().height : null : null;
-                    this._mainRef.current?.getBoundingClientRect() ? this._oldHeight = this._mainRef.current?.getBoundingClientRect().height : null;
-                }, 1);
-            }
-        );
-
-        Doc.SetSearchQuery(this.query);
-        this.rootDoc.searchMatch = true;
-    }
-    componentWillUnmount() {
-        this.rootDoc.searchMatch = undefined;
-        this._reactionDisposer2 && this._reactionDisposer2();
-        this._reactionDisposer3 && this._reactionDisposer3();
-
-    }
-
-
-
-    private _reactionDisposer2?: IReactionDisposer;
-    private _reactionDisposer3?: IReactionDisposer;
-
-
-
-    @computed get highlightPos() { return NumCast(this.rootDoc.searchIndex) }
-
-    @action
-    public DocumentIcon() {
-        const layoutresult = StrCast(this.rootDoc.type);
-        if (!this._useIcons) {
-            const returnXDimension = () => this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE);
-            const returnYDimension = () => this._displayDim;
-            const docview = <div
-                onPointerDown={action(() => {
-                    this._useIcons = !this._useIcons;
-                    this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE);
-                })}
-                onPointerEnter={action(() => this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE))} >
-                <ContentFittingDocumentView
-                    Document={this.rootDoc}
-                    LibraryPath={emptyPath}
-                    rootSelected={returnFalse}
-                    fitToBox={StrCast(this.rootDoc.type).indexOf(DocumentType.COL) !== -1}
-                    addDocument={returnFalse}
-                    removeDocument={returnFalse}
-                    addDocTab={returnFalse}
-                    pinToPres={returnFalse}
-                    docFilters={returnEmptyFilter}
-                    ContainingCollectionDoc={undefined}
-                    ContainingCollectionView={undefined}
-                    ScreenToLocalTransform={Transform.Identity}
-                    renderDepth={1}
-                    PanelWidth={returnXDimension}
-                    PanelHeight={returnYDimension}
-                    NativeWidth={returnZero}
-                    NativeHeight={returnZero}
-                    focus={emptyFunction}
-                    moveDocument={returnFalse}
-                    parentActive={returnFalse}
-                    whenActiveChanged={returnFalse}
-                    bringToFront={returnFalse}
-                    ContentScaling={returnOne}
-                />
-            </div>;
-            return docview;
-        }
-        const button = layoutresult.indexOf(DocumentType.PDF) !== -1 ? faFilePdf :
-            layoutresult.indexOf(DocumentType.IMG) !== -1 ? faImage :
-                layoutresult.indexOf(DocumentType.RTF) !== -1 ? faStickyNote :
-                    layoutresult.indexOf(DocumentType.VID) !== -1 ? faFilm :
-                        layoutresult.indexOf(DocumentType.COL) !== -1 ? faObjectGroup :
-                            layoutresult.indexOf(DocumentType.AUDIO) !== -1 ? faMusic :
-                                layoutresult.indexOf(DocumentType.LINK) !== -1 ? faLink :
-                                    layoutresult.indexOf(DocumentType.WEB) !== -1 ? faGlobeAsia :
-                                        faCaretUp;
-        return <div><div onClick={action(() => { this._useIcons = false; this._displayDim = Number(SEARCH_THUMBNAIL_SIZE); })} >
-            <FontAwesomeIcon icon={button} size="2x" />
-        </div>
-            <div className="searchItem-label">{this.rootDoc.type ? this.rootDoc.type : "Other"}</div>
-        </div>
-            ;
-    }
-
-    collectionRef = React.createRef<HTMLDivElement>();
-
-    @action
-    pointerDown = (e: React.PointerEvent) => { e.preventDefault(); e.button === 0 && SearchBox.Instance.openSearch(e); }
-
-    @action
-    nextHighlight = (e: React.MouseEvent) => {
-        e.preventDefault();
-        e.stopPropagation();
-        //e.button === 0 && SearchBox.Instance.openSearch(e);
-
-        this.rootDoc!.searchMatch = false;
-        setTimeout(() => this.rootDoc!.searchMatch = true, 0);
-        this.rootDoc.searchIndex = NumCast(this.rootDoc.searchIndex);
-        this.length = NumCast(this.rootDoc!.length);
-    }
-
-    @action
-    nextHighlight2 = (e: React.MouseEvent) => {
-        e.preventDefault();
-        e.stopPropagation();
-
-        //e.button === 0 && SearchBox.Instance.openSearch(e);
-
-        this.rootDoc!.searchMatch2 = false;
-        setTimeout(() => this.rootDoc!.searchMatch2 = true, 0);
-        this.rootDoc.searchIndex = NumCast(this.rootDoc.searchIndex);
-
-        this.length = NumCast(this.rootDoc!.length);
-    }
-
-    @observable length: number | undefined = 0;
-
-    highlightDoc = (e: React.PointerEvent) => {
-        if (this.rootDoc!.type === DocumentType.LINK) {
-            if (this.rootDoc!.anchor1 && this.rootDoc!.anchor2) {
-
-                const doc1 = Cast(this.rootDoc!.anchor1, Doc, null);
-                const doc2 = Cast(this.rootDoc!.anchor2, Doc, null);
-                Doc.BrushDoc(doc1);
-                Doc.BrushDoc(doc2);
-            }
-        } else {
-            Doc.BrushDoc(this.rootDoc!);
-        }
-        e.stopPropagation();
-    }
-
-    unHighlightDoc = (e: React.PointerEvent) => {
-        if (this.rootDoc!.type === DocumentType.LINK) {
-            if (this.rootDoc!.anchor1 && this.rootDoc!.anchor2) {
-
-                const doc1 = Cast(this.rootDoc!.anchor1, Doc, null);
-                const doc2 = Cast(this.rootDoc!.anchor2, Doc, null);
-                Doc.UnBrushDoc(doc1);
-                Doc.UnBrushDoc(doc2);
-            }
-        } else {
-            Doc.UnBrushDoc(this.rootDoc!);
-        }
-    }
-
-    onContextMenu = (e: React.MouseEvent) => {
-        e.preventDefault();
-        e.stopPropagation();
-        ContextMenu.Instance.clearItems();
-        ContextMenu.Instance.addItem({
-            description: "Copy ID", event: () => {
-                Utils.CopyText(StrCast(this.rootDoc[Id]));
-            },
-            icon: "fingerprint"
-        });
-        ContextMenu.Instance.displayMenu(e.clientX, e.clientY);
-    }
-
-    _downX = 0;
-    _downY = 0;
-    _target: any;
-    onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
-        this._downX = e.clientX;
-        this._downY = e.clientY;
-        e.stopPropagation();
-        this._target = e.currentTarget;
-        document.removeEventListener("pointermove", this.onPointerMoved);
-        document.removeEventListener("pointerup", this.onPointerUp);
-        document.addEventListener("pointermove", this.onPointerMoved);
-        document.addEventListener("pointerup", this.onPointerUp);
-    }
-    onPointerMoved = (e: PointerEvent) => {
-        if (Math.abs(e.clientX - this._downX) > Utils.DRAG_THRESHOLD ||
-            Math.abs(e.clientY - this._downY) > Utils.DRAG_THRESHOLD) {
-            document.removeEventListener("pointermove", this.onPointerMoved);
-            document.removeEventListener("pointerup", this.onPointerUp);
-            const doc = Doc.IsPrototype(this.rootDoc) ? Doc.MakeDelegate(this.rootDoc) : this.rootDoc;
-            DragManager.StartDocumentDrag([this._target], new DragManager.DocumentDragData([doc]), e.clientX, e.clientY);
-        }
-    }
-    onPointerUp = (e: PointerEvent) => {
-        document.removeEventListener("pointermove", this.onPointerMoved);
-        document.removeEventListener("pointerup", this.onPointerUp);
-    }
-
-    @computed
-    get contextButton() {
-        return <ParentDocSelector Document={this.rootDoc} addDocTab={(doc, where) => CollectionDockingView.AddRightSplit(doc)} />;
-    }
-
-    @computed get searchElementDoc() { return this.rootDoc; }
-    // @computed get targetDoc() { return this.searchElementDoc?.targetDoc as Doc; }
-
-    @computed get searchItemTemplate() { return Cast(Doc.UserDoc().searchItemTemplate, Doc, null); }
-    childLayoutTemplate = () => this.layoutDoc._viewType === CollectionViewType.Stacking ? this.searchItemTemplate : undefined;
-    getTransform = () => {
-        return this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight
-    }
-    panelHeight = () => {
-        return this.props.PanelHeight();
-    }
-    selectElement = (doc: Doc) => {
-        //this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.layoutDoc._itemIndex));
-    }
-
-    newsearch() {
-        runInAction(() => {
-            if (StrCast(this.rootDoc.bucketfield) !== "results") {
-                SearchBox.Instance._icons = [StrCast(this.rootDoc.bucketfield)];
-                SearchBox.Instance._icons = SearchBox.Instance._icons;
-            }
-            else {
-                SearchBox.Instance._icons = SearchBox.Instance._allIcons;
-            }
-            SearchBox.Instance.submitSearch();
-        })
-    }
-
-    @action
-    returnLines() {
-        if ((Cast(this.rootDoc.lines, listSpec("string")))!.length > 1) {
-            if (!this._displayLines) {
-                console.log(Cast(this.rootDoc.lines, listSpec("string")));
-                return <div style={{ width: 10 }}
-                    onPointerDown={action(() => {
-                        this._displayLines = !this._displayLines;
-                        //this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE);
-                    })}
-                //onPointerEnter={action(() => this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE))}
-                >
-                    {Cast(this.rootDoc.lines, listSpec("string"))!.filter((m, i) => i).map((l, i) => <div style={{ overflow: "visible" }} id={i.toString()} className="searchItem-highlighting">{l}</div>)}
-                </div>;;
-            }
-        }
-    }
-
-    //this._displayDim = Number(SEARCH_THUMBNAIL_SIZE); 
-
-    @observable _displayLines: boolean = true;
-
-    returnButtons() {
-        return <div>
-            <div onClick={action(() => {
-                this.rootDoc!.type === DocumentType.PDF ? this._displayLines = !this._displayLines : null;
-            })}>
-                {this.rootDoc!.type === DocumentType.PDF ? "Expand Lines" : null}
-                {NumCast(this.rootDoc!.length) > 1 ? `Instance ${NumCast(this.rootDoc.searchIndex) === 0 ? NumCast(this.rootDoc.length) : NumCast(this.rootDoc.searchIndex)} of ${NumCast(this.rootDoc.length)}` : null}
-                <button onClick={this.nextHighlight} style={{ padding: 2, position: "absolute", left: 77 }}>
-                    <FontAwesomeIcon icon="arrow-up" size="sm" />
-                </button>
-                <button onClick={this.nextHighlight2} style={{ padding: 2, position: "absolute", left: 87 }}>
-                    <FontAwesomeIcon icon="arrow-down" size="sm" />
-                </button>
-            </div>
-            <div>
-                <div style={{ background: "lightgrey" }}>
-                    {this.returnLines()}
-                </div>
-            </div>
-        </div>
-    }
-
-    private _mainRef: React.RefObject<HTMLDivElement> = React.createRef();
-
-
-    render() {
-        const doc1 = Cast(this.rootDoc!.anchor1, Doc);
-        const doc2 = Cast(this.rootDoc!.anchor2, Doc);
-        if (StrCast(this.rootDoc.bucketfield) === "webs") {
-            this.props.Document._viewType = CollectionViewType.Stacking;
-            this.props.Document._chromeStatus = 'disabled';
-            this.props.Document._height = this.rootDoc._height;
-            return <div>
-                <CollectionView {...this.props}
-                    Document={this.props.Document}
-                    PanelHeight={this.panelHeight}
-                    whenActiveChanged={emptyFunction}
-                    onClick={undefined}
-                    moveDocument={returnFalse}
-                    childLayoutTemplate={undefined}
-                    addDocument={undefined}
-                    removeDocument={returnFalse}
-                    focus={this.selectElement}
-                    ScreenToLocalTransform={this.getTransform} />
-            </div>
-        }
-        if (this.rootDoc.isBucket === true) {
-            this.props.Document._viewType = CollectionViewType.Stacking;
-            this.props.Document._chromeStatus = 'disabled';
-            this.props.Document._height = this.rootDoc._height;
-
-            return <div>
-                <CollectionView {...this.props}
-                    Document={this.props.Document}
-                    PanelHeight={this.panelHeight}
-                    whenActiveChanged={emptyFunction}
-                    onClick={undefined}
-                    moveDocument={returnFalse}
-                    childLayoutTemplate={this.childLayoutTemplate}
-                    addDocument={undefined}
-                    removeDocument={returnFalse}
-                    focus={this.selectElement}
-                    ScreenToLocalTransform={this.getTransform} />
-                <button onClick={() => this.newsearch()} className="bucket-expand" style={{ transform: "none", fontSize: "100%", textTransform: "none", background: "lightgray", color: "black", bottom: 8, marginBottom: -2, paddingTop: 2, fontFamily: "Arial, sans-serif" }}>See all {StrCast(this.rootDoc.bucketfield)}...
-            </button>
-            </div>
-        }
-        else if (this.rootDoc.isBucket === false) {
-            this.props.Document._chromeStatus = 'disabled';
-            return <div className="searchItem">
-                <div className="searchItem-body" >
-                    <div className="searchItem-title-container">
-                        <div className="searchItem-title" style={{ height: "10px", overflow: "hidden", textOverflow: "ellipsis" }}>No Search Results</div>
-                    </div>
-                </div>
-            </div>
-        }
-        else {
-            return <div className="searchItem-overview" onPointerDown={this.pointerDown} onContextMenu={this.onContextMenu}>
-                <div ref={this._mainRef} className="searchItem" onPointerEnter={this.highlightDoc} onPointerLeave={this.unHighlightDoc}>
-                    <div className="searchItem-body" onClick={this.onClick}>
-                        <div className="searchItem-title-container">
-                            <div className="searchItem-title" style={{ height: "10px", overflow: "hidden", textOverflow: "ellipsis" }}>{StrCast(this.rootDoc.title)}</div>
-                            <div className="searchItem-highlighting">
-                                {this.rootDoc.highlighting ? StrCast(this.rootDoc.highlighting).length ? "Matched fields:" + StrCast(this.rootDoc.highlighting) : Cast(this.rootDoc.lines, listSpec("string"))!.length ? Cast(this.rootDoc.lines, listSpec("string"))![0] : "" : null}</div>
-                            <div className={`icon-${this._displayLines ? "q" : "a"}`}>
-                                {NumCast(this.rootDoc.length) > 1 || this.rootDoc!.type === DocumentType.PDF ? this.returnButtons() : null}
-                            </div>
-                        </div>
-                    </div>
-                    <div className="searchItem-info" style={{ width: this._useIcons ? "30px" : "100%" }}>
-                        <div className={`icon-${this._useIcons ? "icons" : "live"}`}>
-                            <div className="searchItem-type" title="Click to Preview" onPointerDown={this.onPointerDown}>{this.DocumentIcon()}</div>
-                        </div>
-                    </div>
-                    {/* <div className="searchItem-context" title="Drag as document">
-                    {(doc1 instanceof Doc && doc2 instanceof Doc) && this.rootDoc!.type === DocumentType.LINK ? <LinkContextMenu doc1={doc1} doc2={doc2} /> :
-                        this.contextButton}
-                </div> */}
-                </div>
-            </div>;
-        }
-    }
-} 
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 8c7196ca1eda1f89bbac3e2f24219df739978776 Mon Sep 17 00:00:00 2001
From: Andy Rickert <andrew_rickert@brown.edu>
Date: Wed, 5 Aug 2020 00:07:59 -0400
Subject: lint

---
 src/client/views/EditableView.tsx                  | 12 ++---
 .../views/collections/CollectionSchemaCells.tsx    | 25 ++--------
 .../views/collections/CollectionSchemaView.tsx     |  4 +-
 src/client/views/collections/CollectionSubView.tsx |  2 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  8 ++--
 src/client/views/search/SearchBox.tsx              | 56 +++++-----------------
 6 files changed, 31 insertions(+), 76 deletions(-)

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

diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index a98ef97ea..a5628d5ee 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -187,13 +187,13 @@ export class EditableView extends React.Component<EditableProps> {
     }
 
     returnHighlights() {
-        let results = [];
-        let contents = this.props.bing!();
+        const results = [];
+        const contents = this.props.bing!();
 
         if (contents !== undefined) {
             if (this.props.positions !== undefined) {
-                let positions = this.props.positions;
-                let length = this.props.search!.length;
+                const positions = this.props.positions;
+                const length = this.props.search!.length;
 
                 // contents = String(this.props.contents.valueOf());
 
@@ -201,10 +201,10 @@ export class EditableView extends React.Component<EditableProps> {
                 positions.forEach((num, cur) => {
                     results.push(<span style={{ backgroundColor: "#FFFF00", fontStyle: this.props.fontStyle, fontSize: this.props.fontSize, color: this.props.contents ? "black" : "grey" }}>{contents ? contents.slice(num, num + length) : this.props.placeholder?.valueOf()}</span>);
                     let end = 0;
-                    cur === positions.length - 1 ? end = contents.length : end = positions[cur + 1];
+                    cur === positions.length - 1 ? end = contents!.length : end = positions[cur + 1];
                     results.push(<span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize, color: this.props.contents ? "black" : "grey" }}>{contents ? contents.slice(num + length, end) : this.props.placeholder?.valueOf()}</span>);
                 }
-                )
+                );
             }
             return results;
         }
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index b02b4c86a..7a80f4484 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -241,7 +241,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
         //         <FontAwesomeIcon icon="expand" size="sm" />
         //     </div>
         // );   
-        let positions = [];
+        const positions = [];
         if (StrCast(this.props.Document._searchString) !== "") {
             const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
             let term = "";
@@ -256,8 +256,8 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
                     term = String(NumCast(cfield));
                 }
             }
-            let search = StrCast(this.props.Document._searchString);
-            let start = term.indexOf(search) as number;
+            const search = StrCast(this.props.Document._searchString);
+            let start = term.indexOf(search);
             let tally = 0;
             if (start !== -1) {
                 positions.push(start);
@@ -883,36 +883,27 @@ export class CollectionSchemaButtons extends CollectionSchemaCell {
         //     (!this.props.CollectionView || !this.props.CollectionView.props.isSelected() ? undefined :
         //         SetupDrag(reference, () => this._document, this.props.moveDocument, this.props.Document.schemaDoc ? "copy" : undefined)(e));
         // };
-        let doc = this.props.rowProps.original;
+        const doc = this.props.rowProps.original;
         let buttons = <div style={{
             paddingTop: 8,
             paddingLeft: 3,
         }}><button onClick={() => {
-            console.log(doc);
-            console.log(doc.searchMatch);
             doc.searchMatch = false;
-            console.log(doc.searchMatch);
             setTimeout(() => doc.searchMatch = true, 0);
-            console.log(doc.searchMatch);
             doc.searchIndex = NumCast(doc.searchIndex);
         }} style={{ padding: 2, left: 77 }}>
                 <FontAwesomeIcon icon="arrow-up" size="sm" />
             </button>
             <button onClick={() => {
                 {
-                    console.log(doc);
-                    console.log(doc.searchMatch2);
                     doc.searchMatch2 = false;
-                    console.log(doc.searchMatch2);
                     setTimeout(() => doc.searchMatch2 = true, 0);
-                    console.log(doc.searchMatch2);
                     doc.searchIndex = NumCast(doc.searchIndex);
                 }
             }} style={{ padding: 2 }}>
                 <FontAwesomeIcon icon="arrow-down" size="sm" />
             </button></div>;
         const type = StrCast(doc.type);
-        console.log(StrCast(doc.type));
         if (type === "pdf") {
             buttons = <div><button
                 style={{
@@ -923,19 +914,14 @@ export class CollectionSchemaButtons extends CollectionSchemaCell {
                 }}
 
                 onClick={() => {
-                    console.log(doc);
-                    console.log(doc.searchMatch);
                     doc.searchMatch = false;
-                    console.log(doc.searchMatch);
                     setTimeout(() => doc.searchMatch = true, 0);
-                    console.log(doc.searchMatch);
                     doc.searchIndex = NumCast(doc.searchIndex);
                 }}>
                 <FontAwesomeIcon icon="arrow-down" size="sm" />
-            </button></div >
+            </button></div >;
         }
         else if (type !== "rtf") {
-            console.log("sad");
             buttons = undefined;
         }
 
@@ -945,7 +931,6 @@ export class CollectionSchemaButtons extends CollectionSchemaCell {
         else {
             buttons = undefined;
         }
-
         return (
             <div> {buttons}</div>
         );
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index d47d41a1e..a003de0d3 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -329,14 +329,14 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
                     if (filter) {
                         Doc.setDocFilter(this.props.Document, newKey, filter, "match");
                         if (this.props.Document.selectedDoc !== undefined) {
-                            let doc = Cast(this.props.Document.selectedDoc, Doc) as Doc;
+                            const doc = Cast(this.props.Document.selectedDoc, Doc) as Doc;
                             Doc.setDocFilter(doc, newKey, filter, "match");
                         }
                     }
                     else {
                         this.props.Document._docFilters = undefined;
                         if (this.props.Document.selectedDoc !== undefined) {
-                            let doc = Cast(this.props.Document.selectedDoc, Doc) as Doc;
+                            const doc = Cast(this.props.Document.selectedDoc, Doc) as Doc;
                             doc._docFilters = undefined;
                         }
                     }
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 888f0b9e9..b896518ed 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -159,7 +159,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                                 newarray = [];
                                 newdocs.forEach((t) => {
                                     if (d.data !== undefined) {
-                                        let newdocs = DocListCast(t.data);
+                                        const newdocs = DocListCast(t.data);
                                         newdocs.forEach((newdoc) => {
                                             newarray.push(newdoc);
                                         });
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index b21596493..ab29f6889 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -298,7 +298,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
             const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true });
             const res = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
-            let length = res[0].length;
+            const length = res[0].length;
             let tr = this._editorView.state.tr;
             const flattened: TextSelection[] = [];
             res.map(r => r.map(h => flattened.push(h)));
@@ -318,7 +318,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             else if (this._searchIndex === 0 && length !== 1) {
                 this._searchIndex = length - 2;
             }
-            let index = this._searchIndex;
+            const index = this._searchIndex;
 
             Doc.GetProto(this.dataDoc).searchIndex = index;
             Doc.GetProto(this.dataDoc).length = length;
@@ -331,7 +331,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
             const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true });
             const res = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
-            let length = res[0].length;
+            const length = res[0].length;
             let tr = this._editorView.state.tr;
             const flattened: TextSelection[] = [];
             res.map(r => r.map(h => flattened.push(h)));
@@ -339,7 +339,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark));
             this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
             this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
-            let index = this._searchIndex;
+            const index = this._searchIndex;
 
             Doc.GetProto(this.dataDoc).searchIndex = index;
             Doc.GetProto(this.dataDoc).length = length;
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 001792f41..097e6c4d9 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -94,7 +94,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         }
         if (this.inputRef.current) {
             this.inputRef.current.focus();
-            runInAction(() => { this._searchbarOpen = true });
+            runInAction(() => { this._searchbarOpen = true; });
         }
         if (this.rootDoc.searchQuery && this.newAssign) {
             const sq = this.rootDoc.searchQuery;
@@ -112,11 +112,11 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                 this.submitSearch();
             });
         }
-    };
+    }
 
 
     @action
-    getViews = (doc: Doc) => SearchUtil.GetViewsOfDocument(doc);
+    getViews = (doc: Doc) => SearchUtil.GetViewsOfDocument(doc)
 
 
     @observable newsearchstring: string = "";
@@ -127,7 +127,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
 
 
         if (e.target.value === "") {
-            console.log(this._results);
             this._results.forEach(result => {
                 Doc.UnBrushDoc(result[0]);
                 result[0].searchMatch = undefined;
@@ -140,8 +139,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                 this.props.Document.selectedDoc = undefined;
 
             }
-            console.log("CLOSE");
-            runInAction(() => { this.open = false });
+            runInAction(() => { this.open = false; });
             this._openNoResults = false;
             this._results = [];
             this._resultsSet.clear();
@@ -226,7 +224,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         if (this._collectionStatus) {
             query = this.addCollectionFilter(query);
             query = query.replace(/\s+/g, ' ').trim();
-            console.log(query)
 
         }
         return query;
@@ -253,8 +250,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
 
     addCollectionFilter(query: string): string {
         const collections: Doc[] = this.getCurCollections();
-
-        console.log(collections);
         const oldWords = query.split(" ");
 
         const collectionString: string[] = [];
@@ -312,18 +307,16 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             }
             let docs = DocListCast(selectedCollection.dataDoc[Doc.LayoutFieldKey(selectedCollection.dataDoc)]);
             const found: [Doc, string[], string[]][] = [];
-            const docsforFilter: Doc[] = []
+            const docsforFilter: Doc[] = [];
             let newarray: Doc[] = [];
 
             while (docs.length > 0) {
                 newarray = [];
                 docs.forEach((d) => {
-                    if (d.data != undefined) {
+                    if (d.data !== undefined) {
                         newarray.push(...DocListCast(d.data));
                     }
-
-                    let hlights: string[] = [];
-
+                    const hlights: string[] = [];
                     const protos = Doc.GetAllPrototypes(d);
                     protos.forEach(proto => {
                         Object.keys(proto).forEach(key => {
@@ -345,15 +338,11 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                 selectedCollection.props.Document._searchDocs = new List<Doc>(docsforFilter);
                 docs = DocListCast(selectedCollection.dataDoc[Doc.LayoutFieldKey(selectedCollection.dataDoc)]);
                 while (docs.length > 0) {
-                    console.log("HIT");
                     newarray = [];
                     docs.forEach((d) => {
                         if (d.data !== undefined) {
-                            console.log(d._searchDocs);
                             d._searchDocs = new List<Doc>(docsforFilter);
-                            console.log(d);
-                            console.log(d._searchDocs);
-                            let newdocs = DocListCast(d.data);
+                            const newdocs = DocListCast(d.data);
                             newdocs.forEach((newdoc) => {
                                 newarray.push(newdoc);
                             });
@@ -449,7 +438,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         this._visibleElements = [];
         this._visibleDocuments = [];
         if (StrCast(this.props.Document.searchQuery)) {
-            if (this._timeout) { clearTimeout(this._timeout); this._timeout = undefined };
+            if (this._timeout) { clearTimeout(this._timeout); this._timeout = undefined; }
             this._timeout = setTimeout(() => {
                 console.log("Resubmitting search");
             }, 60000);
@@ -526,7 +515,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                             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)) : [];
-                            console.log(hlights);
                             doc ? console.log(Cast(doc.context, Doc)) : null;
                             if (this.findCommonElements(hlights)) {
                             }
@@ -683,7 +671,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                         if (result) {
                             const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
                             const lines = new List<string>(result[2]);
-                            console.log(lines);
                             result[0].lines = lines;
                             result[0].highlighting = highlights.join(", ");
                             highlights.forEach((item) => headers.add(item));
@@ -701,7 +688,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                             const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
                             const lines = new List<string>(result[2]);
                             highlights.forEach((item) => headers.add(item));
-                            console.log(lines);
                             result[0].lines = lines;
                             result[0].highlighting = highlights.join(", ");
                             result[0].searchMatch = true;
@@ -796,15 +782,11 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                                     let docs: Doc[] = [];
                                     docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]);
                                     while (docs.length > 0) {
-                                        console.log("HIT");
                                         newarray = [];
                                         docs.forEach((d) => {
                                             if (d.data !== undefined) {
-                                                console.log(d._searchDocs);
                                                 d._searchDocs = new List<Doc>(this.docsforfilter);
-                                                console.log(d);
-                                                console.log(d._searchDocs);
-                                                let newdocs = DocListCast(d.data);
+                                                const newdocs = DocListCast(d.data);
                                                 newdocs.forEach((newdoc) => {
                                                     newarray.push(newdoc);
                                                 });
@@ -821,15 +803,11 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                                     let docs: Doc[] = [];
                                     docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]);
                                     while (docs.length > 0) {
-                                        console.log("HIT");
                                         newarray = [];
                                         docs.forEach((d) => {
                                             if (d.data !== undefined) {
-                                                console.log(d._searchDocs);
                                                 d._searchDocs = new List<Doc>();
-                                                console.log(d);
-                                                console.log(d._searchDocs);
-                                                let newdocs = DocListCast(d.data);
+                                                const newdocs = DocListCast(d.data);
                                                 newdocs.forEach((newdoc) => {
                                                     newarray.push(newdoc);
                                                 });
@@ -868,15 +846,11 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                                                         let docs: Doc[] = [];
                                                         docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]);
                                                         while (docs.length > 0) {
-                                                            console.log("HIT");
                                                             newarray = [];
                                                             docs.forEach((d) => {
                                                                 if (d.data !== undefined) {
-                                                                    console.log(d._searchDocs);
                                                                     d._searchDocs = new List<Doc>();
-                                                                    console.log(d);
-                                                                    console.log(d._searchDocs);
-                                                                    let newdocs = DocListCast(d.data);
+                                                                    const newdocs = DocListCast(d.data);
                                                                     newdocs.forEach((newdoc) => {
                                                                         newarray.push(newdoc);
                                                                     });
@@ -906,15 +880,11 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                                                         let docs: Doc[] = [];
                                                         docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]);
                                                         while (docs.length > 0) {
-                                                            console.log("HIT");
                                                             newarray = [];
                                                             docs.forEach((d) => {
                                                                 if (d.data !== undefined) {
-                                                                    console.log(d._searchDocs);
                                                                     d._searchDocs = new List<Doc>();
-                                                                    console.log(d);
-                                                                    console.log(d._searchDocs);
-                                                                    let newdocs = DocListCast(d.data);
+                                                                    const newdocs = DocListCast(d.data);
                                                                     newdocs.forEach((newdoc) => {
                                                                         newarray.push(newdoc);
                                                                     });
-- 
cgit v1.2.3-70-g09d2


From 85fee2871fcbfba90ca9ce3ba4a1842e85e41f9f Mon Sep 17 00:00:00 2001
From: Andy Rickert <andrew_rickert@brown.edu>
Date: Wed, 5 Aug 2020 01:17:28 -0400
Subject:  lint

---
 src/client/util/CurrentUserUtils.ts                |   1 -
 src/client/views/EditableView.tsx                  |   4 +-
 src/client/views/MainView.tsx                      |   9 +-
 .../views/collections/CollectionSchemaCells.tsx    |  11 +-
 src/client/views/collections/CollectionSubView.tsx |   4 +-
 src/client/views/linking/LinkMenuItem.tsx          |   1 -
 src/client/views/nodes/DocumentLinksButton.tsx     |   2 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |   3 +-
 .../views/nodes/formattedText/RichTextMenu.tsx     |   3 +-
 src/client/views/search/FieldFilters.scss          |  12 -
 src/client/views/search/FieldFilters.tsx           |  41 --
 src/client/views/search/FilterBox.scss             | 178 ---------
 src/client/views/search/FilterBox.tsx              | 431 ---------------------
 src/server/websocket.ts                            |   8 +-
 14 files changed, 25 insertions(+), 683 deletions(-)
 delete mode 100644 src/client/views/search/FieldFilters.scss
 delete mode 100644 src/client/views/search/FieldFilters.tsx
 delete mode 100644 src/client/views/search/FilterBox.scss
 delete mode 100644 src/client/views/search/FilterBox.tsx

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

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index ea701ec33..53d187aa0 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -771,7 +771,6 @@ export class CurrentUserUtils {
 
     // setup the list of sidebar mode buttons which determine what is displayed in the sidebar
     static async setupSidebarButtons(doc: Doc) {
-        this.setupSidebarContainer(doc);
         await CurrentUserUtils.setupToolsBtnPanel(doc);
         CurrentUserUtils.setupWorkspaces(doc);
         CurrentUserUtils.setupCatalog(doc);
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index a5628d5ee..ec3e754fb 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -197,11 +197,11 @@ export class EditableView extends React.Component<EditableProps> {
 
                 // contents = String(this.props.contents.valueOf());
 
-                results.push(<span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize, color: this.props.contents ? "black" : "grey" }}>{contents ? contents.slice(0, this.props.positions![0]) : this.props.placeholder?.valueOf()}</span>);
+                results.push(<span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize, color: this.props.contents ? "black" : "grey" }}>{contents ? contents.slice(0, this.props.positions[0]) : this.props.placeholder?.valueOf()}</span>);
                 positions.forEach((num, cur) => {
                     results.push(<span style={{ backgroundColor: "#FFFF00", fontStyle: this.props.fontStyle, fontSize: this.props.fontSize, color: this.props.contents ? "black" : "grey" }}>{contents ? contents.slice(num, num + length) : this.props.placeholder?.valueOf()}</span>);
                     let end = 0;
-                    cur === positions.length - 1 ? end = contents!.length : end = positions[cur + 1];
+                    cur === positions.length - 1 ? end = contents.length : end = positions[cur + 1];
                     results.push(<span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize, color: this.props.contents ? "black" : "grey" }}>{contents ? contents.slice(num + length, end) : this.props.placeholder?.valueOf()}</span>);
                 }
                 );
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 119fa3451..1b2dd1c44 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -82,8 +82,8 @@ export class MainView extends React.Component {
     @computed public get mainFreeform(): Opt<Doc> { return (docs => (docs && docs.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); }
     @computed public get searchDoc() { return Cast(this.userDoc["search-panel"], Doc) as Doc; }
 
-
-    @observable public sidebarContent: any = this.userDoc?.["sidebar"];
+    sidebar: string = "sidebar";
+    @observable public sidebarContent: any = this.userDoc?.[this.sidebar];
     @observable public panelContent: string = "none";
     @observable public showProperties: boolean = false;
     public isPointerDown = false;
@@ -193,8 +193,9 @@ export class MainView extends React.Component {
         }
         if (targets && targets.length && SearchBox.Instance._searchbarOpen) {
             let check = false;
+            const icon = "icon";
             targets.forEach((thing) => {
-                if (thing.className.toString() === "collectionSchemaView-table" || (thing as any)?.dataset["icon"] === "filter" || thing.className.toString() === "beta" || thing.className.toString() === "collectionSchemaView-menuOptions-wrapper") {
+                if (thing.className.toString() === "collectionSchemaView-table" || (thing as any)?.dataset[icon] === "filter" || thing.className.toString() === "beta" || thing.className.toString() === "collectionSchemaView-menuOptions-wrapper") {
                     check = true;
                 }
             });
@@ -731,7 +732,7 @@ export class MainView extends React.Component {
     @computed get search() {
         return <div className="mainView-searchPanel">
             {/* <div style={{ float: "left", marginLeft: "10px" }}>{Doc.CurrentUserEmail}</div> */}
-            <div><DocumentView Document={this.searchDoc!}
+            <div><DocumentView Document={this.searchDoc}
                 DataDoc={undefined}
                 LibraryPath={emptyPath}
                 addDocument={undefined}
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 7a80f4484..98b7b7739 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -32,6 +32,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import DatePicker from "react-datepicker";
 import "react-datepicker/dist/react-datepicker.css";
 import { DateField } from "../../../fields/DateField";
+import { RichTextField } from "../../../fields/RichTextField";
 const path = require('path');
 
 library.add(faExpand);
@@ -292,8 +293,11 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
                             bing={() => {
                                 const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
                                 if (cfield !== undefined) {
-                                    if (cfield.Text !== undefined) {
-                                        return (cfield.Text);
+                                    console.log(typeof (cfield));
+                                    // if (typeof(cfield)===RichTextField)
+                                    const a = cfield as RichTextField;
+                                    if (a.Text !== undefined) {
+                                        return (a.Text);
                                     }
                                     else if (StrCast(cfield)) {
                                         return StrCast(cfield);
@@ -884,7 +888,8 @@ export class CollectionSchemaButtons extends CollectionSchemaCell {
         //         SetupDrag(reference, () => this._document, this.props.moveDocument, this.props.Document.schemaDoc ? "copy" : undefined)(e));
         // };
         const doc = this.props.rowProps.original;
-        let buttons = <div style={{
+        let buttons: JSX.Element | undefined = undefined;
+        buttons = <div style={{
             paddingTop: 8,
             paddingLeft: 3,
         }}><button onClick={() => {
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index b896518ed..4025e25f9 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -151,10 +151,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                         console.log(d);
                         let newdocs = DocListCast(d.data);
                         if (newdocs.length > 0) {
-                            let vibecheck = false;
-
+                            let vibecheck: boolean | undefined = undefined;
                             let newarray: Doc[] = [];
-
                             while (newdocs.length > 0) {
                                 newarray = [];
                                 newdocs.forEach((t) => {
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 6feb0a398..f4aed94e7 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -191,7 +191,6 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
             case DocumentType.AUDIO: destinationIcon = "microphone"; break;
             case DocumentType.BUTTON: destinationIcon = "bolt"; break;
             case DocumentType.PRES: destinationIcon = "tv"; break;
-            case DocumentType.QUERY: destinationIcon = "search"; break;
             case DocumentType.SCRIPTING: destinationIcon = "terminal"; break;
             case DocumentType.IMPORT: destinationIcon = "cloud-upload-alt"; break;
             case DocumentType.DOCHOLDER: destinationIcon = "expand"; break;
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 4713ce447..025669b41 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -125,7 +125,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
         } else if (this.props.InMenu && !this.props.StartLink && DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View) {
             const linkDoc = DocUtils.MakeLink({ doc: DocumentLinksButton.StartLink.props.Document }, { doc: this.props.View.props.Document }, "long drag");
             // this notifies any of the subviews that a document is made so that they can make finer-grained hyperlinks ().  see note above in onLInkButtonMoved
-            DocumentLinksButton.StartLink!._link = this.props.View._link = linkDoc;
+            DocumentLinksButton.StartLink._link = this.props.View._link = linkDoc;
             setTimeout(action(() => DocumentLinksButton.StartLink!._link = this.props.View._link = undefined), 0);
             LinkManager.currentLink = linkDoc;
             if (linkDoc) {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index ab29f6889..a1f576029 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -236,7 +236,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) {
                 if (!this._applyingChange && json.replace(/"selection":.*/, "") !== curProto?.Data.replace(/"selection":.*/, "")) {
                     this._applyingChange = true;
-                    (curText !== Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text) && (this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()))) && (this.dataDoc["lastModified"] = new DateField(new Date(Date.now())));
+                    const lastmodified = "lastmodified";
+                    (curText !== Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text) && (this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()))) && (this.dataDoc[lastmodified] = new DateField(new Date(Date.now())));
                     if ((!curTemp && !curProto) || curText || curLayout?.Data.includes("dash")) { // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
                         if (json.replace(/"selection":.*/, "") !== curLayout?.Data.replace(/"selection":.*/, "")) {
                             !curText && tx.storedMarks?.map(m => m.type.name === "pFontSize" && (Doc.UserDoc().fontSize = this.layoutDoc._fontSize = m.attrs.fontSize));
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 6e268be48..5af07c15d 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -903,8 +903,9 @@ export default class RichTextMenu extends AntimodeMenu {
             ref_node = pos.nodeBefore;
         }
         if (pos.nodeAfter !== null && pos.nodeAfter !== undefined) {
-            if (!pos.nodeBefore || this.view.state.selection.$from.pos !== this.view.state.selection.$to.pos)
+            if (!pos.nodeBefore || this.view.state.selection.$from.pos !== this.view.state.selection.$to.pos) {
                 ref_node = pos.nodeAfter;
+            }
         }
         if (!ref_node && pos.pos > 0) {
             let skip = false;
diff --git a/src/client/views/search/FieldFilters.scss b/src/client/views/search/FieldFilters.scss
deleted file mode 100644
index e1d0d8df5..000000000
--- a/src/client/views/search/FieldFilters.scss
+++ /dev/null
@@ -1,12 +0,0 @@
-.field-filters {
-    width: 100%;
-    display: grid;
-    // grid-template-columns: 18% 20% 60%;
-    grid-template-columns: 20% 25% 60%;
-}
-
-.field-filters-required {
-    width: 100%;
-    display: grid;
-    grid-template-columns: 50% 50%;
-}
\ No newline at end of file
diff --git a/src/client/views/search/FieldFilters.tsx b/src/client/views/search/FieldFilters.tsx
deleted file mode 100644
index 7a33282d2..000000000
--- a/src/client/views/search/FieldFilters.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import * as React from 'react';
-import { observable } from 'mobx';
-import { CheckBox } from './CheckBox';
-import { Keys } from './FilterBox';
-import "./FieldFilters.scss";
-
-export interface FieldFilterProps {
-    titleFieldStatus: boolean;
-    dataFieldStatus: boolean;
-    authorFieldStatus: boolean;
-    updateTitleStatus(stat: boolean): void;
-    updateAuthorStatus(stat: boolean): void;
-    updateDataStatus(stat: boolean): void;
-}
-
-export class FieldFilters extends React.Component<FieldFilterProps> {
-
-    static Instance: FieldFilters;
-
-    @observable public _resetBoolean = false;
-    @observable public _resetCounter: number = 0;
-
-    constructor(props: FieldFilterProps) {
-        super(props);
-        FieldFilters.Instance = this;
-    }
-
-    resetFieldFilters() {
-        this._resetBoolean = true;
-    }
-
-    render() {
-        return (
-            <div className="field-filters">
-                <CheckBox default={true} numCount={3} parent={this} originalStatus={this.props.titleFieldStatus} updateStatus={this.props.updateTitleStatus} title={Keys.TITLE} />
-                <CheckBox default={true} numCount={3} parent={this} originalStatus={this.props.authorFieldStatus} updateStatus={this.props.updateAuthorStatus} title={Keys.AUTHOR} />
-                <CheckBox default={false} numCount={3} parent={this} originalStatus={this.props.dataFieldStatus} updateStatus={this.props.updateDataStatus} title={"Deleted Docs"} />
-            </div>
-        );
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/search/FilterBox.scss b/src/client/views/search/FilterBox.scss
deleted file mode 100644
index 094ea9cc5..000000000
--- a/src/client/views/search/FilterBox.scss
+++ /dev/null
@@ -1,178 +0,0 @@
-@import "../globalCssVariables";
-@import "./NaviconButton.scss";
-
-.filter-form {
-    padding: 25px;
-    width: 440px;
-    position: relative;
-    right: 1px;
-    color: grey;
-    flex-direction: column;
-    display: inline-block;
-    transform-origin: top;
-    overflow: auto;
-    border-bottom: solid black 3px;
-
-    .top-filter-header {
-
-        #header {
-            text-transform: uppercase;
-            letter-spacing: 2px;
-            font-size: 13;
-            width: 80%;
-        }
-
-        .close-icon {
-            width: 20%;
-            opacity: .6;
-            position: relative;
-            display: block;
-
-            .line {
-                display: block;
-                background: $alt-accent;
-                width: 20;
-                height: 3;
-                position: absolute;
-                right: 0;
-                border-radius: ($height-line / 2);
-
-                &.line-1 {
-                    transform: rotate(45deg);
-                    top: 45%;
-                }
-
-                &.line-2 {
-                    transform: rotate(-45deg);
-                    top: 45%;
-                }
-            }
-        }
-
-        .close-icon:hover {
-            opacity: 1;
-        }
-
-    }
-
-    .filter-options {
-
-        .filter-div {
-            margin-top: 10px;
-            margin-bottom: 10px;
-            display: inline-block;
-            width: 100%;
-            border-color: rgba(178, 206, 248, .2); // $darker-alt-accent
-            border-top-style: solid;
-
-            .filter-header {
-                display: flex;
-                align-items: center;
-                margin-bottom: 10px;
-                letter-spacing: 2px;
-
-                .filter-title {
-                    font-size: 13;
-                    text-transform: uppercase;
-                    margin-top: 10px;
-                    margin-bottom: 10px;
-                    -webkit-transition: all 0.2s ease-in-out;
-                    -moz-transition: all 0.2s ease-in-out;
-                    -o-transition: all 0.2s ease-in-out;
-                    transition: all 0.2s ease-in-out;
-                }
-            }
-
-            .filter-header:hover .filter-title {
-                transform: scale(1.05);
-            }
-
-            .filter-panel {
-                max-height: 0px;
-                width: 100%;
-                overflow: hidden;
-                opacity: 0;
-                transform-origin: top;
-                -webkit-transition: all 0.2s ease-in-out;
-                -moz-transition: all 0.2s ease-in-out;
-                -o-transition: all 0.2s ease-in-out;
-                transition: all 0.2s ease-in-out;
-                text-align: center;
-            }
-        }
-    }
-
-    .filter-buttons {
-        border-color: rgba(178, 206, 248, .2); // $darker-alt-accent
-        border-top-style: solid;
-        padding-top: 10px;
-    }
-}
-
-.active-filters {
-    display: flex;
-    flex-direction: row-reverse;
-    justify-content: flex-end;
-    width: 100%;
-    margin-right: 30px;
-    position: relative;
-
-    .active-icon {
-        max-width: 40px;
-        flex: initial;
-
-        &.icon {
-            width: 40px;
-            text-align: center;
-            margin-bottom: 5px;
-            position: absolute;
-        }
-
-        &.container {
-            display: flex;
-            flex-direction: column;
-            width: 40px;
-        }
-
-        &.description {
-            text-align: center;
-            top: 40px;
-            position: absolute;
-            width: 40px;
-            font-size: 9px;
-            opacity: 0;
-            -webkit-transition: all 0.2s ease-in-out;
-            -moz-transition: all 0.2s ease-in-out;
-            -o-transition: all 0.2s ease-in-out;
-            transition: all 0.2s ease-in-out;
-        }
-
-        &.icon:hover+.description {
-            opacity: 1;
-        }
-    }
-
-    .col-icon {
-        height: 35px;
-        margin-left: 5px;
-        width: 35px;
-        background-color: black;
-        color: white;
-        border-radius: 50%;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-
-        .save-filter,
-        .reset-filter,
-        .all-filter {
-            background-color: gray;
-        }
-
-        .save-filter:hover,
-        .reset-filter:hover,
-        .all-filter:hover {
-            background-color: $darker-alt-accent;
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx
deleted file mode 100644
index eb61f9a14..000000000
--- a/src/client/views/search/FilterBox.tsx
+++ /dev/null
@@ -1,431 +0,0 @@
-import * as React from 'react';
-import { observer } from 'mobx-react';
-import { observable, action } from 'mobx';
-import "./SearchBox.scss";
-import { faTimes, faCheckCircle, faObjectGroup } from '@fortawesome/free-solid-svg-icons';
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { Doc } from '../../../fields/Doc';
-import { Id } from '../../../fields/FieldSymbols';
-import { DocumentType } from "../../documents/DocumentTypes";
-import { Cast, StrCast } from '../../../fields/Types';
-import * as _ from "lodash";
-import { IconBar } from './IconBar';
-import { FieldFilters } from './FieldFilters';
-import { SelectionManager } from '../../util/SelectionManager';
-import { DocumentView } from '../nodes/DocumentView';
-import { CollectionFilters } from './CollectionFilters';
-import * as $ from 'jquery';
-import "./FilterBox.scss";
-import { SearchBox } from './SearchBox';
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-
-library.add(faTimes);
-library.add(faCheckCircle);
-library.add(faObjectGroup);
-
-export enum Keys {
-    TITLE = "title",
-    AUTHOR = "author",
-    DATA = "data"
-}
-
-@observer
-export class FilterBox extends React.Component {
-
-    static Instance: FilterBox;
-    public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.RTF, 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 _basicWordStatus: boolean = true;
-    @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;
-    @observable private _wordStatusOpen: boolean = false;
-    @observable private _typeOpen: boolean = false;
-    @observable private _colOpen: boolean = false;
-    @observable private _fieldOpen: boolean = false;
-    public _pointerTime: number = -1;
-
-    constructor(props: Readonly<{}>) {
-        super(props);
-        FilterBox.Instance = this;
-    }
-    setupAccordion() {
-        $('document').ready(function () {
-            const acc = document.getElementsByClassName('filter-header');
-            // tslint:disable-next-line: prefer-for-of
-            for (let i = 0; i < acc.length; i++) {
-                acc[i].addEventListener("click", function (this: HTMLElement) {
-                    this.classList.toggle("active");
-
-                    const panel = this.nextElementSibling as HTMLElement;
-                    if (panel.style.maxHeight) {
-                        panel.style.overflow = "hidden";
-                        panel.style.maxHeight = "";
-                        panel.style.opacity = "0";
-                    } else {
-                        setTimeout(() => {
-                            panel.style.overflow = "visible";
-                        }, 200);
-                        setTimeout(() => {
-                            panel.style.opacity = "1";
-                        }, 50);
-                        panel.style.maxHeight = panel.scrollHeight + "px";
-
-                    }
-                });
-
-                const el = acc[i] as HTMLElement;
-                el.click();
-            }
-        });
-    }
-
-    @action.bound
-    minimizeAll() {
-        $('document').ready(function () {
-            const acc = document.getElementsByClassName('filter-header');
-
-            // tslint:disable-next-line: prefer-for-of
-            for (var i = 0; i < acc.length; i++) {
-                const classList = acc[i].classList;
-                if (classList.contains("active")) {
-                    acc[i].classList.toggle("active");
-                    const panel = acc[i].nextElementSibling as HTMLElement;
-                    panel.style.overflow = "hidden";
-                    panel.style.maxHeight = "";
-                }
-            }
-        });
-    }
-
-    @action.bound
-    resetFilters = () => {
-        this._basicWordStatus = true;
-        IconBar.Instance.selectAll();
-        FieldFilters.Instance.resetFieldFilters();
-    }
-
-    basicRequireWords(query: string): string {
-        const oldWords = query.split(" ");
-        const newWords: string[] = [];
-        oldWords.forEach(word => {
-            const newWrd = "+" + word;
-            newWords.push(newWrd);
-        });
-        query = newWords.join(" ");
-
-        return query;
-    }
-
-    basicFieldFilters(query: string, type: string): string {
-        const oldWords = query.split(" ");
-        let mod = "";
-
-        if (type === Keys.AUTHOR) {
-            mod = " author_t:";
-        } if (type === Keys.DATA) {
-            //TODO
-        } if (type === Keys.TITLE) {
-            mod = " title_t:";
-        }
-
-        const newWords: string[] = [];
-        oldWords.forEach(word => {
-            const newWrd = mod + word;
-            newWords.push(newWrd);
-        });
-
-        query = newWords.join(" ");
-
-        return query;
-    }
-
-    applyBasicFieldFilters(query: string) {
-        let finalQuery = "";
-
-        if (this._titleFieldStatus) {
-            finalQuery = finalQuery + this.basicFieldFilters(query, Keys.TITLE);
-        }
-        if (this._authorFieldStatus) {
-            finalQuery = finalQuery + this.basicFieldFilters(query, Keys.AUTHOR);
-        }
-        if (this._deletedDocsStatus) {
-            finalQuery = finalQuery + this.basicFieldFilters(query, Keys.DATA);
-        }
-        return finalQuery;
-    }
-
-    get fieldFiltersApplied() { return !(this._authorFieldStatus && this._titleFieldStatus); }
-
-    //TODO: basically all of this
-    //gets all of the collections of all the docviews that are selected
-    //if a collection is the only thing selected, search only in that collection (not its container)
-    getCurCollections(): Doc[] {
-        const selectedDocs: DocumentView[] = SelectionManager.SelectedDocuments();
-        const collections: Doc[] = [];
-
-        selectedDocs.forEach(async element => {
-            const layout: string = StrCast(element.props.Document.layout);
-            //checks if selected view (element) is a collection. if it is, adds to list to search through
-            if (layout.indexOf("Collection") > -1) {
-                //makes sure collections aren't added more than once
-                if (!collections.includes(element.props.Document)) {
-                    collections.push(element.props.Document);
-                }
-            }
-            //makes sure collections aren't added more than once
-            if (element.props.ContainingCollectionDoc && !collections.includes(element.props.ContainingCollectionDoc)) {
-                collections.push(element.props.ContainingCollectionDoc);
-            }
-        });
-
-        return collections;
-    }
-
-    getFinalQuery(query: string): string {
-        //alters the query so it looks in the correct fields
-        //if this is true, then not all of the field boxes are checked
-        //TODO: data
-        if (this.fieldFiltersApplied) {
-            query = this.applyBasicFieldFilters(query);
-            query = query.replace(/\s+/g, ' ').trim();
-        }
-
-        //alters the query based on if all words or any words are required
-        //if this._wordstatus is false, all words are required and a + is added before each
-        if (!this._basicWordStatus) {
-            query = this.basicRequireWords(query);
-            query = query.replace(/\s+/g, ' ').trim();
-        }
-
-        //if should be searched in a specific collection
-        if (this._collectionStatus) {
-            query = this.addCollectionFilter(query);
-            query = query.replace(/\s+/g, ' ').trim();
-        }
-        return query;
-    }
-
-    addCollectionFilter(query: string): string {
-        const collections: Doc[] = this.getCurCollections();
-        const oldWords = query.split(" ");
-
-        const collectionString: string[] = [];
-        collections.forEach(doc => {
-            const proto = doc.proto;
-            const protoId = (proto || doc)[Id];
-            const colString: string = "{!join from=data_l to=id}id:" + protoId + " ";
-            collectionString.push(colString);
-        });
-
-        let finalColString = collectionString.join(" ");
-        finalColString = finalColString.trim();
-        return "+(" + finalColString + ")" + query;
-    }
-
-    get filterTypes() {
-        return this._icons.length === 9 ? undefined : this._icons;
-    }
-
-    @action
-    filterDocsByType(docs: Doc[]) {
-        if (this._icons.length === 9) {
-            return docs;
-        }
-        const finalDocs: Doc[] = [];
-        docs.forEach(doc => {
-            const layoutresult = Cast(doc.type, "string");
-            if (layoutresult && this._icons.includes(layoutresult)) {
-                finalDocs.push(doc);
-            }
-        });
-        return finalDocs;
-    }
-
-    getABCicon() {
-        return (
-            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.8 87.8" height="35">
-                <path d="M25.4 47.9c-1.3 1.3-1.9 2.8-1.9 4.8 0 3.8 2.3 6.1 6.1 6.1 5.1 0 8-3.3 9-6.2 0.2-0.7 0.4-1.4 0.4-2.1v-6.1c-0.1 0-0.1 0-0.2 0C32.2 44.5 27.7 45.6 25.4 47.9z" />
-                <path d="M64.5 28.6c-2.2 0-4.1 1.5-4.7 3.8l0 0.2c-0.1 0.3-0.1 0.7-0.1 1.1v3.3c0 0.4 0.1 0.8 0.2 1.1 0.6 2.2 2.4 3.6 4.6 3.6 3.2 0 5.2-2.6 5.2-6.7C69.5 31.8 68 28.6 64.5 28.6z" />
-                <path d="M43.9 0C19.7 0 0 19.7 0 43.9s19.7 43.9 43.9 43.9 43.9-19.6 43.9-43.9S68.1 0 43.9 0zM40.1 65.5l-0.5-4c-3 3.1-7.4 4.9-12.1 4.9 -6.8 0-13.6-4.4-13.6-12.8 0-4 1.3-7.4 4-10 4.1-4.1 11.1-6.2 20.8-6.3 0-5.5-2.9-8.4-8.3-8.4 -3.6 0-7.4 1.1-10.2 2.9l-1.1 0.7 -2.4-6.9 0.7-0.4c3.7-2.4 8.9-3.8 14.1-3.8 10.9 0 16.7 6.2 16.7 17.9V54.6c0 4.1 0.2 7.2 0.7 9.7L49 65.5H40.1zM65.5 67.5c1.8 0 3-0.5 4-0.9l0.5-0.2 0.8 3.4 -0.3 0.2c-1 0.5-3 1.1-5.5 1.1 -5.8 0-9.7-4-9.7-9.9 0-6.1 4.3-10.3 10.4-10.3 2.1 0 4 0.5 4.9 1l0.3 0.2 -1 3.5 -0.5-0.3c-0.7-0.4-1.8-0.8-3.7-0.8 -3.7 0-6.1 2.6-6.1 6.6C59.5 64.8 61.9 67.5 65.5 67.5zM65 45.3c-2.5 0-4.5-0.9-5.9-2.7l-0.1 2.3h-3.8l0-0.5c0.1-1.2 0.2-3.1 0.2-4.8V16.7h4.3v10.8c1.4-1.6 3.5-2.5 6-2.5 2.2 0 4.1 0.8 5.5 2.3 1.8 1.8 2.8 4.5 2.8 7.7C73.8 42.1 69.3 45.3 65 45.3z" />
-            </svg>
-        );
-    }
-
-    getTypeIcon() {
-        return (
-            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.8 87.8" height="35">
-                <path d="M43.9 0C19.7 0 0 19.7 0 43.9s19.7 43.9 43.9 43.9 43.9-19.6 43.9-43.9S68.1 0 43.9 0zM43.9 12.2c4.1 0 7.5 3.4 7.5 7.5 0 4.1-3.4 7.5-7.5 7.5 -4.1 0-7.5-3.4-7.5-7.5C36.4 15.5 39.7 12.2 43.9 12.2zM11.9 50.4l7.5-13 7.5 13H11.9zM47.6 75.7h-7.5l-3.7-6.5 3.8-6.5h7.5l3.8 6.5L47.6 75.7zM70.7 70.7c-0.2 0.2-0.4 0.3-0.7 0.3s-0.5-0.1-0.7-0.3l-25.4-25.4 -25.4 25.4c-0.2 0.2-0.4 0.3-0.7 0.3s-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1 0-1.4l25.4-25.4 -25.4-25.4c-0.4-0.4-0.4-1 0-1.4s1-0.4 1.4 0l25.4 25.4 25.4-25.4c0.4-0.4 1-0.4 1.4 0s0.4 1 0 1.4l-25.4 25.4 25.4 25.4C71.1 69.7 71.1 70.3 70.7 70.7zM61.4 51.4v-15h15v15H61.4z" />
-            </svg>
-        );
-    }
-
-    getKeyIcon() {
-        return (
-            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.8 87.8" height="35">
-                <path d="M38.5 32.4c0 3.4-2.7 6.1-6.1 6.1 -3.4 0-6.1-2.7-6.1-6.1 0-3.4 2.8-6.1 6.1-6.1C35.8 26.3 38.5 29 38.5 32.4zM87.8 43.9c0 24.2-19.6 43.9-43.9 43.9S0 68.1 0 43.9C0 19.7 19.7 0 43.9 0S87.8 19.7 87.8 43.9zM66.8 60.3L50.2 43.7c-0.5-0.5-0.6-1.2-0.4-1.8 2.4-5.6 1.1-12.1-3.2-16.5 -5.9-5.8-15.4-5.8-21.2 0l0 0c-4.3 4.3-5.6 10.8-3.2 16.5 3.2 7.6 12 11.2 19.7 8 0.6-0.3 1.4-0.1 1.8 0.4l3.1 3.1h3.9c1.2 0 2.2 1 2.2 2.2v3.6h3.6c1.2 0 2.2 1 2.2 2.2v4l1.6 1.6h6.5V60.3z" />
-            </svg>
-        );
-    }
-
-    getColIcon() {
-        return (
-            <div className="col-icon">
-                <FontAwesomeIcon icon={faObjectGroup} size="lg" />
-            </div>
-        );
-    }
-
-    @action.bound
-    openFilter = () => {
-        this._filterOpen = !this._filterOpen;
-        SearchBox.Instance.closeResults();
-        this.setupAccordion();
-    }
-
-    //if true, any keywords can be used. if false, all keywords are required.
-    @action.bound
-    handleWordQueryChange = () => {
-        this._basicWordStatus = !this._basicWordStatus;
-    }
-
-    @action.bound
-    updateIcon(newArray: string[]) { this._icons = newArray; }
-
-    @action.bound
-    getIcons(): string[] { return this._icons; }
-
-    stopProp = (e: React.PointerEvent) => {
-        e.stopPropagation();
-        this._pointerTime = e.timeStamp;
-    }
-
-    @action.bound
-    public closeFilter() {
-        this._filterOpen = false;
-    }
-
-    @action.bound
-    updateAnyKeywordStatus(newStat: boolean) { this._anyKeywordStatus = newStat; }
-
-    @action.bound
-    updateAllKeywordStatus(newStat: boolean) { this._allKeywordStatus = newStat; }
-
-    @action.bound
-    updateTitleStatus(newStat: boolean) { this._titleFieldStatus = newStat; }
-
-    @action.bound
-    updateAuthorStatus(newStat: boolean) { this._authorFieldStatus = newStat; }
-
-    @action.bound
-    updateDataStatus(newStat: boolean) { this._deletedDocsStatus = newStat; }
-
-    @action.bound
-    updateCollectionStatus(newStat: boolean) { this._collectionStatus = newStat; }
-
-    @action.bound
-    updateSelfCollectionStatus(newStat: boolean) { this._collectionSelfStatus = newStat; }
-
-    @action.bound
-    updateParentCollectionStatus(newStat: boolean) { this._collectionParentStatus = newStat; }
-
-    getAnyKeywordStatus() { return this._anyKeywordStatus; }
-    getAllKeywordStatus() { return this._allKeywordStatus; }
-    getCollectionStatus() { return this._collectionStatus; }
-    getSelfCollectionStatus() { return this._collectionSelfStatus; }
-    getParentCollectionStatus() { return this._collectionParentStatus; }
-    getTitleStatus() { return this._titleFieldStatus; }
-    getAuthorStatus() { return this._authorFieldStatus; }
-    getDataStatus() { return this._deletedDocsStatus; }
-
-    getActiveFilters() {
-        return (
-            <div className="active-filters">
-                {!this._basicWordStatus ? <div className="active-icon container">
-                    <div className="active-icon icon">{this.getABCicon()}</div>
-                    <div className="active-icon description">Required Words Applied</div>
-                </div> : undefined}
-                {!(this._icons.length === 9) ? <div className="active-icon container">
-                    <div className="active-icon icon">{this.getTypeIcon()}</div>
-                    <div className="active-icon description">Type Filters Applied</div>
-                </div> : undefined}
-                {!(this._authorFieldStatus && this._dataFieldStatus && this._titleFieldStatus) ?
-                    <div className="active-icon container">
-                        <div className="active-icon icon">{this.getKeyIcon()}</div>
-                        <div className="active-icon description">Field Filters Applied</div>
-                    </div> : undefined}
-                {this._collectionStatus ? <div className="active-icon container">
-                    <div className="active-icon icon">{this.getColIcon()}</div>
-                    <div className="active-icon description">Collection Filters Active</div>
-                </div> : undefined}
-            </div>
-        );
-    }
-
-    // Useful queries:
-    // Delegates of a document: {!join from=id to=proto_i}id:{protoId}
-    // Documents in a collection: {!join from=data_l to=id}id:{collectionProtoId} //id of collections prototype
-    render() {
-        return (
-            <div>
-                <div style={{ display: "flex", flexDirection: "row-reverse" }}>
-                    <SearchBox />
-                    {/* {this.getActiveFilters()} */}
-                </div>
-                {this._filterOpen ? (
-                    <div className="filter-form" onPointerDown={this.stopProp} id="filter-form" style={this._filterOpen ? { display: "flex", background: "black" } : { 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" onClick={this.closeFilter}>
-                                <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" onClick={this.handleWordQueryChange}>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" onClick={this.resetFilters}>Reset Filters</button>
-                        </div>
-                    </div>
-                ) :
-                    undefined}
-            </div>
-        );
-    }
-}
\ No newline at end of file
diff --git a/src/server/websocket.ts b/src/server/websocket.ts
index cdce41a3a..2c8ec090a 100644
--- a/src/server/websocket.ts
+++ b/src/server/websocket.ts
@@ -286,16 +286,16 @@ export namespace WebSocket {
             dynfield = true;
             const val = docfield[key];
             key = key.substring(7);
-            if (key==="_height"){
-                Object.values(suffixMap).forEach(suf => {update[key] = { set: null };});
+            if (key === "_height") {
+                Object.values(suffixMap).forEach(suf => { update[key] = { set: null }; });
             }
             else {
-            Object.values(suffixMap).forEach(suf => {update[key + getSuffix(suf)] = { set: null };});
+                Object.values(suffixMap).forEach(suf => { update[key + getSuffix(suf)] = { set: null }; });
             }
             const term = ToSearchTerm(val);
             if (term !== undefined) {
                 const { suffix, value } = term;
-                if (key==="_height"){
+                if (key === "_height") {
                     update[key] = { set: value };
                 }
                 update[key + suffix] = { set: value };
-- 
cgit v1.2.3-70-g09d2


From 48932f578ac5926655c7d1f90fb659a0ead3b992 Mon Sep 17 00:00:00 2001
From: Andy Rickert <andrew_rickert@brown.edu>
Date: Wed, 5 Aug 2020 01:33:11 -0400
Subject: z

---
 src/client/views/nodes/formattedText/FormattedTextBox.tsx | 1 +
 1 file changed, 1 insertion(+)

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

diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index a1f576029..c06e59fe5 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -355,6 +355,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true });
             const end = this._editorView.state.doc.nodeSize - 2;
             this._editorView.dispatch(this._editorView.state.tr.removeMark(0, end, mark).removeMark(0, end, activeMark));
+
         }
         if (FormattedTextBox.PasteOnLoad) {
             const pdfDocId = FormattedTextBox.PasteOnLoad.clipboardData?.getData("dash/pdfOrigin");
-- 
cgit v1.2.3-70-g09d2


From 6612acac309767c6deafc45d931e42ff1ee4c86b Mon Sep 17 00:00:00 2001
From: Andy Rickert <andrew_rickert@brown.edu>
Date: Wed, 5 Aug 2020 15:09:49 -0400
Subject: fixes for bob

---
 .../views/collections/CollectionSchemaCells.tsx    |  4 +--
 .../views/collections/CollectionSchemaView.scss    | 10 ------
 src/client/views/collections/SchemaTable.tsx       |  6 ++--
 .../views/nodes/formattedText/FormattedTextBox.tsx | 36 +++++++++++++---------
 src/client/views/pdf/PDFViewer.tsx                 |  3 --
 src/server/websocket.ts                            | 10 +-----
 6 files changed, 27 insertions(+), 42 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index f627faa63..d11d6a5ba 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -902,8 +902,8 @@ export class CollectionSchemaButtons extends CollectionSchemaCell {
             </button>
             <button onClick={() => {
                 {
-                    doc.searchMatch2 = false;
-                    setTimeout(() => doc.searchMatch2 = true, 0);
+                    doc.searchMatchAlt = false;
+                    setTimeout(() => doc.searchMatchAlt = true, 0);
                     doc.searchIndex = NumCast(doc.searchIndex);
                 }
             }} style={{ padding: 2 }}>
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
index 897c11dc7..6bf24fe63 100644
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ b/src/client/views/collections/CollectionSchemaView.scss
@@ -161,16 +161,6 @@
 
 .collectionSchema-col {
     height: 100%;
-
-    .collectionSchema-apper {
-        &.col-before {
-            border-left: 2px solid red;
-    }
-
-        &.col-after {
-            border-right: 2px solid red;
-        }
-    }
 }
 
 
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index 8b7717ad1..83830e111 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -160,7 +160,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
         const focusedCol = this._focusedCell.col;
         const isEditable = !this.props.headerIsEditing;
 
-        if (this.childDocs.reduce((found, doc) => found || doc.type === "nnnnn", false)) {
+        if (this.childDocs.reduce((found, doc) => found || doc.type === "x", false)) {
             columns.push(
                 {
                     expander: true,
@@ -334,8 +334,8 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     @action
     nextHighlight2 = (doc: Doc) => {
 
-        doc.searchMatch2 = false;
-        setTimeout(() => doc.searchMatch2 = true, 0);
+        doc.searchMatchAlt = false;
+        setTimeout(() => doc.searchMatchAlt = true, 0);
         doc.searchIndex = NumCast(doc.searchIndex);
     }
 
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index c06e59fe5..c2f9f2030 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -293,7 +293,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             this._editorView.dispatch(tr.addMark(flattened[lastSel].from, flattened[lastSel].to, link));
         }
     }
-    public highlightSearchTerms = (terms: string[]) => {
+    public highlightSearchTerms = (terms: string[], alt: boolean) => {
         if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
 
             const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
@@ -309,24 +309,28 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark));
             this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
             this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
+            if (alt === true) {
+                if (this._searchIndex > 1) {
+                    this._searchIndex += -2;
+                }
+                else if (this._searchIndex === 1) {
+                    this._searchIndex = length - 1;
+                }
+                else if (this._searchIndex === 0 && length !== 1) {
+                    this._searchIndex = length - 2;
+                }
 
-            if (this._searchIndex > 1) {
-                this._searchIndex += -2;
-            }
-            else if (this._searchIndex === 1) {
-                this._searchIndex = length - 1;
             }
-            else if (this._searchIndex === 0 && length !== 1) {
-                this._searchIndex = length - 2;
+            else {
+
             }
             const index = this._searchIndex;
 
             Doc.GetProto(this.dataDoc).searchIndex = index;
-            Doc.GetProto(this.dataDoc).length = length;
         }
     }
 
-    public highlightSearchTerms2 = (terms: string[]) => {
+    public highlightSearchTermsAlt = (terms: string[]) => {
         if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
 
             const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
@@ -336,14 +340,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             let tr = this._editorView.state.tr;
             const flattened: TextSelection[] = [];
             res.map(r => r.map(h => flattened.push(h)));
+
             const lastSel = Math.min(flattened.length - 1, this._searchIndex);
             flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark));
             this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
             this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
+
+
             const index = this._searchIndex;
 
             Doc.GetProto(this.dataDoc).searchIndex = index;
-            Doc.GetProto(this.dataDoc).length = length;
         }
     }
 
@@ -780,11 +786,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
 
         this.setupEditor(this.config, this.props.fieldKey);
 
-        this._disposers.search = reaction(() => this.rootDoc.searchMatch2,
-            search => search ? this.highlightSearchTerms2([Doc.SearchQuery()]) : this.unhighlightSearchTerms(),
+        this._disposers.searchAlt = reaction(() => this.rootDoc.searchMatchAlt,
+            search => search ? this.highlightSearchTerms([Doc.SearchQuery()], false) : this.unhighlightSearchTerms(),
             { fireImmediately: true });
-        this._disposers.search2 = reaction(() => this.rootDoc.searchMatch,
-            search => search ? this.highlightSearchTerms([Doc.SearchQuery()]) : this.unhighlightSearchTerms(),
+        this._disposers.search = reaction(() => this.rootDoc.searchMatch,
+            search => search ? this.highlightSearchTerms([Doc.SearchQuery()], true) : this.unhighlightSearchTerms(),
             { fireImmediately: this.rootDoc.searchMatch ? true : false });
 
         this._disposers.record = reaction(() => this._recording,
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 7f31931a9..264d3e6c6 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -338,7 +338,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
         this.Index = Math.min(this.Index + 1, this.allAnnotations.length - 1);
         this.scrollToAnnotation(this.allAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y))[this.Index]);
         this.Document.searchIndex = this.Index;
-        this.Document.length = this.allAnnotations.length;
 
     }
 
@@ -408,7 +407,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
                 query: searchString
             });
             this.Document.searchIndex = this.Index;
-            this.Document.length = this.allAnnotations.length;
         }
         else if (this._mainCont.current) {
             const executeFind = () => {
@@ -423,7 +421,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
             this._mainCont.current.addEventListener("pagesloaded", executeFind);
             this._mainCont.current.addEventListener("pagerendered", executeFind);
             this.Document.searchIndex = this.Index;
-            this.Document.length = this.allAnnotations.length;
         }
 
     }
diff --git a/src/server/websocket.ts b/src/server/websocket.ts
index 24371a997..63cfa41f0 100644
--- a/src/server/websocket.ts
+++ b/src/server/websocket.ts
@@ -287,18 +287,10 @@ export namespace WebSocket {
             dynfield = true;
             const val = docfield[key];
             key = key.substring(7);
-            if (key === "_height") {
-                Object.values(suffixMap).forEach(suf => { update[key] = { set: null }; });
-            }
-            else {
-                Object.values(suffixMap).forEach(suf => { update[key + getSuffix(suf)] = { set: null }; });
-            }
+            Object.values(suffixMap).forEach(suf => { update[key + getSuffix(suf)] = { set: null }; });
             const term = ToSearchTerm(val);
             if (term !== undefined) {
                 const { suffix, value } = term;
-                if (key === "_height") {
-                    update[key] = { set: value };
-                }
                 update[key + suffix] = { set: value };
             }
         }
-- 
cgit v1.2.3-70-g09d2


From d5d0a46c0fdb6a1839c56927c66e332b14f5189f Mon Sep 17 00:00:00 2001
From: Andy Rickert <andrew_rickert@brown.edu>
Date: Wed, 5 Aug 2020 16:26:39 -0400
Subject: final changes for bob

---
 solr-8.3.1/bin/solr-8983.pid                       |  2 +-
 src/client/views/collections/SchemaTable.tsx       |  5 ++---
 .../views/nodes/formattedText/FormattedTextBox.tsx | 24 ----------------------
 3 files changed, 3 insertions(+), 28 deletions(-)

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

diff --git a/solr-8.3.1/bin/solr-8983.pid b/solr-8.3.1/bin/solr-8983.pid
index efc75f3cc..1f77d281d 100644
--- a/solr-8.3.1/bin/solr-8983.pid
+++ b/solr-8.3.1/bin/solr-8983.pid
@@ -1 +1 @@
-34698
+1731
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index 83830e111..0a5ef987a 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -177,6 +177,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                 }
             );
         }
+        console.log(columns);
 
         const cols = this.props.columns.map(col => {
 
@@ -314,6 +315,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
             width: 28,
             resizable: false
         });
+        console.log(columns);
         return columns;
     }
 
@@ -493,7 +495,6 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     @computed
     get reactTable() {
         const children = this.childDocs;
-        const hasCollectionChild = children.reduce((found, doc) => found || doc.type === "collection", false);
         const expandedRowsList = this._openCollections.map(col => children.findIndex(doc => doc[Id] === col).toString());
         const expanded = {};
         //@ts-ignore
@@ -515,8 +516,6 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
             resized={this.resized}
             NoDataComponent={() => null}
             onResizedChange={this.props.onResizedChange}
-            SubComponent={!hasCollectionChild ? undefined : row => (row.original.type !== "collection") ? (null) :
-                <div className="reactTable-sub"><SchemaTable {...this.props} Document={row.original} dataDoc={undefined} childDocs={undefined} /></div>}
 
         />;
     }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index c2f9f2030..5f0f33351 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -330,30 +330,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         }
     }
 
-    public highlightSearchTermsAlt = (terms: string[]) => {
-        if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
-
-            const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
-            const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true });
-            const res = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
-            const length = res[0].length;
-            let tr = this._editorView.state.tr;
-            const flattened: TextSelection[] = [];
-            res.map(r => r.map(h => flattened.push(h)));
-
-            const lastSel = Math.min(flattened.length - 1, this._searchIndex);
-            flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark));
-            this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
-            this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
-
-
-            const index = this._searchIndex;
-
-            Doc.GetProto(this.dataDoc).searchIndex = index;
-        }
-    }
-
-
     public unhighlightSearchTerms = () => {
         if (window.screen.width < 600) null;
         else if (this._editorView && (this._editorView as any).docView) {
-- 
cgit v1.2.3-70-g09d2


From fa0b28c300416621dec25407484fc2606a736e2a Mon Sep 17 00:00:00 2001
From: Geireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>
Date: Thu, 6 Aug 2020 05:11:18 +0800
Subject: automatic text progressivize, ui changes, bug fixes

---
 src/client/documents/Documents.ts                  |   2 +
 src/client/views/PropertiesButtons.tsx             |  37 ++-
 .../views/collections/CollectionDockingView.scss   |   8 +-
 .../views/collections/CollectionDockingView.tsx    |   2 +-
 .../views/collections/CollectionStackingView.tsx   |  12 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   4 +-
 .../collectionFreeForm/PropertiesView.tsx          |   4 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  20 +-
 src/client/views/nodes/PresBox.scss                |  56 +++-
 src/client/views/nodes/PresBox.tsx                 | 337 ++++++++-------------
 .../views/nodes/formattedText/FormattedTextBox.tsx |  65 ++++
 .../views/presentationview/PresElementBox.scss     |  35 ++-
 .../views/presentationview/PresElementBox.tsx      |  49 ++-
 13 files changed, 386 insertions(+), 245 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 539341b62..57fcf3a00 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -129,6 +129,7 @@ export interface DocumentOptions {
     isLinkButton?: boolean;
     _columnWidth?: number;
     _fontSize?: string;
+    _fontWeight?: number;
     _fontFamily?: string;
     curPage?: number;
     currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video)  value is in seconds
@@ -139,6 +140,7 @@ export interface DocumentOptions {
     appearFrame?: number; // the frame in which the document appears
     presTransition?: number; //the time taken for the transition TO a document
     presDuration?: number; //the duration of the slide in presentation view
+    presProgressivize?: boolean;
     // xArray?: number[];
     // yArray?: number[];
     borderRounding?: string;
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index d46c03470..7d8a75dda 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -30,6 +30,7 @@ import { undoBatch, UndoManager } from '../util/UndoManager';
 import { DocumentType } from '../documents/DocumentTypes';
 import { CollectionFreeFormView } from './collections/collectionFreeForm/CollectionFreeFormView';
 import { InkField } from '../../fields/InkField';
+import { PresBox } from './nodes/PresBox';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -209,13 +210,44 @@ export class PropertiesButtons extends React.Component<{}, {}> {
         const isPinned = targetDoc && Doc.isDocPinned(targetDoc);
         return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div></>}>
             <div className="propertiesButtons-linker"
-                style={{ backgroundColor: isPinned ? "white" : "", color: isPinned ? "black" : "white" }}
+                style={{ backgroundColor: isPinned ? "" : "white", color: isPinned ? "white" : "black" }}
                 onClick={e => DockedFrameRenderer.PinDoc(targetDoc, isPinned)}>
                 <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin"
                 />
             </div></Tooltip>;
     }
 
+    @computed
+    get pinWithViewButton() {
+        const targetDoc = this.selectedDoc;
+        const isPinned = targetDoc && Doc.isDocPinned(targetDoc);
+        if (targetDoc) {
+            const x = targetDoc._panX;
+            const y = targetDoc._panY;
+            const scale = targetDoc._viewScale;
+        }
+        return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Pin with this view"}</div></>}>
+            <div className="propertiesButtons-linker"
+                style={{ backgroundColor: "white", color: "black" }}
+                onClick={e => {
+                    if (targetDoc) {
+                        DockedFrameRenderer.PinDoc(targetDoc, false);
+                        const activeDoc = PresBox.Instance.childDocs[PresBox.Instance.childDocs.length - 1];
+                        const x = targetDoc._panX;
+                        const y = targetDoc._panY;
+                        const scale = targetDoc._viewScale;
+                        activeDoc.presPinView = true;
+                        activeDoc.presPinViewX = x;
+                        activeDoc.presPinViewY = y;
+                        activeDoc.presPinViewScale = scale;
+                    }
+                }}>
+                <div style={{ position: 'absolute', fontSize: 25, fontWeight: 700, transform: 'translate(42%, -7px)', color: 'rgba(0,0,0,0.2)' }}>V</div>
+                <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin" />
+            </div></Tooltip>;
+    }
+
+
     @computed
     get metadataButton() {
         //const view0 = this.view0;
@@ -607,6 +639,9 @@ export class PropertiesButtons extends React.Component<{}, {}> {
             <div className="propertiesButtons-button">
                 {this.pinButton}
             </div>
+            <div className="propertiesButtons-button">
+                {this.pinWithViewButton}
+            </div>
             <div className="propertiesButtons-button">
                 {this.copyButton}
             </div>
diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss
index 857f751d3..98babc3d2 100644
--- a/src/client/views/collections/CollectionDockingView.scss
+++ b/src/client/views/collections/CollectionDockingView.scss
@@ -45,7 +45,7 @@
 
         .miniPres-button-text {
             display: flex;
-            height: 30;
+            height: 20;
             font-weight: 400;
             min-width: 100%;
             border-radius: 5px;
@@ -55,15 +55,15 @@
         }
 
         .miniPres-divider {
-            width: 1px;
+            width: 0.5px;
             height: 80%;
             border-right: solid 2px #5a5a5a;
         }
 
         .miniPres-button {
             display: flex;
-            height: 30;
-            min-width: 30;
+            height: 20;
+            min-width: 20;
             border-radius: 100%;
             align-items: center;
             justify-content: center;
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 9c85bd0a2..bc88236dd 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -871,7 +871,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     }
     renderMiniPres() {
         return <div className="miniPres" style={{
-            width: 400, height: 50, background: '#323232'
+            width: 250, height: 30, background: '#323232'
         }}>
             <div className="miniPresOverlay" >
                 <div className="miniPres-button" onClick={PresBox.Instance.back}><FontAwesomeIcon icon={"arrow-left"} /></div>
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index e00bdb065..fe3d57bdb 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -184,7 +184,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
         if (found) {
             const top = found.getBoundingClientRect().top;
             const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
-            smoothScroll(doc.presTransition ? Number(doc.presTransition) : 500, this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
+            smoothScroll(doc.presTransition || doc.presTransition === 0 ? NumCast(doc.presTransition) : 500, this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
         }
         afterFocus && setTimeout(() => {
             if (afterFocus?.()) { }
@@ -291,20 +291,19 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
                 const docs = this.childDocList;
                 if (docs) {
                     newDocs.map((doc, i) => {
+                        console.log(doc.title);
                         if (i === 0) {
                             if (targInd === -1) targInd = docs.length;
                             else targInd = docs.indexOf(this.filteredChildren[targInd]);
                             const srcInd = docs.indexOf(doc);
                             docs.splice(srcInd, 1);
                             docs.splice((targInd > srcInd ? targInd - 1 : targInd) + plusOne, 0, doc);
-                        } else {
+                        } else if (i < (newDocs.length / 2)) { //glr: for some reason dragged documents are duplicated
                             if (targInd === -1) targInd = docs.length;
-                            else targInd = docs.indexOf(this.filteredChildren[targInd]);
+                            else targInd = docs.indexOf(newDocs[0]) + 1;
                             const srcInd = docs.indexOf(doc);
-                            const firstInd = docs.indexOf(newDocs[0]);
                             docs.splice(srcInd, 1);
-                            // docs.splice((targInd > srcInd ? targInd - 1 : targInd) + plusOne, 0, doc);
-                            docs.splice(firstInd + 1, 0, doc);
+                            docs.splice((targInd > srcInd ? targInd - 1 : targInd) + plusOne, 0, doc);
                         }
                     });
                 }
@@ -312,6 +311,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
         }
         return false;
     }
+
     @undoBatch
     @action
     onExternalDrop = async (e: React.DragEvent): Promise<void> => {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 109808956..65cd28742 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -911,8 +911,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             //     !doc.z && NumCast(this.layoutDoc.scale) < 1 && this.scaleAtPt(DocumentView._focusHack, 1); // [NumCast(doc.x), NumCast(doc.y)], 1);
             // } else {
             if (DocListCast(this.dataDoc[this.props.fieldKey]).includes(doc)) {
-                // glr: freeform transform speed can be set through user by adjusting for presentation transform
-                if (!doc.z) this.setPan(newPanX, newPanY, doc.presTransition ? `transform ${doc.presTransition}ms` : "transform 500ms", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
+                // glr: freeform transform speed can be set by adjusting presTransition field - needs a way of knowing when presentation is not active...
+                if (!doc.z) this.setPan(newPanX, newPanY, doc.presTransition || doc.presTransition === 0 ? `transform ${doc.presTransition}ms` : "transform 500ms", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
             }
             Doc.BrushDoc(this.props.Document);
             this.props.focus(this.props.Document);
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index 1f66d4144..035cd938e 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -865,7 +865,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         if (this.isPres) {
             return <div className="propertiesView" style={{ width: this.props.width }} >
                 <div className="propertiesView-title" style={{ width: this.props.width }}>
-                    Presentation Toolbar
+                    Presentation
                 <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}>
                         <FontAwesomeIcon icon="times" color="black" size="sm" />
                     </div>
@@ -922,7 +922,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     <div className="propertiesView-sharing-title"
                         onPointerDown={() => runInAction(() => { this.openSlideOptions = !this.openSlideOptions; })}
                         style={{ backgroundColor: this.openSlideOptions ? "black" : "" }}>
-                        <FontAwesomeIcon icon={"cog"} /> &nbsp; {PresBox.Instance.stringType} options
+                        &nbsp; <FontAwesomeIcon icon={"cog"} /> &nbsp; {PresBox.Instance.stringType} options
                     <div className="propertiesView-sharing-title-icon">
                             <FontAwesomeIcon icon={this.openSlideOptions ? "caret-down" : "caret-right"} size="lg" color="white" />
                         </div>
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index c29547eac..35ed6c5a5 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -107,6 +107,15 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
         d["w-indexed"] = new List<number>(windexed);
         d["opacity-indexed"] = new List<number>(oindexed);
         d["scroll-indexed"] = new List<number>(scrollIndexed);
+        if (d.appearFrame) {
+            if (d.appearFrame === timecode + 1) {
+                d["text-color"] = "red";
+            } else if (d.appearFrame < timecode + 1) {
+                d["text-color"] = "grey";
+            } else { d["text-color"] = "black"; }
+        } else if (d.appearFrame === 0) {
+            d["text-color"] = "black";
+        }
     }
 
     public static updateScrollframe(doc: Doc, time: number) {
@@ -139,6 +148,15 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
             xindexed?.length <= timecode + 1 && xindexed.push(undefined as any as number);
             yindexed?.length <= timecode + 1 && yindexed.push(undefined as any as number);
             opacityindexed?.length <= timecode + 1 && opacityindexed.push(undefined as any as number);
+            if (doc.appearFrame) {
+                if (doc.appearFrame === timecode + 1) {
+                    doc["text-color"] = "red";
+                } else if (doc.appearFrame < timecode + 1) {
+                    doc["text-color"] = "grey";
+                } else { doc["text-color"] = "black"; }
+            } else if (doc.appearFrame === 0) {
+                doc["text-color"] = "black";
+            }
             doc.dataTransition = "all 1s";
         });
         setTimeout(() => docs.forEach(doc => doc.dataTransition = "inherit"), 1010);
@@ -166,7 +184,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
 
     public static setupKeyframes(docs: Doc[], timecode: number, progressivize: boolean = false) {
         docs.forEach((doc, i) => {
-            if (!doc.appearFrame) doc.appearFrame = i;
+            if (doc.appearFrame === undefined) doc.appearFrame = i;
             const curTimecode = progressivize ? i : timecode;
             const xlist = new List<number>(numberRange(timecode + 1).map(i => undefined) as any as number[]);
             const ylist = new List<number>(numberRange(timecode + 1).map(i => undefined) as any as number[]);
diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss
index 089f69873..16821f5bc 100644
--- a/src/client/views/nodes/PresBox.scss
+++ b/src/client/views/nodes/PresBox.scss
@@ -754,8 +754,6 @@
     }
 
     .presBox-button {
-        margin-right: 2.5px;
-        margin-left: 2.5px;
         height: 25px;
         border-radius: 5px;
         display: none;
@@ -787,13 +785,65 @@
         min-width: 100px;
         width: 100px;
         position: absolute;
-        right: 8px;
+        right: 10px;
 
         .present-icon {
             margin-right: 7px;
         }
     }
 
+        
+    .miniPresOverlay {
+        background-color: #323232;
+        color: white;
+        border-radius: 5px;
+        grid-template-rows: 100%;
+        height: 25;
+        width: 200;
+        justify-content: space-evenly;
+        align-items: center;
+        display: flex;
+        position: absolute;
+        right: 10px;
+
+        .miniPres-button-text {
+            display: flex;
+            height: 20;
+            width: max-content;
+            font-family: Roboto;
+            font-weight: 400;
+            letter-spacing: normal;
+            border-radius: 5px;
+            align-items: center;
+            justify-content: center;
+            transition: all 0.3s;
+        }
+
+        .miniPres-divider {
+            width: 0.5px;
+            height: 80%;
+            border-right: solid 1px #5a5a5a;
+        }
+
+        .miniPres-button {
+            display: flex;
+            height: 20;
+            min-width: 20;
+            border-radius: 100%;
+            align-items: center;
+            justify-content: center;
+            transition: all 0.3s;
+        }
+
+        .miniPres-button:hover {
+            background-color: #5a5a5a;
+        }
+
+        .miniPres-button-text:hover {
+            background-color: #5a5a5a;
+        }
+    }
+
 
 
     .collectionViewBaseChrome-viewPicker {
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 2389d3875..1caefdc57 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -97,7 +97,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     @action
     next = () => {
         this.updateCurrentPresentation();
+        const activeNext = Cast(this.childDocs[this.itemIndex + 1], Doc, null);
         const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null);
+        const childDocs = DocListCast(presTargetDoc[Doc.LayoutFieldKey(presTargetDoc)]);
+        const currentFrame = Cast(presTargetDoc.currentFrame, "number", null);
         const lastFrame = Cast(presTargetDoc.lastFrame, "number", null);
         const curFrame = NumCast(presTargetDoc.currentFrame);
         let internalFrames: boolean = false;
@@ -107,8 +110,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             presTargetDoc._viewTransition = "all 1s";
             setTimeout(() => presTargetDoc._viewTransition = undefined, 1010);
             presTargetDoc.currentFrame = curFrame + 1;
+            if (presTargetDoc.scrollProgressivize) CollectionFreeFormDocumentView.updateScrollframe(presTargetDoc, currentFrame);
+            if (presTargetDoc.presProgressivize) CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0);
             if (presTargetDoc.zoomProgressivize) this.zoomProgressivizeNext(presTargetDoc);
-            // Case 2: No more frames in current doc and next slide is defined, therefore move to next slide
+            // Case 2: Audio or video therefore wait to play the audio or video before moving on
         } else if ((presTargetDoc.type === DocumentType.VID || presTargetDoc.type === DocumentType.AUDIO) && !this._moveOnFromAudio) {
             if (presTargetDoc.type === DocumentType.AUDIO) {
                 AudioBox.Instance.playFrom(0);
@@ -117,7 +122,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             if (presTargetDoc.type === DocumentType.VID) {
                 this._moveOnFromAudio = true;
             }
-        } else if (this.childDocs[this.itemIndex + 1] !== undefined) {
+            // Case 3: No more frames in current doc and next slide is defined, therefore move to next slide
+        } else if (activeNext !== undefined) {
+            if (!presTargetDoc.presProgressivize) {
+                const nextTagDoc = Cast(this.childDocs[this.itemIndex + 1].presentationTargetDoc, Doc, null);
+                const nextChildDocs = DocListCast(nextTagDoc[Doc.LayoutFieldKey(presTargetDoc)]);
+                nextChildDocs.forEach((doc, i) => {
+                    doc.opacity = 1;
+                })
+            }
             const nextSelected = this.itemIndex + 1;
             this.gotoDocument(nextSelected, this.itemIndex);
             this._moveOnFromAudio = false;
@@ -130,15 +143,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         this.updateCurrentPresentation();
         const docAtCurrent = this.childDocs[this.itemIndex];
         if (docAtCurrent) {
-            //check if any of the group members had used zooming in including the current document
-            //If so making sure to zoom out, which goes back to state before zooming action
             let prevSelected = this.itemIndex;
-            let didZoom = docAtCurrent.zoomButton;
-            // for (; !didZoom && prevSelected > 0 && this.childDocs[prevSelected].groupButton; prevSelected--) {
-            //     didZoom = this.childDocs[prevSelected].zoomButton;
-            // }
             prevSelected = Math.max(0, prevSelected - 1);
-
             this.gotoDocument(prevSelected, this.itemIndex);
         }
     }
@@ -159,19 +165,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 const panelWidth: number = srcDocView.props.PanelWidth();
                 const panelHeight: number = srcDocView.props.PanelHeight();
                 console.log("srcDocView: " + srcDocView.props.PanelWidth());
-                // console.log("layoutdoc._width: " + layoutdoc._width);
-                // console.log("srcContext._width: " + srcContext._width);
                 const newPanX = NumCast(presTargetDoc.x) + NumCast(layoutdoc._width) / 2;
                 const newPanY = NumCast(presTargetDoc.y) + NumCast(layoutdoc._height) / 2;
-                // const newPanX = NumCast(presTargetDoc.x) + panelWidth / 2;
-                // const newPanY = NumCast(presTargetDoc.y) + panelHeight / 2;
                 let newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight);
-                // srcContext._panX = newPanX + (NumCast(presTargetDoc._viewScale) * this.checkList(presTargetDoc, presTargetDoc["viewfinder-left-indexed"]) + NumCast(presTargetDoc._panX) + (this.checkList(presTargetDoc, presTargetDoc["viewfinder-width-indexed"]) / 2));
-                // srcContext._panY = newPanY + (NumCast(presTargetDoc._viewScale) * this.checkList(presTargetDoc, presTargetDoc["viewfinder-top-indexed"]) + NumCast(presTargetDoc._panY) + (this.checkList(presTargetDoc, presTargetDoc["viewfinder-height-indexed"]) / 2));
                 srcContext._panX = newPanX + (vfLeft + (vfWidth / 2));
                 srcContext._panY = newPanY + (vfTop + (vfHeight / 2));
-                // srcContext._panX = newPanX
-                // srcContext._panY = newPanY
                 srcContext._viewScale = newScale;
                 console.log("X: " + srcContext._panX + ", Y: " + srcContext._panY + ", Scale: " + srcContext._viewScale);
             }
@@ -203,9 +201,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
             if (tagDoc) tagDoc.opacity = 1;
             if (curDoc.presHideTillShownButton) {
-                console.log("-------------hide before---------------");
-                console.log("this.itemIndex: " + this.itemIndex);
-                console.log("index: " + index)
                 if (index > this.itemIndex) {
                     tagDoc.opacity = 0;
                 } else if (!curDoc.presHideAfterButton) {
@@ -213,9 +208,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 }
             }
             if (curDoc.presHideAfterButton) {
-                console.log("-------------hide after---------------");
-                console.log("this.itemIndex: " + (this.itemIndex + 1));
-                console.log("index: " + (index + 1))
                 if (index < this.itemIndex) {
                     tagDoc.opacity = 0;
                 } else if (!curDoc.presHideTillShownButton) {
@@ -225,73 +217,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         });
     }
 
-    @action
-    onHideAfterPresClick = () => {
-        this.childDocs.forEach((doc, index) => {
-            const curDoc = Cast(doc, Doc, null);
-            const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
-            if (curDoc.presHideAfterButton) {
-                if (index < this.itemIndex) {
-                    tagDoc.opacity = 0;
-                } else if (index = this.itemIndex) {
-                    tagDoc.opacity = 1;
-                }
-            }
-        });
-    }
-
-    /**
-     * This is the method that checks for the actions that need to be performed
-     * before the document has been presented, which involves 3 button options:
-     * Hide Until Presented, Hide After Presented, Fade After Presented
-     */
-    // @action
-    // hideDocumentInPres = () => {
-    //     this.updateCurrentPresentation();
-    //     this.childDocs.forEach((doc, i) => {
-    //         const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
-    //         console.log("HB: " + doc.presHideTillShownButton);
-    //         console.log("HA: " + doc.presHideAfterButton);
-    //         if (doc.presHideTillShownButton) {
-    //             if (i < this.itemIndex) {
-    //                 console.log(i + 1 + "hide before");
-    //                 tagDoc.opacity = 0;
-    //                 console.log(tagDoc.opacity);
-    //             } else {
-    //                 tagDoc.opacity = 1;
-    //             }
-    //         }
-    //         if (doc.presHideAfterButton) {
-    //             if (i > this.itemIndex) {
-    //                 console.log(i + 1 + "hide after");
-    //                 tagDoc.opacity = 0;
-    //                 console.log(tagDoc.opacity);
-    //             } else {
-    //                 tagDoc.opacity = 1;
-    //             }
-    //         }
-    //     });
-    // }
-
-    /**
-     * This is the method that checks for the actions that need to be performed
-     * after the document has been presented, which involves 3 button options:
-     * Hide Until Presented, Hide After Presented, Fade After Presented
-     */
-    // showAfterPresented = (index: number) => {
-    //     this.updateCurrentPresentation();
-    //     this.childDocs.forEach((doc, ind) => {
-    //         const presTargetDoc = doc.presentationTargetDoc as Doc;
-    //         //the order of cases is aligned based on priority
-    //         if (doc.presHideTillShownButton && ind <= index) {
-    //             presTargetDoc.opacity = 1;
-    //         }
-    //         if (doc.presHideAfterButton && ind < index) {
-    //             presTargetDoc.opacity = 0;
-    //         }
-    //     });
-    // }
-
     /**
      * This method makes sure that cursor navigates to the element that
      * has the option open and last in the group. If not in the group, and it has
@@ -310,24 +235,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 if (srcContext) this.layoutDoc.presCollection = srcContext;
             } else if (targetDoc) this.layoutDoc.presCollection = targetDoc;
         }
-        if (srcContext) console.log("NC: " + srcContext.title);
-        if (presCollection) console.log("PC: " + presCollection.title);
         if (collectionDocView) {
-            if (activeItem.openDocument) {
-                collectionDocView.props.addDocTab(activeItem, "inPlace");
-            } else if (srcContext && srcContext !== presCollection) {
-                if (activeItem.openDocument) {
-                    collectionDocView.props.addDocTab(activeItem, "inPlace");
-                } else {
-                    console.log("Case 1: new srcContext inside of current collection so add a new tab to the current pres collection");
-                    console.log(collectionDocView);
-                    collectionDocView.props.addDocTab(srcContext, "inPlace");
-                }
+            if (srcContext && srcContext !== presCollection) {
+                // Case 1: new srcContext inside of current collection so add a new tab to the current pres collection
+                collectionDocView.props.addDocTab(srcContext, "inPlace");
             }
         }
-        if (targetDoc.presWebsiteData) {
-            targetDoc.data = targetDoc.presWebsiteData;
-        }
         // else if (srcContext) {
         //     console.log("Case 2: srcContext - not open and collection containing this document exists, so open collection that contains it and then await zooming in on document");
         //     this.props.addDocTab(srcContext, "onRight");
@@ -354,6 +267,17 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             //awaiting jump so that new scale can be found, since jumping is async
             targetDoc && await DocumentManager.Instance.jumpToDocument(targetDoc, willZoom, undefined, srcContext);
         }
+        if (activeItem.presPinView) {
+            targetDoc._panX = activeItem.presPinViewX;
+            targetDoc._panY = activeItem.presPinViewY;
+            targetDoc._viewScale = activeItem.presPinViewScale;
+        }
+        if (collectionDocView && activeItem.openDocument) {
+            collectionDocView.props.addDocTab(activeItem, "inPlace");
+        }
+        if (targetDoc.presWebsiteData) {
+            targetDoc.data = targetDoc.presWebsiteData;
+        }
     }
 
     //The function that is called when a document is clicked or reached through next or back.
@@ -381,6 +305,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     @observable _presTimer!: NodeJS.Timeout;
 
     //The function that starts or resets presentaton functionally, depending on status flag.
+    @undoBatch
     @action
     startOrResetPres = (startSlide: number) => {
         this.updateCurrentPresentation();
@@ -432,31 +357,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         this.turnOffEdit();
         if (srcContext) {
             if (srcContext.miniPres) {
-                document.removeEventListener("keydown", this.keyEvents, false);
+                document.removeEventListener("keydown", this.minimizeEvents, false);
                 srcContext.miniPres = false;
-                // Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocuments as Doc), undefined, this.rootDoc);
                 CollectionDockingView.AddRightSplit(this.rootDoc);
-                // this.layoutDoc.inOverlay = false;
             } else {
-                document.addEventListener("keydown", this.keyEvents, false);
+                document.addEventListener("keydown", this.minimizeEvents, false);
                 srcContext.miniPres = true;
                 this.props.addDocTab?.(this.rootDoc, "close");
-                // Doc.AddDocToList((Doc.UserDoc().myOverlayDocuments as Doc), undefined, this.rootDoc);
             }
         }
-        // if (srcContext) {
-        //     Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocuments as Doc), undefined, this.rootDoc);
-        //     CollectionDockingView.AddRightSplit(this.rootDoc);
-        //     this.layoutDoc.inOverlay = false;
-        // }
-        // else {
-        //         const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
-        //         this.rootDoc.x = pt[0];// 500;//e.clientX + 25;
-        //         this.rootDoc.y = pt[1];////e.clientY - 25;
-        //         this.props.addDocTab?.(this.rootDoc, "close");
-        //         Doc.AddDocToList((Doc.UserDoc().myOverlayDocuments as Doc), undefined, this.rootDoc);
-        //     }
-        // }
     }
 
     @undoBatch
@@ -464,7 +373,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         //@ts-ignore
         const viewType = e.target.selectedOptions[0].value as CollectionViewType;
         viewType === CollectionViewType.Stacking && (this.rootDoc._pivotField = undefined); // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here
-        // this.updateMinimize(this.rootDoc._viewType = viewType);
+        this.rootDoc._viewType = viewType;
         if (viewType === CollectionViewType.Stacking) this.layoutDoc._gridGap = 5;
     });
 
@@ -485,7 +394,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         } else if (movement === 'switch') {
             targetDoc.presTransition = 0;
             activeItem.presSwitchButton = !activeItem.presSwitchButton;
-            if (activeItem.presSwitchButton) activeItem.presMovement = 'Switch';
+            if (activeItem.presSwitchButton) activeItem.presMovement = 'Jump cut';
             else activeItem.presMovement = 'None';
         } else {
             activeItem.presMovement = 'None';
@@ -496,12 +405,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     });
 
     whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive));
+    // For dragging documents into the presentation trail
     addDocumentFilter = (doc: Doc | Doc[]) => {
         const docs = doc instanceof Doc ? [doc] : doc;
         docs.forEach((doc, i) => {
             if (this.childDocs.includes(doc)) {
-                console.log(docs.length);
-                console.log(i + 1);
                 if (docs.length === i + 1) return false;
             } else {
                 doc.aliasOf instanceof Doc && (doc.presentationTargetDoc = doc.aliasOf);
@@ -574,33 +482,45 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         }
     }
 
+    @action
+    minimizeEvents = (e: KeyboardEvent) => {
+        e.stopPropagation();
+        e.preventDefault();
+        if (e.keyCode === 27) { // Escape key
+            this.layoutDoc.presStatus = "edit";
+        } if (e.keyCode === 37) { // left(37) / a(65) / up(38) to go back
+            this.back();
+        } if (e.keyCode === 39) { // right (39) / d(68) / down(40) to go to next
+            this.next();
+        }
+    }
+
     //Esc click
     @action
     keyEvents = (e: KeyboardEvent) => {
         e.stopPropagation();
         e.preventDefault();
-        // switch(e.keyCode) {
-        //     case 27: console.log("escape");
-        //     case 65 && (e.metaKey || e.altKey):
-        // }
-        // Escape key
-        if (e.keyCode === 27) {
+
+        if (e.keyCode === 27) { // Escape key
             if (this.layoutDoc.presStatus === "edit") this._selectedArray = [];
             else this.layoutDoc.presStatus = "edit";
-            // Ctrl-A to select all
-        } if ((e.metaKey || e.altKey) && e.keyCode === 65) {
+        } if ((e.metaKey || e.altKey) && e.keyCode === 65) { // Ctrl-A to select all
             if (this.layoutDoc.presStatus === "edit") this._selectedArray = this.childDocs;
-            // left(37) / a(65) / up(38) to go back
-        } if (e.keyCode === 37) {
+        } if (e.keyCode === 37) { // left(37) / a(65) / up(38) to go back
             if (this.layoutDoc.presStatus !== "edit") this.back();
-            // right (39) / d(68) / down(40) to go to next
-        } if (e.keyCode === 39) {
-            if (this.layoutDoc.presStatus !== "edit") this.next();
-            // spacebar to 'present' or go to next slide
-        } if (e.keyCode === 32) {
+        } if (e.keyCode === 39) { // right (39) / d(68) / down(40) to go to next
             if (this.layoutDoc.presStatus !== "edit") this.next();
+        } if (e.keyCode === 32) { // spacebar to 'present' or autoplay
+            if (this.layoutDoc.presStatus !== "edit") this.startOrResetPres(0);
             else this.layoutDoc.presStatus = "manual";
         }
+        if (e.keyCode === 8) { // delete selected items
+            if (this.layoutDoc.presStatus === "edit") {
+                this._selectedArray.forEach((doc, i) => {
+                    this.removeDocument(doc);
+                });
+            }
+        }
     }
 
     @observable private transitionTools: boolean = false;
@@ -617,7 +537,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     viewPaths = async () => {
         const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
         if (this.pathBoolean) {
-            console.log("true");
             if (srcContext) {
                 this.togglePath();
                 srcContext._fitToBox = false;
@@ -625,7 +544,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 srcContext.presPathView = false;
             }
         } else {
-            console.log("false");
             if (srcContext) {
                 this.togglePath();
                 srcContext._fitToBox = true;
@@ -633,13 +551,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 srcContext.presPathView = true;
             }
         }
-        console.log("view paths");
         const viewType = srcContext?._viewType;
         const fit = srcContext?._fitToBox;
-
-        // if (!DocumentManager.Instance.getDocumentView(curPres)) {
-        //     CollectionDockingView.AddRightSplit(curPres);
-        // }
     }
 
     @computed get order() {
@@ -664,7 +577,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
 
     @computed get paths() {
         let pathPoints = "";
-        console.log(this.childDocs.length - 1);
         this.childDocs.forEach((doc, index) => {
             const targetDoc = Cast(doc.presentationTargetDoc, Doc, null);
             const srcContext = Cast(targetDoc.context, Doc, null);
@@ -678,7 +590,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 else pathPoints = pathPoints + " " + 0 + "," + 0;
             }
         });
-        console.log(pathPoints);
         return (<polyline
             points={pathPoints}
             style={{
@@ -720,12 +631,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         }
     }
 
+    // WHAT IS THIS?
     @action
     dropdownToggle = (menu: string) => {
-        console.log('presBox' + menu + 'Dropdown');
         const dropMenu = document.getElementById('presBox' + menu + 'Dropdown');
-        console.log(dropMenu);
-        console.log(dropMenu?.style.display);
         if (dropMenu) dropMenu.style.display === 'none' ? dropMenu.style.display = 'block' : dropMenu.style.display = 'none';
     }
 
@@ -749,8 +658,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         if (activeItem && targetDoc) {
             const transitionSpeed = targetDoc.presTransition ? String(Number(targetDoc.presTransition) / 1000) : 0.5;
             const duration = targetDoc.presDuration ? String(Number(targetDoc.presDuration) / 1000) : 2;
-            const transitionThumbLocation = String(-9.48 * Number(transitionSpeed) + 93);
-            const durationThumbLocation = String(9.48 * Number(duration));
             const effect = targetDoc.presEffect ? targetDoc.presEffect : 'None';
             activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom';
             return (
@@ -767,7 +674,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                 <div className={`presBox-dropdownOption ${activeItem.presMovement === 'None' ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.movementChanged('none')}>None</div>
                                 <div className={`presBox-dropdownOption ${activeItem.presMovement === 'Zoom' ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.movementChanged('zoom')}>Pan and Zoom</div>
                                 <div className={`presBox-dropdownOption ${activeItem.presMovement === 'Pan' ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.movementChanged('nav')}>Pan</div>
-                                <div className={`presBox-dropdownOption ${activeItem.presMovement === 'Switch' ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.movementChanged('switch')}>Switch</div>
+                                <div className={`presBox-dropdownOption ${activeItem.presMovement === 'Jump cut' ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.movementChanged('switch')}>Jump cut</div>
                             </div>
                         </div>
                         <div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === 'Pan' || activeItem.presMovement === 'Zoom' ? "inline-flex" : "none" }}>
@@ -985,7 +892,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     }
 
     createNewSlide = (layout?: string, title?: string, freeform?: boolean) => {
-        console.log("whats going on?");
         let doc = undefined;
         if (layout) doc = this.createTemplate(layout);
         if (freeform && layout) doc = this.createTemplate(layout, title);
@@ -1019,7 +925,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const content2 = Docs.Create.TextDocument("Click to change text", { title: "Column 2", _width: 185, _height: 140, x: 205, y: 80, _fontSize: "14pt" });
         switch (layout) {
             case 'blank':
-                doc = Docs.Create.FreeformDocument([], { title: input ? input : "Blank slide", _width: 400, _height: 225, _fitToBox: true, x: x, y: y });
+                doc = Docs.Create.FreeformDocument([], { title: input ? input : "Blank slide", _width: 400, _height: 225, x: x, y: y });
                 break;
             case 'title':
                 doc = Docs.Create.FreeformDocument([title, subtitle], { title: input ? input : "Title slide", _width: 400, _height: 225, _fitToBox: true, x: x, y: y });
@@ -1084,14 +990,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             CollectionFreeFormDocumentView.setupScroll(tagDoc, 0);
             CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
         }
-        let lastFrame: number = 0;
-        childDocs.forEach((doc) => {
-            if (NumCast(doc.appearFrame) > lastFrame) lastFrame = NumCast(doc.appearFrame);
-        });
+        // let lastFrame: number = 0;
+        // childDocs.forEach((doc) => {
+        //     if (NumCast(doc.appearFrame) > lastFrame) lastFrame = NumCast(doc.appearFrame);
+        // });
         CollectionFreeFormDocumentView.updateScrollframe(tagDoc, currentFrame);
         CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0);
         tagDoc.currentFrame = Math.max(0, (currentFrame || 0) + 1);
-        tagDoc.lastFrame = Math.max(NumCast(tagDoc.currentFrame), lastFrame);
+        tagDoc.lastFrame = Math.max(NumCast(tagDoc.currentFrame), NumCast(tagDoc.lastFrame));
         if (tagDoc.zoomProgressivize) {
             const resize = document.getElementById('resizable');
             if (resize) {
@@ -1153,20 +1059,20 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                     <div className={`presBox-ribbon ${this.progressivizeTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
                         <div className="ribbon-box">
                             {this.stringType} selected
-                            <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.COL ? "inline-flex" : "none" }}>
+                            <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform' ? "inline-flex" : "none" }}>
                                 <div className="ribbon-button" style={{ backgroundColor: activeItem.presProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeChild}>Child documents</div>
                                 <div className="ribbon-button" style={{ display: activeItem.presProgressivize ? "flex" : "none", backgroundColor: targetDoc.editProgressivize ? "#aedef8" : "" }} onClick={this.editProgressivize}>Edit</div>
                             </div>
-                            <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.COL || targetDoc.type === DocumentType.IMG ? "inline-flex" : "none" }}>
+                            <div className="ribbon-doubleButton" style={{ display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG ? "inline-flex" : "none" }}>
                                 <div className="ribbon-button" style={{ backgroundColor: activeItem.zoomProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeZoom}>Internal zoom</div>
                                 <div className="ribbon-button" style={{ display: activeItem.zoomProgressivize ? "flex" : "none", backgroundColor: targetDoc.editZoomProgressivize ? "#aedef8" : "" }} onClick={this.editZoomProgressivize}>Viewfinder</div>
                                 {/* <div className="ribbon-button" style={{ display: activeItem.zoomProgressivize ? "flex" : "none", backgroundColor: targetDoc.editSnapZoomProgressivize ? "#aedef8" : "" }} onClick={this.editSnapZoomProgressivize}>Snapshot</div> */}
                             </div>
-                            <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.RTF ? "inline-flex" : "none" }}>
+                            <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform' ? "inline-flex" : "none" }}>
                                 <div className="ribbon-button" onClick={this.progressivizeText}>Text progressivize</div>
                                 <div className="ribbon-button" style={{ display: activeItem.textProgressivize ? "flex" : "none", backgroundColor: targetDoc.editTextProgressivize ? "#aedef8" : "" }} onClick={this.editTextProgressivize}>Edit</div>
                             </div>
-                            <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.PDF ? "inline-flex" : "none" }}>
+                            <div className="ribbon-doubleButton" style={{ display: targetDoc._viewType === "stacking" || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF ? "inline-flex" : "none" }}>
                                 <div className="ribbon-button" style={{ backgroundColor: activeItem.scrollProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeScroll}>Scroll progressivize</div>
                                 <div className="ribbon-button" style={{ display: activeItem.scrollProgressivize ? "flex" : "none", backgroundColor: targetDoc.editScrollProgressivize ? "#aedef8" : "" }} onClick={this.editScrollProgressivize}>Edit</div>
                             </div>
@@ -1188,7 +1094,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                 </div>
                                 <Tooltip title={<><div className="dash-tooltip">{"Last frame"}</div></>}><div className="ribbon-property">{NumCast(targetDoc.lastFrame)}</div></Tooltip>
                             </div>
-                            <div className="ribbon-button" style={{ height: 20, backgroundColor: "#5a9edd" }} onClick={() => console.log("play frames")}>Play</div>
+                            <div className="ribbon-button" style={{ height: 20, backgroundColor: "#5a9edd" }} onClick={() => console.log(" TODO: play frames")}>Play</div>
                         </div>
                     </div>
                 </div>
@@ -1298,9 +1204,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
         const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
         targetDoc.presProgressivize = !targetDoc.presProgressivize;
-        console.log(targetDoc.presProgressivize);
         if (activeItem.presProgressivize) {
-            console.log("progressivize");
             targetDoc.currentFrame = 0;
             CollectionFreeFormDocumentView.setupKeyframes(docs, docs.length, true);
             targetDoc.lastFrame = docs.length - 1;
@@ -1350,9 +1254,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const y: List<number> = ylist;
         const tags: JSX.Element[] = [];
         let pathPoints = ""; //List of all of the pathpoints that need to be added
-        // console.log(x);
-        // console.log(x.length);
-        // console.log(x[0]);
         for (let i = 0; i < x.length - 1; i++) {
             if (y[i] || x[i]) {
                 if (i === 0) pathPoints = (x[i] - 11) + "," + (y[i] + 33);
@@ -1630,7 +1531,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     @undoBatch
     @action
     nextAppearFrame = (doc: Doc, i: number): void => {
-        console.log("next");
         const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
         const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
         const appearFrame = Cast(doc.appearFrame, "number", null);
@@ -1638,9 +1538,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             doc.appearFrame = 0;
         }
         doc.appearFrame = appearFrame + 1;
-        const olist = new List<number>(numberRange(NumCast(targetDoc.lastFrame)).map(t => targetDoc.presProgressivize && t < (doc.appearFrame ? doc.appearFrame : i) ? 0 : 1));
-        doc["opacity-indexed"] = olist;
-        console.log(doc.appearFrame);
+        this.updateOpacityList(doc["opacity-indexed"], NumCast(doc.appearFrame));
     }
 
     @undoBatch
@@ -1654,9 +1552,32 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             doc.appearFrame = 0;
         }
         doc.appearFrame = Math.max(0, appearFrame - 1);
-        const olist = new List<number>(numberRange(NumCast(targetDoc.lastFrame)).map(t => targetDoc.presProgressivize && t < (doc.appearFrame ? doc.appearFrame : i) ? 0 : 1));
-        doc["opacity-indexed"] = olist;
-        console.log(doc.appearFrame);
+        this.updateOpacityList(doc["opacity-indexed"], NumCast(doc.appearFrame));
+    }
+
+    @action
+    updateOpacityList = (list: any, frame: number) => {
+        const x: List<number> = list;
+        if (x && x.length >= frame) {
+            for (let i = 0; i < x.length; i++) {
+                if (i < frame) {
+                    x[i] = 0;
+                } else if (i >= frame) {
+                    x[i] = 1;
+                }
+            }
+            list = x;
+        } else {
+            x.length = frame + 1;
+            for (let i = 0; i < x.length; i++) {
+                if (i < frame) {
+                    x[i] = 0;
+                } else if (i >= frame) {
+                    x[i] = 1;
+                }
+            }
+            list = x;
+        }
     }
 
     @computed get moreInfoDropdown() {
@@ -1746,37 +1667,37 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                     onPointerDown={e => e.stopPropagation()}
                     onChange={this.viewChanged}
                     value={mode}>
-                    {/* <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Invalid}>Min</option> */}
                     <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Stacking}>List</option>
-                    {/* <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Time}>Time</option> */}
                     <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Carousel}>Slides</option>
                 </select>
                 <div className="presBox-presentPanel">
-                    <span className={`presBox-button ${this.layoutDoc.presStatus !== "edit" ? "active" : ""}`} title={"Reset Presentation" + this.layoutDoc.presStatus ? "" : " From Start"} style={{ minWidth: 60, gridColumn: 2 }}>
-                        <div className="presBox-button-left" onClick={() => this.startOrResetPres(0)}>
-                            <FontAwesomeIcon icon={"clock"} /> &nbsp;
-                            <FontAwesomeIcon icon={this.layoutDoc.presStatus === "auto" ? "pause" : "play"} />
-                        </div>
-                        <div className={`presBox-button-right ${this.playTools ? "active" : ""}`} onClick={e => { e.stopPropagation; this.togglePlay(); }}>
-                            <FontAwesomeIcon className="dropdown" style={{ margin: 0, transform: this.playTools ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={"angle-down"} />
-                            {this.playDropdown}
-                        </div>
-                    </span>
-                    <span className={`presBox-button ${this.layoutDoc.presStatus === "edit" ? "present" : ""}`} title="Present">
+                    <span className={`presBox-button ${this.layoutDoc.presStatus === "edit" ? "present" : ""}`}>
                         <div className="presBox-button-left" onClick={() => this.layoutDoc.presStatus = "manual"}><FontAwesomeIcon icon={"play-circle"} /> &nbsp; Present </div>
                         <div className={`presBox-button-right ${this.presentTools ? "active" : ""}`} onClick={e => { e.stopPropagation; this.togglePresent(); }}>
                             <FontAwesomeIcon className="dropdown" style={{ margin: 0, transform: this.presentTools ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={"angle-down"} />
                             {this.presentDropdown}
                         </div>
                     </span>
-                    <div className={`presBox-button ${this.layoutDoc.presStatus !== "edit" ? "active" : ""}`} title="Back" onClick={this.back}>
-                        <FontAwesomeIcon icon={"arrow-left"} />
-                    </div>
-                    <div className={`presBox-button ${this.layoutDoc.presStatus !== "edit" ? "active" : ""}`} title="Next" onClick={this.next}>
-                        <FontAwesomeIcon icon={"arrow-right"} />
-                    </div>
-                    <div className={`presBox-button ${this.layoutDoc.presStatus !== "edit" ? "edit" : ""}`} title="Next" onClick={() => this.layoutDoc.presStatus = "edit"}>
-                        <FontAwesomeIcon icon={"times"} />
+                    <div className="miniPresOverlay" style={{ display: this.layoutDoc.presStatus !== "edit" ? "inline-flex" : "none" }}>
+                        {/* <span className={`presBox-button ${this.layoutDoc.presStatus !== "edit" ? "active" : ""}`}>
+                            <div className="presBox-button-left" onClick={() => this.startOrResetPres(0)}>
+                                <FontAwesomeIcon icon={"clock"} /> &nbsp;
+                                <FontAwesomeIcon icon={this.layoutDoc.presStatus === "auto" ? "pause" : "play"} />
+                            </div>
+                            <div className={`presBox-button-right ${this.playTools ? "active" : ""}`} onClick={e => { e.stopPropagation; this.togglePlay(); }}>
+                                <FontAwesomeIcon className="dropdown" style={{ margin: 0, transform: this.playTools ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={"angle-down"} />
+                                {this.playDropdown}
+                            </div>
+                        </span> */}
+                        <div className="miniPres-button" onClick={this.back}><FontAwesomeIcon icon={"arrow-left"} /></div>
+                        <div className="miniPres-button" onClick={() => this.startOrResetPres(this.itemIndex)}><FontAwesomeIcon icon={PresBox.Instance.layoutDoc.presStatus === "auto" ? "pause" : "play"} /></div>
+                        <div className="miniPres-button" onClick={this.next}><FontAwesomeIcon icon={"arrow-right"} /></div>
+                        <div className="miniPres-divider"></div>
+                        <div className="miniPres-button-text">Slide {this.itemIndex + 1} / {this.childDocs.length}</div>
+                        <div className="miniPres-divider"></div>
+                        <div className="miniPres-button" onClick={() => this.layoutDoc.presStatus = "edit"}>
+                            <FontAwesomeIcon icon={"times"} />
+                        </div>
                     </div>
                 </div>
             </div>
@@ -1809,14 +1730,4 @@ Scripting.addGlobal(function lookupPresBoxField(container: Doc, field: string, d
     if (field === '_itemIndex') return container._itemIndex;
     if (field === 'presBox') return container;
     return undefined;
-});
-
-
-
-// console.log("render = " + this.layoutDoc.title + " " + this.layoutDoc.presStatus);
-// const presOrderedDocs = DocListCast(activeItem.presOrderedDocs);
-// if (presOrderedDocs.length != this.childDocs.length || presOrderedDocs.some((pd, i) => pd !== this.childDocs[i])) {
-//     this.rootDoc.presOrderedDocs = new List<Doc>(this.childDocs.slice());
-// }
-
-
+});
\ No newline at end of file
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index fc65f34eb..76d23ddfe 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -536,6 +536,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.rootDoc);
             }, icon: "eye"
         });
+        appearanceItems.push({ description: "Create progressivized slide...", event: this.progressivizeText, icon: "desktop" });
         cm.addItem({ description: "Appearance...", subitems: appearanceItems, icon: "eye" });
 
         const options = cm.findByDescription("Options...");
@@ -547,6 +548,69 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         this._downX = this._downY = Number.NaN;
     }
 
+    progressivizeText = () => {
+        const list = this.ProseRef?.getElementsByTagName("li");
+        const mainBulletText: string[] = [];
+        const mainBulletList: Doc[] = [];
+        if (list) {
+            const newBullets: Doc[] = this.recursiveProgressivize(1, list);
+            mainBulletList.push.apply(mainBulletList, newBullets);
+        }
+        console.log(mainBulletList.length);
+        const title = Docs.Create.TextDocument(StrCast(this.rootDoc.title), { title: "Title", _width: 800, _height: 70, x: 20, y: -10, _fontSize: '20pt', backgroundColor: "rgba(0,0,0,0)", appearFrame: 0, _fontWeight: 700 });
+        mainBulletList.push(title);
+        const doc = Docs.Create.FreeformDocument(mainBulletList, {
+            title: StrCast(this.rootDoc.title),
+            x: NumCast(this.props.Document.x), y: NumCast(this.props.Document.y) + NumCast(this.props.Document._height) + 10,
+            _width: 400, _height: 225, _fitToBox: true,
+        });
+        this.props.addDocument?.(doc);
+    }
+
+    recursiveProgressivize = (nestDepth: number, list: HTMLCollectionOf<HTMLLIElement>, d?: number, y?: number, before?: string): Doc[] => {
+        const mainBulletList: Doc[] = [];
+        let b = d ? d : 0;
+        let yLoc = y ? y : 0;
+        let nestCount = 0;
+        let count: string = before ? before : '';
+        const fontSize: string = (16 - (nestDepth * 2)) + 'pt';
+        const xLoc: number = (nestDepth * 20);
+        const width: number = 390 - xLoc;
+        const height: number = 55 - (nestDepth * 5);
+        for (let i = 0; i < list.length; i++) {
+            const mainBullets: number = Number(list[i].getAttribute("data-bulletstyle"));
+            if (mainBullets === nestDepth) {
+                if (list[i].childElementCount > 1) {
+                    b++;
+                    nestCount++;
+                    count = before ? count + nestCount + "." : nestCount + ".";
+                    yLoc += height;
+                    const text = list[i].getElementsByTagName("p")[0].innerText;
+                    const length = text.length;
+                    console.log(yLoc);
+                    const bullet1 = Docs.Create.TextDocument(count + " " + text, { title: "Slide text", _width: width, _height: height, x: xLoc, y: 10 + (yLoc), _fontSize: fontSize, backgroundColor: "rgba(0,0,0,0)", appearFrame: d ? d : b });
+                    mainBulletList.push(bullet1);
+                    const newList = this.recursiveProgressivize(nestDepth + 1, list[i].getElementsByTagName("li"), b, yLoc, count);
+                    mainBulletList.push.apply(mainBulletList, newList);
+                    b += newList.length;
+                    yLoc += newList.length * (55 - ((nestDepth + 1) * 5));
+                } else {
+                    b++;
+                    nestCount++;
+                    count = before ? count + nestCount + "." : nestCount + ".";
+                    yLoc += height;
+                    const text = list[i].innerText;
+                    const length = text.length;
+                    console.log(yLoc);
+                    const bullet1 = Docs.Create.TextDocument(count + " " + text, { title: "Slide text", _width: width, _height: height, x: xLoc, y: 10 + (yLoc), _fontSize: fontSize, backgroundColor: "rgba(0,0,0,0)", appearFrame: d ? d : b });
+                    mainBulletList.push(bullet1);
+                }
+            }
+        }
+        console.log("b: " + b);
+        return mainBulletList;
+    }
+
     recordDictation = () => {
         DictationManager.Controls.listen({
             interimHandler: this.setCurrentBulletContent,
@@ -1374,6 +1438,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                         color: this.props.color ? this.props.color : StrCast(this.layoutDoc[this.props.fieldKey + "-color"], this.props.hideOnLeave ? "white" : "inherit"),
                         pointerEvents: interactive ? undefined : "none",
                         fontSize: Cast(this.layoutDoc._fontSize, "string", null),
+                        fontWeight: Cast(this.layoutDoc._fontWeight, "number", null),
                         fontFamily: StrCast(this.layoutDoc._fontFamily, "inherit"),
                         transition: "opacity 1s"
                     }}
diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss
index 159cb5f8a..fa70b2a41 100644
--- a/src/client/views/presentationview/PresElementBox.scss
+++ b/src/client/views/presentationview/PresElementBox.scss
@@ -2,7 +2,8 @@
     display: grid;
     grid-template-columns: max-content max-content max-content;
     background-color: #d5dce2;
-    // box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.25);
+    font-family: Roboto;
+    letter-spacing: normal;
     position: relative;
     pointer-events: all;
     width: 100%;
@@ -21,13 +22,30 @@
 
     .presElementBox-highlight {
         position: absolute;
-        transform: translate(-100px, -6px);
+        transform: translate(-100px, -4px);
         z-index: -1;
         width: calc(100% + 200px);
-        height: calc(100% + 12px);
+        height: calc(100% + 8px);
         background-color: #AEDDF8;
     }
 
+    .presElementBox-highlightTop {
+        position: absolute;
+        transform: translate(-100px, -4px);
+        z-index: -1;
+        width: calc(100% + 200px);
+        height: calc(50% + 4px);
+    }
+
+    .presElementBox-highlightBottom {
+        position: absolute;
+        transform: translate(-100px, 0px);
+        z-index: -1;
+        top: 50%;
+        width: calc(100% + 200px);
+        height: calc(50% + 4px);
+    }
+
     .documentView-node {
         position: absolute;
         z-index: 1;
@@ -79,8 +97,12 @@
 
 .presElementBox-number {
     font-size: 12px;
+    width: 20;
     font-weight: 700;
-    left: -15;
+    text-align: right;
+    justify-content: center;
+    align-content: center;
+    left: -20;
     position: absolute;
     display: inline-block;
     overflow: hidden;
@@ -110,9 +132,8 @@
     font-size: 10;
     font-weight: 300;
     font-family: Roboto;
-    /* font-style: italic; */
+    z-index: 300;
     letter-spacing: normal;
-    /* left: 10px; */
 }
 
 .presElementBox-embedded {
@@ -174,7 +195,7 @@
     bottom: 3px;
     width: 20px;
     height: 20px;
-    z-index: 200;
+    z-index: 300;
     display: flex;
     background-color: black;
     color: white;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index b3d8cca98..e035ed0b8 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -220,7 +220,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
         let durationInS: number;
         if (this.targetDoc.presDuration) durationInS = NumCast(this.targetDoc.presDuration) / 1000;
         else durationInS = 2;
-        return "V: " + durationInS + "s";
+        return "D: " + durationInS + "s";
     }
 
     @computed get transition() {
@@ -245,25 +245,61 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
         }
     }
 
+    headerUp = (e: React.PointerEvent<HTMLDivElement>) => {
+        e.stopPropagation();
+        e.preventDefault();
+        DragManager.docsBeingDragged = [];
+        this._highlightTopRef.current!.style.borderBottom = "0px";
+        this._highlightBottomRef.current!.style.borderBottom = "0px";
+    }
+
     startDrag = (e: PointerEvent, down: number[], delta: number[]) => {
         // const ele: HTMLElement[] = PresBox.Instance._eleArray.map(doc => doc);
         const activeItem = this.rootDoc;
         const dragData = new DragManager.DocumentDragData(PresBox.Instance.sortArray().map(doc => doc));
         // let value = this.getValue(this._heading);
         // value = typeof value === "string" ? `"${value}"` : value;
+        let dragItem: HTMLElement[] = [];
+        PresBox.Instance._dragArray.map(ele => {
+            const drag = ele;
+            drag.style.backgroundColor = "#d5dce2";
+            drag.style.borderRadius = '5px';
+            dragItem.push(drag);
+        });
         if (activeItem) {
-            DragManager.StartDocumentDrag(PresBox.Instance._dragArray.map(ele => ele), dragData, e.clientX, e.clientY);
+            DragManager.StartDocumentDrag(dragItem.map(ele => ele), dragData, e.clientX, e.clientY);
             activeItem.dragging = true;
             return true;
         }
         return false;
     }
 
+    private _highlightTopRef: React.RefObject<HTMLDivElement> = React.createRef();
+    private _highlightBottomRef: React.RefObject<HTMLDivElement> = React.createRef();
 
 
+    onPointerTop = (e: React.PointerEvent<HTMLDivElement>) => {
+        if (DragManager.docsBeingDragged.length > 0) {
+            this._highlightTopRef.current!.style.borderTop = "solid 2px #5B9FDD";
+        }
+    }
+
+    onPointerBottom = (e: React.PointerEvent<HTMLDivElement>) => {
+        if (DragManager.docsBeingDragged.length > 0) {
+            this._highlightBottomRef.current!.style.borderBottom = "solid 2px #5B9FDD";
+        }
+    }
+
+    onPointerLeave = (e: React.PointerEvent<HTMLDivElement>) => {
+        if (DragManager.docsBeingDragged.length > 0) {
+            this._highlightBottomRef.current!.style.borderBottom = "0px";
+            this._highlightTopRef.current!.style.borderTop = "0px";
+        }
+    }
+
     render() {
         const treecontainer = this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Tree;
-        const className = "presElementBox-item" + (this.itemIndex === this.indexInPres ? " presElementBox-active" : "");
+        const className = "presElementBox-item" + (PresBox.Instance._selectedArray.includes(this.rootDoc) ? " presElementBox-active" : "");
         const pbi = "presElementBox-interaction";
         return !(this.rootDoc instanceof Doc) || this.targetDoc instanceof Promise ? (null) : (
             <div className={className} key={this.props.Document[Id] + this.indexInPres}
@@ -288,6 +324,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                     }
                 }}
                 onPointerDown={this.headerDown}
+                onPointerUp={this.headerUp}
             >
                 <>
                     <div className="presElementBox-number">
@@ -297,7 +334,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                         {`${this.targetDoc?.title}`}
                     </div>
                     <Tooltip title={<><div className="dash-tooltip">{"Movement speed"}</div></>}><div className="presElementBox-time" style={{ display: PresBox.Instance.toolbarWidth > 300 ? "block" : "none" }}>{this.transition}</div></Tooltip>
-                    <Tooltip title={<><div className="dash-tooltip">{"Duration of visibility"}</div></>}><div className="presElementBox-time" style={{ display: PresBox.Instance.toolbarWidth > 300 ? "block" : "none" }}>{this.duration}</div></Tooltip>
+                    <Tooltip title={<><div className="dash-tooltip">{"Duration"}</div></>}><div className="presElementBox-time" style={{ display: PresBox.Instance.toolbarWidth > 300 ? "block" : "none" }}>{this.duration}</div></Tooltip>
                     <Tooltip title={<><div className="dash-tooltip">{"Remove from presentation"}</div></>}><div
                         className="presElementBox-closeIcon"
                         // onPointerDown={e => e.stopPropagation()}
@@ -311,7 +348,9 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                         <FontAwesomeIcon icon={(this.rootDoc.presExpandInlineButton ? "angle-up" : "angle-down")} onPointerDown={e => e.stopPropagation()} />
                     </div></Tooltip>
                 </>
-                <div className="presElementBox-highlight" style={{ display: PresBox.Instance._selectedArray.includes(this.rootDoc) ? "block" : "none" }} />
+                <div ref={this._highlightTopRef} onPointerOver={this.onPointerTop} onPointerLeave={this.onPointerLeave} className="presElementBox-highlightTop" style={{ zIndex: 299, backgroundColor: "rgba(0,0,0,0)" }} />
+                <div ref={this._highlightBottomRef} onPointerOver={this.onPointerBottom} onPointerLeave={this.onPointerLeave} className="presElementBox-highlightBottom" style={{ zIndex: 299, backgroundColor: "rgba(0,0,0,0)" }} />
+                <div className="presElementBox-highlight" style={{ backgroundColor: PresBox.Instance._selectedArray.includes(this.rootDoc) ? "#AEDDF8" : "rgba(0,0,0,0)" }} />
                 <div className="presElementBox-buttons" style={{ display: this.rootDoc.presExpandInlineButton ? "grid" : "none" }}>
                     <button title="Zoom" className={pbi + (this.rootDoc.presZoomButton ? "-selected" : "")} onClick={this.onZoomDocumentClick}><FontAwesomeIcon icon={"search"} onPointerDown={e => e.stopPropagation()} /></button>
                     <button title="Navigate" className={pbi + (this.rootDoc.presNavButton ? "-selected" : "")} onClick={this.onNavigateDocumentClick}><FontAwesomeIcon icon={"location-arrow"} onPointerDown={e => e.stopPropagation()} /></button>
-- 
cgit v1.2.3-70-g09d2


From cc905d329c88d7bdf9b7324a4f02ab92906ba7c8 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 5 Aug 2020 22:20:49 -0400
Subject: cleanup of presentation code pre-merge.

---
 src/client/documents/Documents.ts                  |  4 --
 src/client/util/CurrentUserUtils.ts                |  8 ++--
 src/client/views/InkingStroke.tsx                  |  6 +--
 src/client/views/MainView.tsx                      |  2 +-
 .../CollectionStackingViewFieldColumn.tsx          |  3 +-
 .../views/collections/CollectionTreeView.tsx       |  1 -
 .../collectionFreeForm/PropertiesView.tsx          |  4 +-
 src/client/views/nodes/AudioBox.tsx                |  1 -
 .../views/nodes/CollectionFreeFormDocumentView.tsx | 11 +----
 src/client/views/nodes/DocumentLinksButton.tsx     |  2 +-
 src/client/views/nodes/PresBox.tsx                 | 49 ++++++++++------------
 .../views/nodes/formattedText/FormattedTextBox.tsx | 17 ++++----
 .../views/nodes/formattedText/RichTextMenu.tsx     |  3 +-
 .../views/presentationview/PresElementBox.tsx      |  2 +-
 14 files changed, 46 insertions(+), 67 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 57fcf3a00..959aeac41 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -801,10 +801,6 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.FONTICON), undefined, { hideLinkButton: true, ...(options || {}) });
         }
 
-        export function MenuIconDocument(options?: DocumentOptions) {
-            return InstanceFromProto(Prototypes.get(DocumentType.MENUICON), undefined, { hideLinkButton: true, ...(options || {}) });
-        }
-
         export function PresElementBoxDocument(options?: DocumentOptions) {
             return InstanceFromProto(Prototypes.get(DocumentType.PRESELEMENT), undefined, { ...(options || {}) });
         }
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 8023df8b4..4e59434b5 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -546,7 +546,7 @@ export class CurrentUserUtils {
                     btn.color = "white";
                     btn._backgroundColor = "";
                 }));
-            })
+            });
         });
         return doc.menuStack as Doc;
     }
@@ -763,13 +763,13 @@ export class CurrentUserUtils {
     }
 
     static setupSidebarContainer(doc: Doc) {
-        if (doc["sidebar"] === undefined) {
+        if (doc.sidebar === undefined) {
             const sidebarContainer = new Doc();
             sidebarContainer._chromeStatus = "disabled";
             sidebarContainer.onClick = ScriptField.MakeScript("freezeSidebar()");
-            doc["sidebar"] = new PrefetchProxy(sidebarContainer);
+            doc.sidebar = new PrefetchProxy(sidebarContainer);
         }
-        return doc["sidebar"] as Doc;
+        return doc.sidebar as Doc;
     }
 
     // setup the list of sidebar mode buttons which determine what is displayed in the sidebar
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 6c5eda256..4a77728b6 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -115,9 +115,9 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
             StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "transparent"),
             "none", "none", "0", scaleX, scaleY, "", this.props.active() ? "visiblepainted" : "none", false, true);
 
-        var controlPoints: { X: number, Y: number, I: number }[] = [];
-        var handlePoints: { X: number, Y: number, I: number, dot1: number, dot2: number }[] = [];
-        var handleLine: { X1: number, Y1: number, X2: number, Y2: number, X3: number, Y3: number, dot1: number, dot2: number }[] = [];
+        const controlPoints: { X: number, Y: number, I: number }[] = [];
+        const handlePoints: { X: number, Y: number, I: number, dot1: number, dot2: number }[] = [];
+        const handleLine: { X1: number, Y1: number, X2: number, Y2: number, X3: number, Y3: number, dot1: number, dot2: number }[] = [];
         if (data.length >= 4) {
             for (var i = 0; i <= data.length - 4; i += 4) {
                 controlPoints.push({ X: data[i].X, Y: data[i].Y, I: i });
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 138ff226f..7f50dda72 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -80,7 +80,7 @@ export class MainView extends React.Component {
     @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeWorkspace, Doc)) : CurrentUserUtils.GuestWorkspace; }
     @computed public get mainFreeform(): Opt<Doc> { return (docs => (docs && docs.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); }
 
-    @observable public sidebarContent: any = this.userDoc?.["sidebar"];
+    @observable public sidebarContent: any = this.userDoc?.sidebar;
     @observable public panelContent: string = "none";
     @observable public showProperties: boolean = false;
     public isPointerDown = false;
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 68c233a16..fbc4e1552 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -12,6 +12,7 @@ import { NumCast, StrCast, Cast } from "../../../fields/Types";
 import { ImageField } from "../../../fields/URLField";
 import { TraceMobx } from "../../../fields/util";
 import { Docs, DocUtils } from "../../documents/Documents";
+import { DocumentType } from "../../documents/DocumentTypes";
 import { DragManager } from "../../util/DragManager";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
@@ -366,7 +367,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
                             {this.props.parent.children(this.props.docList, uniqueHeadings.length)}
                             {singleColumn ? (null) : this.props.parent.columnDragger}
                         </div>
-                        {(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled' && type !== 'presentation') ?
+                        {(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled' && type !== DocumentType.PRES) ?
                             <div key={`${heading}-add-document`} className="collectionStackingView-addDocumentButton"
                                 style={{ width: style.columnWidth / style.numGroupColumns }}>
                                 <EditableView {...newEditableViewProps} menuCallback={this.menuCallback} />
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 8ec855c7c..3c7471d7c 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -133,7 +133,6 @@ class TreeView extends React.Component<TreeViewProps> {
     }
 
     protected createTreeDropTarget = (ele: HTMLDivElement) => {
-        console.log("ele");
         this._treedropDisposer?.();
         ele && (this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this), undefined, this.preTreeDrop.bind(this)), this.doc);
     }
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index 2b0a00498..dcbf8e989 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -552,7 +552,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
     getField(key: string) {
         //if (this.selectedDoc) {
-        return Field.toString(this.selectedDoc[key] as Field);
+        return Field.toString(this?.[key] as Field);
         // } else {
         //     return undefined as Opt<string>;
         // }
@@ -698,7 +698,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 <input className="width-range" type="range"
                     defaultValue={Number(this.widthStk)} min={1} max={100}
                     onChange={(action((e) => this.widthStk = e.target.value))}
-                    onMouseDown={(e) => { this._widthUndo = UndoManager.StartBatch("width undo");; }}
+                    onMouseDown={(e) => { this._widthUndo = UndoManager.StartBatch("width undo"); }}
                     onMouseUp={(e) => { this._widthUndo?.end(); this._widthUndo = undefined; }}
                 />
             </div>
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index dba92faae..2396e6973 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -21,7 +21,6 @@ import { Docs, DocUtils } from "../../documents/Documents";
 import { ComputedField } from "../../../fields/ScriptField";
 import { Networking } from "../../Network";
 import { LinkAnchorBox } from "./LinkAnchorBox";
-import { signedCookie } from "cookie-parser";
 
 // testing testing 
 
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 35ed6c5a5..42a42ddf1 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -18,8 +18,6 @@ import { DocumentType } from "../../documents/DocumentTypes";
 import { Zoom, Fade, Flip, Rotate, Bounce, Roll, LightSpeed } from 'react-reveal';
 import { PresBox } from "./PresBox";
 import { InkingStroke } from "../InkingStroke";
-import { PDFViewer } from "../pdf/PDFViewer";
-import { PDFBox } from "./PDFBox";
 
 export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
     dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined;
@@ -119,7 +117,6 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     }
 
     public static updateScrollframe(doc: Doc, time: number) {
-        let _pdfViewer: PDFViewer | undefined;
         const timecode = Math.round(time);
         const scrollIndexed = Cast(doc['scroll-indexed'], listSpec("number"), null);
         scrollIndexed?.length <= timecode + 1 && scrollIndexed.push(undefined as any as number);
@@ -191,15 +188,11 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
             const wlist = new List<number>(numberRange(timecode + 1).map(i => undefined) as any as number[]);
             const hlist = new List<number>(numberRange(timecode + 1).map(i => undefined) as any as number[]);
             const olist = new List<number>(numberRange(timecode + 1).map(t => progressivize && t < (doc.appearFrame ? doc.appearFrame : i) ? 0 : 1));
-            let oarray: List<number>;
-            console.log(doc.title + "AF: " + doc.appearFrame);
-            console.log("timecode: " + timecode);
-            oarray = olist;
+            const oarray = olist;
             oarray.fill(0, 0, NumCast(doc.appearFrame) - 1);
             oarray.fill(1, NumCast(doc.appearFrame), timecode);
             // oarray.fill(0, 0, NumCast(doc.appearFrame) - 1);
-            // oarray.fill(1, NumCast(doc.appearFrame), timecode);
-            // console.log(oarray);
+            // oarray.fill(1, NumCast(doc.appearFrame), timecode);\
             wlist[curTimecode] = NumCast(doc._width);
             hlist[curTimecode] = NumCast(doc._height);
             xlist[curTimecode] = NumCast(doc.x);
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 4713ce447..025669b41 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -125,7 +125,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
         } else if (this.props.InMenu && !this.props.StartLink && DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View) {
             const linkDoc = DocUtils.MakeLink({ doc: DocumentLinksButton.StartLink.props.Document }, { doc: this.props.View.props.Document }, "long drag");
             // this notifies any of the subviews that a document is made so that they can make finer-grained hyperlinks ().  see note above in onLInkButtonMoved
-            DocumentLinksButton.StartLink!._link = this.props.View._link = linkDoc;
+            DocumentLinksButton.StartLink._link = this.props.View._link = linkDoc;
             setTimeout(action(() => DocumentLinksButton.StartLink!._link = this.props.View._link = undefined), 0);
             LinkManager.currentLink = linkDoc;
             if (linkDoc) {
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 1caefdc57..ccf1fb8e3 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -129,7 +129,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 const nextChildDocs = DocListCast(nextTagDoc[Doc.LayoutFieldKey(presTargetDoc)]);
                 nextChildDocs.forEach((doc, i) => {
                     doc.opacity = 1;
-                })
+                });
             }
             const nextSelected = this.itemIndex + 1;
             this.gotoDocument(nextSelected, this.itemIndex);
@@ -158,28 +158,24 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const vfHeight: number = this.checkList(presTargetDoc, presTargetDoc["viewfinder-height-indexed"]);
         // Case 1: document that is not a Golden Layout tab
         if (srcContext) {
-            console.log("CASE 1");
             const srcDocView = DocumentManager.Instance.getDocumentView(srcContext);
             if (srcDocView) {
                 const layoutdoc = Doc.Layout(presTargetDoc);
                 const panelWidth: number = srcDocView.props.PanelWidth();
                 const panelHeight: number = srcDocView.props.PanelHeight();
-                console.log("srcDocView: " + srcDocView.props.PanelWidth());
                 const newPanX = NumCast(presTargetDoc.x) + NumCast(layoutdoc._width) / 2;
                 const newPanY = NumCast(presTargetDoc.y) + NumCast(layoutdoc._height) / 2;
-                let newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight);
+                const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight);
                 srcContext._panX = newPanX + (vfLeft + (vfWidth / 2));
                 srcContext._panY = newPanY + (vfTop + (vfHeight / 2));
                 srcContext._viewScale = newScale;
-                console.log("X: " + srcContext._panX + ", Y: " + srcContext._panY + ", Scale: " + srcContext._viewScale);
             }
         }
         // Case 2: document is the containing collection
         if (docView && !srcContext) {
-            console.log("CASE 2");
             const panelWidth: number = docView.props.PanelWidth();
             const panelHeight: number = docView.props.PanelHeight();
-            let newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight);
+            const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight);
             presTargetDoc._panX = vfLeft + (vfWidth / 2);
             presTargetDoc._panY = vfTop + (vfWidth / 2);
             presTargetDoc._viewScale = newScale;
@@ -791,7 +787,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                 <div className="ribbon-button" style={{ display: "flex", backgroundColor: targetDoc.editProgressivize ? "#aedef8" : "" }} onClick={this.editProgressivize}>Start manually</div>
                             </div>
                             <div className="ribbon-doubleButton" style={{ display: "flex" }}>
-                                <div className="ribbon-button" style={{ backgroundColor: activeItem.openDocument ? "#aedef8" : "" }} onClick={() => { activeItem.openDocument = !activeItem.openDocument }}>Open document</div>
+                                <div className="ribbon-button" style={{ backgroundColor: activeItem.openDocument ? "#aedef8" : "" }} onClick={() => activeItem.openDocument = !activeItem.openDocument}>Open document</div>
                             </div>
                             <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.WEB ? "inline-flex" : "none" }}>
                                 <div className="ribbon-button" onClick={this.progressivizeText}>Store original website</div>
@@ -808,15 +804,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             <div>
                 <div className={'presBox-toolbar-dropdown'} style={{ display: this.newDocumentTools && this.layoutDoc.presStatus === "edit" ? "inline-flex" : "none" }} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
                     <div className="layout-container" style={{ height: 'max-content' }}>
-                        <div className="layout" style={{ border: this.layout === 'blank' ? 'solid 2px #5b9ddd' : '' }} onClick={() => runInAction(() => { this.layout = 'blank'; this.createNewSlide(this.layout); })} />
-                        <div className="layout" style={{ border: this.layout === 'title' ? 'solid 2px #5b9ddd' : '' }} onClick={() => runInAction(() => { this.layout = 'title'; this.createNewSlide(this.layout); })}>
+                        <div className="layout" style={{ border: this.layout === 'blank' ? 'solid 2px #5b9ddd' : '' }} onClick={action(() => { this.layout = 'blank'; this.createNewSlide(this.layout); })} />
+                        <div className="layout" style={{ border: this.layout === 'title' ? 'solid 2px #5b9ddd' : '' }} onClick={action(() => { this.layout = 'title'; this.createNewSlide(this.layout); })}>
                             <div className="title">Title</div>
                             <div className="subtitle">Subtitle</div>
                         </div>
-                        <div className="layout" style={{ border: this.layout === 'header' ? 'solid 2px #5b9ddd' : '' }} onClick={() => runInAction(() => { this.layout = 'header'; this.createNewSlide(this.layout); })}>
+                        <div className="layout" style={{ border: this.layout === 'header' ? 'solid 2px #5b9ddd' : '' }} onClick={action(() => { this.layout = 'header'; this.createNewSlide(this.layout); })}>
                             <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>Section header</div>
                         </div>
-                        <div className="layout" style={{ border: this.layout === 'content' ? 'solid 2px #5b9ddd' : '' }} onClick={() => runInAction(() => { this.layout = 'content'; this.createNewSlide(this.layout); })}>
+                        <div className="layout" style={{ border: this.layout === 'content' ? 'solid 2px #5b9ddd' : '' }} onClick={action(() => { this.layout = 'content'; this.createNewSlide(this.layout); })}>
                             <div className="title" style={{ alignSelf: 'center' }}>Title</div>
                             <div className="content">Text goes here</div>
                         </div>
@@ -845,39 +841,39 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                         {/* <div className="dropdown-textInput"> */}
                         <input className="ribbon-textInput" placeholder="..." type="text" name="fname" ref={this.inputRef} onChange={(e) => {
                             e.stopPropagation();
-                            runInAction(() => { (this.title = e.target.value) });
+                            runInAction(() => this.title = e.target.value);
                         }}></input>
                         {/* </div> */}
                     </div>
                     <div className="ribbon-box">
                         Choose type:
                         <div className="ribbon-doubleButton">
-                            <div title="Text" className={'ribbon-button'} style={{ background: this.addFreeform ? "" : "#aedef8" }} onClick={() => runInAction(() => { this.addFreeform = !this.addFreeform })}>Text</div>
-                            <div title="Freeform" className={'ribbon-button'} style={{ background: this.addFreeform ? "#aedef8" : "" }} onClick={() => runInAction(() => { this.addFreeform = !this.addFreeform })}>Freeform</div>
+                            <div title="Text" className={'ribbon-button'} style={{ background: this.addFreeform ? "" : "#aedef8" }} onClick={action(() => this.addFreeform = !this.addFreeform)}>Text</div>
+                            <div title="Freeform" className={'ribbon-button'} style={{ background: this.addFreeform ? "#aedef8" : "" }} onClick={action(() => this.addFreeform = !this.addFreeform)}>Freeform</div>
                         </div>
                     </div>
                     <div className="ribbon-box" style={{ display: this.addFreeform ? "grid" : "none" }}>
                         Preset layouts:
                         <div className="layout-container" style={{ height: this.openLayouts ? 'max-content' : '75px' }}>
-                            <div className="layout" style={{ border: this.layout === 'blank' ? 'solid 2px #5b9ddd' : '' }} onClick={() => runInAction(() => { this.layout = 'blank' })} />
-                            <div className="layout" style={{ border: this.layout === 'title' ? 'solid 2px #5b9ddd' : '' }} onClick={() => runInAction(() => { this.layout = 'title' })}>
+                            <div className="layout" style={{ border: this.layout === 'blank' ? 'solid 2px #5b9ddd' : '' }} onClick={action(() => this.layout = 'blank')} />
+                            <div className="layout" style={{ border: this.layout === 'title' ? 'solid 2px #5b9ddd' : '' }} onClick={action(() => this.layout = 'title')}>
                                 <div className="title">Title</div>
                                 <div className="subtitle">Subtitle</div>
                             </div>
-                            <div className="layout" style={{ border: this.layout === 'header' ? 'solid 2px #5b9ddd' : '' }} onClick={() => runInAction(() => { this.layout = 'header' })}>
+                            <div className="layout" style={{ border: this.layout === 'header' ? 'solid 2px #5b9ddd' : '' }} onClick={action(() => this.layout = 'header')}>
                                 <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>Section header</div>
                             </div>
-                            <div className="layout" style={{ border: this.layout === 'content' ? 'solid 2px #5b9ddd' : '' }} onClick={() => runInAction(() => { this.layout = 'content' })}>
+                            <div className="layout" style={{ border: this.layout === 'content' ? 'solid 2px #5b9ddd' : '' }} onClick={action(() => this.layout = 'content')}>
                                 <div className="title" style={{ alignSelf: 'center' }}>Title</div>
                                 <div className="content">Text goes here</div>
                             </div>
-                            <div className="layout" style={{ border: this.layout === 'twoColumns' ? 'solid 2px #5b9ddd' : '' }} onClick={() => runInAction(() => { this.layout = 'twoColumns' })}>
+                            <div className="layout" style={{ border: this.layout === 'twoColumns' ? 'solid 2px #5b9ddd' : '' }} onClick={action(() => this.layout = 'twoColumns')}>
                                 <div className="title" style={{ alignSelf: 'center', gridColumn: '1/3' }}>Title</div>
                                 <div className="content" style={{ gridColumn: 1, gridRow: 2 }}>Column one text</div>
                                 <div className="content" style={{ gridColumn: 2, gridRow: 2 }}>Column two text</div>
                             </div>
                         </div>
-                        <div className="open-layout" onClick={() => runInAction(() => { this.openLayouts = !this.openLayouts })}>
+                        <div className="open-layout" onClick={action(() => this.openLayouts = !this.openLayouts)}>
                             <FontAwesomeIcon style={{ transition: 'all 0.3s', transform: this.openLayouts ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={"caret-down"} size={"lg"} />
                         </div>
                     </div>
@@ -974,10 +970,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     }
 
     // For toggling the options when the user wants to select play
-    @action togglePlay = () => { this.playTools = !this.playTools; }
+    @action togglePlay = () => { this.playTools = !this.playTools; };
 
     // For toggling the options when the user wants to select play
-    @action togglePresent = () => { this.presentTools = !this.presentTools; }
+    @action togglePresent = () => { this.presentTools = !this.presentTools; };
 
     // Case in which the document has keyframes to navigate to next key frame
     @undoBatch
@@ -1381,9 +1377,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         if (doc && tagDocView) {
 
             const scale = tagDocView.childScaling();
-            console.log("childScaling: " + scale);
             const scale2 = tagDocView.props.ScreenToLocalTransform().Scale;
-            console.log("ScreenToLocal...Scale: " + scale2);
             let height = doc.offsetHeight;
             let width = doc.offsetWidth;
             let top = doc.offsetTop;
@@ -1544,7 +1538,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     @undoBatch
     @action
     prevAppearFrame = (doc: Doc, i: number): void => {
-        console.log("prev");
         const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
         const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
         const appearFrame = Cast(doc.appearFrame, "number", null);
@@ -1595,7 +1588,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         if (activeItem) {
             return (
                 <>
-                    <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={() => runInAction(() => { this.newDocumentTools = !this.newDocumentTools; })}><FontAwesomeIcon icon={"plus"} />
+                    <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={action(() => this.newDocumentTools = !this.newDocumentTools)}><FontAwesomeIcon icon={"plus"} />
                         <FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} />
                     </div></Tooltip>
                     <div className="toolbar-divider" />
@@ -1636,7 +1629,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         } else {
             return (
                 <>
-                    <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={() => runInAction(() => { this.newDocumentTools = !this.newDocumentTools; })}>
+                    <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={action(() => this.newDocumentTools = !this.newDocumentTools)}>
                         <FontAwesomeIcon icon={"plus"} />
                         <FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} />
                     </div></Tooltip>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 76d23ddfe..ab1de5529 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -577,20 +577,19 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         const xLoc: number = (nestDepth * 20);
         const width: number = 390 - xLoc;
         const height: number = 55 - (nestDepth * 5);
-        for (let i = 0; i < list.length; i++) {
-            const mainBullets: number = Number(list[i].getAttribute("data-bulletstyle"));
+        Array.from(list).forEach(listItem => {
+            const mainBullets: number = Number(listItem.getAttribute("data-bulletstyle"));
             if (mainBullets === nestDepth) {
-                if (list[i].childElementCount > 1) {
+                if (listItem.childElementCount > 1) {
                     b++;
                     nestCount++;
                     count = before ? count + nestCount + "." : nestCount + ".";
                     yLoc += height;
-                    const text = list[i].getElementsByTagName("p")[0].innerText;
+                    const text = listItem.getElementsByTagName("p")[0].innerText;
                     const length = text.length;
-                    console.log(yLoc);
                     const bullet1 = Docs.Create.TextDocument(count + " " + text, { title: "Slide text", _width: width, _height: height, x: xLoc, y: 10 + (yLoc), _fontSize: fontSize, backgroundColor: "rgba(0,0,0,0)", appearFrame: d ? d : b });
                     mainBulletList.push(bullet1);
-                    const newList = this.recursiveProgressivize(nestDepth + 1, list[i].getElementsByTagName("li"), b, yLoc, count);
+                    const newList = this.recursiveProgressivize(nestDepth + 1, listItem.getElementsByTagName("li"), b, yLoc, count);
                     mainBulletList.push.apply(mainBulletList, newList);
                     b += newList.length;
                     yLoc += newList.length * (55 - ((nestDepth + 1) * 5));
@@ -599,15 +598,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     nestCount++;
                     count = before ? count + nestCount + "." : nestCount + ".";
                     yLoc += height;
-                    const text = list[i].innerText;
+                    const text = listItem.innerText;
                     const length = text.length;
-                    console.log(yLoc);
                     const bullet1 = Docs.Create.TextDocument(count + " " + text, { title: "Slide text", _width: width, _height: height, x: xLoc, y: 10 + (yLoc), _fontSize: fontSize, backgroundColor: "rgba(0,0,0,0)", appearFrame: d ? d : b });
                     mainBulletList.push(bullet1);
                 }
             }
-        }
-        console.log("b: " + b);
+        });
         return mainBulletList;
     }
 
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 6e268be48..5af07c15d 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -903,8 +903,9 @@ export default class RichTextMenu extends AntimodeMenu {
             ref_node = pos.nodeBefore;
         }
         if (pos.nodeAfter !== null && pos.nodeAfter !== undefined) {
-            if (!pos.nodeBefore || this.view.state.selection.$from.pos !== this.view.state.selection.$to.pos)
+            if (!pos.nodeBefore || this.view.state.selection.$from.pos !== this.view.state.selection.$to.pos) {
                 ref_node = pos.nodeAfter;
+            }
         }
         if (!ref_node && pos.pos > 0) {
             let skip = false;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index e035ed0b8..11ffde9dd 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -259,7 +259,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
         const dragData = new DragManager.DocumentDragData(PresBox.Instance.sortArray().map(doc => doc));
         // let value = this.getValue(this._heading);
         // value = typeof value === "string" ? `"${value}"` : value;
-        let dragItem: HTMLElement[] = [];
+        const dragItem: HTMLElement[] = [];
         PresBox.Instance._dragArray.map(ele => {
             const drag = ele;
             drag.style.backgroundColor = "#d5dce2";
-- 
cgit v1.2.3-70-g09d2


From 33487aa34fd455acf5216cfee7913d6e36f390ed Mon Sep 17 00:00:00 2001
From: Geireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>
Date: Fri, 7 Aug 2020 01:35:46 +0800
Subject: presentaiton options slightly reformatted :pear:

---
 src/client/views/PropertiesButtons.tsx             |  3 +-
 .../views/collections/CollectionDockingView.tsx    |  3 +-
 .../collectionFreeForm/PropertiesView.scss         | 37 +++++++++
 .../collectionFreeForm/PropertiesView.tsx          | 64 ++++++++--------
 src/client/views/nodes/PresBox.scss                |  8 +-
 src/client/views/nodes/PresBox.tsx                 | 89 ++++++++++------------
 .../views/nodes/formattedText/FormattedTextBox.tsx | 19 ++---
 .../views/presentationview/PresElementBox.scss     |  4 +-
 .../views/presentationview/PresElementBox.tsx      |  3 +-
 9 files changed, 128 insertions(+), 102 deletions(-)

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

diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 55eb6c028..5c584d270 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -221,8 +221,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                 <div className="propertiesButtons-linker"
                     style={{ backgroundColor: isPinned ? "white" : "", color: isPinned ? "black" : "white" }}
                     onClick={e => DockedFrameRenderer.PinDoc(targetDoc, isPinned)}>
-                    <FontAwesomeIcon className="documentdecorations-icon" size="lg" icon="map-pin"
-                    />
+                    <FontAwesomeIcon className="documentdecorations-icon" size="lg" icon="map-pin" />
                 </div>
 
                 <div className="propertiesButtons-title" style={{
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 7bd79b2ef..7e096fa37 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -873,9 +873,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
         return (
             <div className="miniPres"
                 style={{ width: 250, height: 30, background: '#323232' }}
-                onClick={() => document.addEventListener("keydown", PresBox.Instance.minimizeEvents, false)}
             >
-                {<div className="miniPresOverlay" onClick={() => document.addEventListener("keydown", PresBox.Instance.minimizeEvents, false)}>
+                {<div className="miniPresOverlay">
                     <div className="miniPres-button" onClick={PresBox.Instance.back}><FontAwesomeIcon icon={"arrow-left"} /></div>
                     <div className="miniPres-button" onClick={() => PresBox.Instance.startAutoPres(PresBox.Instance.itemIndex)}><FontAwesomeIcon icon={PresBox.Instance.layoutDoc.presStatus === "auto" ? "pause" : "play"} /></div>
                     <div className="miniPres-button" onClick={PresBox.Instance.next}><FontAwesomeIcon icon={"arrow-right"} /></div>
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.scss b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
index 5b41db90e..3ae94efb7 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.scss
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
@@ -405,6 +405,43 @@
         }
 
     }
+
+    .propertiesView-presTrails {
+        border-bottom: 1px solid black;
+        //padding: 8.5px;
+
+        .propertiesView-presTrails-title {
+            font-weight: bold;
+            font-size: 12.5px;
+            padding: 4px;
+            display: flex;
+            color: white;
+            padding-left: 8px;
+            background-color: rgb(51, 51, 51);
+
+            &:hover {
+                cursor: pointer;
+            }
+
+            .propertiesView-presTrails-title-icon {
+                float: right;
+                right: 0;
+                position: absolute;
+                margin-left: 2px;
+                margin-right: 9px;
+
+                &:hover {
+                    cursor: pointer;
+                }
+            }
+        }
+
+        .propertiesView-presTrails-content {
+            font-size: 10px;
+            padding: 10px;
+            margin-left: 5px;
+        }
+    }
 }
 
 .inking-button {
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index 89f48fc65..cef2241c9 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -71,11 +71,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     @observable openAppearance: boolean = true;
     @observable openTransform: boolean = true;
     //Pres Trails booleans:
-    @observable openAddSlide: boolean = true;
-    @observable openPresentationTools: boolean = true;
-    @observable openPresTransitions: boolean = true;
-    @observable openPresProgressivize: boolean = true;
-    @observable openSlideOptions: boolean = true;
+    @observable openPresTransitions: boolean = false;
+    @observable openPresProgressivize: boolean = false;
+    @observable openAddSlide: boolean = false;
+    @observable openSlideOptions: boolean = false;
 
     @observable inActions: boolean = false;
     @observable _controlBtn: boolean = false;
@@ -874,6 +873,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 </div>;
             }
             if (this.isPres) {
+                const selectedItem: boolean = PresBox.Instance._selectedArray.length > 0;
                 return <div className="propertiesView" style={{ width: this.props.width }} >
                     <div className="propertiesView-title" style={{ width: this.props.width }}>
                         Presentation
@@ -890,57 +890,57 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             </div>
                         </div>
                     </div>
-                    <div className="propertiesView-settings">
-                        <div className="propertiesView-settings-title"
-                            onPointerDown={() => runInAction(() => { this.openAddSlide = !this.openAddSlide; })}
-                            style={{ backgroundColor: this.openAddSlide ? "black" : "" }}>
-                            &nbsp; <FontAwesomeIcon icon={"plus"} /> &nbsp; Add new slide
-                        <div className="propertiesView-settings-title-icon">
-                                <FontAwesomeIcon icon={this.openAddSlide ? "caret-down" : "caret-right"} size="lg" color="white" />
-                            </div>
-                        </div>
-                        {this.openAddSlide ? <div className="propertiesView-settings-content">
-                            {PresBox.Instance.newDocumentDropdown}
-                        </div> : null}
-                    </div>
-                    <div className="propertiesView-sharing">
-                        <div className="propertiesView-sharing-title"
+                    {!selectedItem ? (null) : <div className="propertiesView-presTrails">
+                        <div className="propertiesView-presTrails-title"
                             onPointerDown={() => runInAction(() => { this.openPresTransitions = !this.openPresTransitions; })}
                             style={{ backgroundColor: this.openPresTransitions ? "black" : "" }}>
                             &nbsp; <FontAwesomeIcon icon={"rocket"} /> &nbsp; Transitions
-                        <div className="propertiesView-sharing-title-icon">
+                        <div className="propertiesView-presTrails-title-icon">
                                 <FontAwesomeIcon icon={this.openPresTransitions ? "caret-down" : "caret-right"} size="lg" color="white" />
                             </div>
                         </div>
-                        {this.openPresTransitions ? <div className="propertiesView-sharing-content">
+                        {this.openPresTransitions ? <div className="propertiesView-presTrails-content">
                             {PresBox.Instance.transitionDropdown}
                         </div> : null}
-                    </div>
-                    <div className="propertiesView-sharing">
-                        <div className="propertiesView-sharing-title"
+                    </div>}
+                    {!selectedItem ? (null) : <div className="propertiesView-presTrails">
+                        <div className="propertiesView-presTrails-title"
                             onPointerDown={() => runInAction(() => { this.openPresProgressivize = !this.openPresProgressivize; })}
                             style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}>
                             &nbsp; <FontAwesomeIcon icon={"tasks"} /> &nbsp; Progressivize
-                        <div className="propertiesView-sharing-title-icon">
+                        <div className="propertiesView-presTrails-title-icon">
                                 <FontAwesomeIcon icon={this.openPresProgressivize ? "caret-down" : "caret-right"} size="lg" color="white" />
                             </div>
                         </div>
-                        {this.openPresProgressivize ? <div className="propertiesView-sharing-content">
+                        {this.openPresProgressivize ? <div className="propertiesView-presTrails-content">
                             {PresBox.Instance.progressivizeDropdown}
                         </div> : null}
-                    </div>
-                    <div className="propertiesView-sharing">
-                        <div className="propertiesView-sharing-title"
+                    </div>}
+                    {!selectedItem ? (null) : <div className="propertiesView-presTrails">
+                        <div className="propertiesView-presTrails-title"
                             onPointerDown={() => runInAction(() => { this.openSlideOptions = !this.openSlideOptions; })}
                             style={{ backgroundColor: this.openSlideOptions ? "black" : "" }}>
                             &nbsp; <FontAwesomeIcon icon={"cog"} /> &nbsp; {PresBox.Instance.stringType} options
-                        <div className="propertiesView-sharing-title-icon">
+                        <div className="propertiesView-presTrails-title-icon">
                                 <FontAwesomeIcon icon={this.openSlideOptions ? "caret-down" : "caret-right"} size="lg" color="white" />
                             </div>
                         </div>
-                        {this.openSlideOptions ? <div className="propertiesView-sharing-content">
+                        {this.openSlideOptions ? <div className="propertiesView-presTrails-content">
                             {PresBox.Instance.optionsDropdown}
                         </div> : null}
+                    </div>}
+                    <div className="propertiesView-presTrails">
+                        <div className="propertiesView-presTrails-title"
+                            onPointerDown={() => runInAction(() => { this.openAddSlide = !this.openAddSlide; })}
+                            style={{ backgroundColor: this.openAddSlide ? "black" : "" }}>
+                            &nbsp; <FontAwesomeIcon icon={"plus"} /> &nbsp; Add new slide
+                        <div className="propertiesView-presTrails-title-icon">
+                                <FontAwesomeIcon icon={this.openAddSlide ? "caret-down" : "caret-right"} size="lg" color="white" />
+                            </div>
+                        </div>
+                        {this.openAddSlide ? <div className="propertiesView-presTrails-content">
+                            {PresBox.Instance.newDocumentDropdown}
+                        </div> : null}
                     </div>
                     <div className="propertiesView-sharing">
                         <div className="propertiesView-sharing-title"
diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss
index 77e7924dd..a87b0e466 100644
--- a/src/client/views/nodes/PresBox.scss
+++ b/src/client/views/nodes/PresBox.scss
@@ -247,7 +247,7 @@ $light-background: #ececec;
         justify-self: left;
         margin-top: 5px;
         padding-left: 10px;
-        background-color: rgb(222, 222, 222);
+        background-color: $light-background;
         border: solid 1px black;
         min-width: 80px;
         max-width: 200px;
@@ -272,7 +272,7 @@ $light-background: #ececec;
             cursor: pointer;
             position: relative;
             height: 100%;
-            background: #d5dce2;
+            background: $light-background;
             display: flex;
             align-items: center;
             justify-content: center;
@@ -436,7 +436,7 @@ $light-background: #ececec;
 
             .presBox-dropdownOptions {
                 position: absolute;
-                top: 29px;
+                top: 24px;
                 left: -1px;
                 z-index: 200;
                 width: 85%;
@@ -461,7 +461,7 @@ $light-background: #ececec;
             background-color: $light-background;
             border-radius: 5px;
             font-size: 10;
-            height: 30;
+            height: 25;
             padding-left: 5px;
             align-items: center;
             margin-top: 5px;
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index efcea832d..a9daba675 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -371,11 +371,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             if (srcContext.miniPres) {
                 srcContext.miniPres = false;
                 CollectionDockingView.AddRightSplit(this.rootDoc);
-                document.removeEventListener("keydown", this.minimizeEvents, false);
             } else {
                 srcContext.miniPres = true;
                 this.props.addDocTab?.(this.rootDoc, "close");
-                document.addEventListener("keydown", this.minimizeEvents, false);
             }
         }
     }
@@ -506,20 +504,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         }
     }
 
-    // Key events when the minimized player is active
-    @action
-    minimizeEvents = (e: KeyboardEvent) => {
-        e.stopPropagation();
-        e.preventDefault();
-        if (e.keyCode === 27) { // Escape key
-            this.layoutDoc.presStatus = "edit";
-        } if (e.keyCode === 37) { // left(37) / a(65) / up(38) to go back
-            this.back();
-        } if (e.keyCode === 39) { // right (39) / d(68) / down(40) to go to next
-            this.next();
-        }
-    }
-
     // Key for when the presentaiton is active (according to Selection Manager)
     @action
     keyEvents = (e: KeyboardEvent) => {
@@ -531,10 +515,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             else this.layoutDoc.presStatus = "edit";
         } if ((e.metaKey || e.altKey) && e.keyCode === 65) { // Ctrl-A to select all
             if (this.layoutDoc.presStatus === "edit") this._selectedArray = this.childDocs;
-        } if (e.keyCode === 37) { // left(37) / a(65) / up(38) to go back
-            if (this.layoutDoc.presStatus !== "edit") this.back();
-        } if (e.keyCode === 39) { // right (39) / d(68) / down(40) to go to next
-            if (this.layoutDoc.presStatus !== "edit") this.next();
+        } if (e.keyCode === 37 || e.keyCode === 38) { // left(37) / a(65) / up(38) to go back
+            this.back();
+        } if (e.keyCode === 39 || e.keyCode === 40) { // right (39) / d(68) / down(40) to go to next
+            this.next();
         } if (e.keyCode === 32) { // spacebar to 'present' or autoplay
             if (this.layoutDoc.presStatus !== "edit") this.startAutoPres(0);
             else this.layoutDoc.presStatus = "manual";
@@ -720,7 +704,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                             <div className="ribbon-property"> {duration} s </div>
                         </div>
                         <input type="range" step="0.1" min="0.1" max="10" value={duration} style={{ display: targetDoc.type === DocumentType.AUDIO ? "none" : "block" }} className={"toolbar-slider"} id="duration-slider" onChange={(e: React.ChangeEvent<HTMLInputElement>) => { e.stopPropagation(); this.setDurationTime(e.target.value); }} />
-                        <div className={"slider-headers"} style={{ display: targetDoc.type === DocumentType.AUDIO ? "none" : "block" }}>
+                        <div className={"slider-headers"} style={{ display: targetDoc.type === DocumentType.AUDIO ? "none" : "grid" }}>
                             <div className="slider-text">Short</div>
                             <div className="slider-text">Medium</div>
                             <div className="slider-text">Long</div>
@@ -814,6 +798,20 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                             <div className="ribbon-doubleButton" style={{ display: "flex" }}>
                                 <div className="ribbon-button" style={{ backgroundColor: activeItem.openDocument ? "#aedef8" : "" }} onClick={() => activeItem.openDocument = !activeItem.openDocument}>Open document</div>
                             </div>
+                            <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.COL ? "inline-flex" : "none" }}>
+                                <div className="ribbon-button" style={{ backgroundColor: activeItem.presPinView ? "#aedef8" : "" }}
+                                    onClick={() => {
+                                        activeItem.presPinView = !activeItem.presPinView;
+                                        if (activeItem.presPinView) {
+                                            const x = targetDoc._panX;
+                                            const y = targetDoc._panY;
+                                            const scale = targetDoc._viewScale;
+                                            activeItem.presPinViewX = x;
+                                            activeItem.presPinViewY = y;
+                                            activeItem.presPinViewScale = scale;
+                                        }
+                                    }}>Presentation pin view</div>
+                            </div>
                             <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.WEB ? "inline-flex" : "none" }}>
                                 <div className="ribbon-button" onClick={this.progressivizeText}>Store original website</div>
                             </div>
@@ -1592,35 +1590,26 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
 
     @computed get toolbar() {
         const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
-        if (activeItem) {
-            return (
-                <div id="toolbarContainer" className={'presBox-toolbar'} style={{ display: this.layoutDoc.presStatus === "edit" ? "inline-flex" : "none" }}>
-                    <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={action(() => this.newDocumentTools = !this.newDocumentTools)}>
-                        <FontAwesomeIcon icon={"plus"} />
-                        <FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} />
-                    </div></Tooltip>
-                    <div className="toolbar-divider" />
-                    <Tooltip title={<><div className="dash-tooltip">{"View paths"}</div></>}><div className={`toolbar-button ${this.pathBoolean ? "active" : ""}`}>
-                        <FontAwesomeIcon icon={"exchange-alt"} onClick={this.childDocs.length > 1 ? this.viewPaths : undefined} />
-                    </div></Tooltip>
-                    <Tooltip title={<><div className="dash-tooltip">{this.expandBoolean ? "Minimize all" : "Expand all"}</div></>}>
-                        <div className={`toolbar-button ${this.expandBoolean ? "active" : ""}`} onClick={() => { this.toggleExpand(); this.childDocs.forEach((doc, ind) => { if (this.expandBoolean) doc.presExpandInlineButton = true; else doc.presExpandInlineButton = false; }); }}>
-                            <FontAwesomeIcon icon={"eye"} />
-                        </div>
-                    </Tooltip>
-                    <div className="toolbar-divider" />
-                </div>
-            );
-        } else {
-            return (
-                <div id="toolbarContainer" className={'presBox-toolbar'}>
-                    <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={action(() => this.newDocumentTools = !this.newDocumentTools)}>
-                        <FontAwesomeIcon icon={"plus"} />
-                        <FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} />
-                    </div></Tooltip>
-                </div>
-            );
-        }
+        return (
+            <div id="toolbarContainer" className={'presBox-toolbar'} style={{ display: this.layoutDoc.presStatus === "edit" ? "inline-flex" : "none" }}>
+                <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={action(() => this.newDocumentTools = !this.newDocumentTools)}>
+                    <FontAwesomeIcon icon={"plus"} />
+                    <FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} />
+                </div></Tooltip>
+                <div className="toolbar-divider" />
+                <Tooltip title={<><div className="dash-tooltip">{"View paths"}</div></>}>
+                    <div style={{ opacity: this.childDocs.length > 1 ? 1 : 0.3 }} className={`toolbar-button ${this.pathBoolean ? "active" : ""}`} onClick={this.childDocs.length > 1 ? this.viewPaths : undefined}>
+                        <FontAwesomeIcon icon={"exchange-alt"} />
+                    </div>
+                </Tooltip>
+                <Tooltip title={<><div className="dash-tooltip">{this.expandBoolean ? "Minimize all" : "Expand all"}</div></>}>
+                    <div style={{ opacity: this.childDocs.length > 0 ? 1 : 0.3 }} className={`toolbar-button ${this.expandBoolean ? "active" : ""}`} onClick={() => { if (this.childDocs.length > 0) this.toggleExpand(); this.childDocs.forEach((doc, ind) => { if (this.expandBoolean) doc.presExpandInlineButton = true; else doc.presExpandInlineButton = false; }); }}>
+                        <FontAwesomeIcon icon={"eye"} />
+                    </div>
+                </Tooltip>
+                <div className="toolbar-divider" />
+            </div>
+        );
     }
 
     /**
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index af4bd77c7..cc37cf586 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -577,7 +577,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         const mainBulletText: string[] = [];
         const mainBulletList: Doc[] = [];
         if (list) {
-            const newBullets: Doc[] = this.recursiveProgressivize(1, list);
+            const newBullets: Doc[] = this.recursiveProgressivize(1, list)[0];
             mainBulletList.push.apply(mainBulletList, newBullets);
         }
         console.log(mainBulletList.length);
@@ -591,7 +591,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         this.props.addDocument?.(doc);
     }
 
-    recursiveProgressivize = (nestDepth: number, list: HTMLCollectionOf<HTMLLIElement>, d?: number, y?: number, before?: string): Doc[] => {
+    recursiveProgressivize = (nestDepth: number, list: HTMLCollectionOf<HTMLLIElement>, d?: number, y?: number, before?: string): [Doc[], number] => {
         const mainBulletList: Doc[] = [];
         let b = d ? d : 0;
         let yLoc = y ? y : 0;
@@ -607,29 +607,30 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 if (listItem.childElementCount > 1) {
                     b++;
                     nestCount++;
-                    count = before ? count + nestCount + "." : nestCount + ".";
                     yLoc += height;
+                    count = before ? count + nestCount + "." : nestCount + ".";
                     const text = listItem.getElementsByTagName("p")[0].innerText;
                     const length = text.length;
-                    const bullet1 = Docs.Create.TextDocument(count + " " + text, { title: "Slide text", _width: width, _height: height, x: xLoc, y: 10 + (yLoc), _fontSize: fontSize, backgroundColor: "rgba(0,0,0,0)", appearFrame: d ? d : b });
+                    const bullet1 = Docs.Create.TextDocument(count + " " + text, { title: "Slide text", _width: width, _autoHeight: true, x: xLoc, y: (yLoc), _fontSize: fontSize, backgroundColor: "rgba(0,0,0,0)", appearFrame: d ? d : b });
+                    // yLoc += NumCast(bullet1._height);
                     mainBulletList.push(bullet1);
                     const newList = this.recursiveProgressivize(nestDepth + 1, listItem.getElementsByTagName("li"), b, yLoc, count);
-                    mainBulletList.push.apply(mainBulletList, newList);
-                    b += newList.length;
+                    mainBulletList.push.apply(mainBulletList, newList[0]);
                     yLoc += newList.length * (55 - ((nestDepth + 1) * 5));
                 } else {
                     b++;
                     nestCount++;
-                    count = before ? count + nestCount + "." : nestCount + ".";
                     yLoc += height;
+                    count = before ? count + nestCount + "." : nestCount + ".";
                     const text = listItem.innerText;
                     const length = text.length;
-                    const bullet1 = Docs.Create.TextDocument(count + " " + text, { title: "Slide text", _width: width, _height: height, x: xLoc, y: 10 + (yLoc), _fontSize: fontSize, backgroundColor: "rgba(0,0,0,0)", appearFrame: d ? d : b });
+                    const bullet1 = Docs.Create.TextDocument(count + " " + text, { title: "Slide text", _width: width, _autoHeight: true, x: xLoc, y: (yLoc), _fontSize: fontSize, backgroundColor: "rgba(0,0,0,0)", appearFrame: d ? d : b });
+                    // yLoc += NumCast(bullet1._height);
                     mainBulletList.push(bullet1);
                 }
             }
         });
-        return mainBulletList;
+        return [mainBulletList, yLoc];
     }
 
     recordDictation = () => {
diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss
index 3d730d7ac..1e776384a 100644
--- a/src/client/views/presentationview/PresElementBox.scss
+++ b/src/client/views/presentationview/PresElementBox.scss
@@ -4,7 +4,7 @@ $light-background: #ececec;
 
 .presElementBox-item {
     display: grid;
-    grid-template-columns: max-content max-content max-content;
+    grid-template-columns: max-content max-content max-content max-content;
     background-color: #d5dce2;
     font-family: Roboto;
     letter-spacing: normal;
@@ -122,7 +122,7 @@ $light-background: #ececec;
     padding-left: 10px;
     padding-right: 10px;
     letter-spacing: normal;
-    max-width: max-content;
+    width: max-content;
     text-overflow: ellipsis;
     overflow: hidden;
     white-space: pre;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 816577847..a6dbb76ef 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -326,11 +326,12 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                     <div className="presElementBox-number">
                         {`${this.indexInPres + 1}.`}
                     </div>
-                    <div ref={this._dragRef} className="presElementBox-name">
+                    <div ref={this._dragRef} className="presElementBox-name" style={{ maxWidth: (PresBox.Instance.toolbarWidth - 70) }}>
                         {`${this.targetDoc?.title}`}
                     </div>
                     <Tooltip title={<><div className="dash-tooltip">{"Movement speed"}</div></>}><div className="presElementBox-time" style={{ display: PresBox.Instance.toolbarWidth > 300 ? "block" : "none" }}>{this.transition}</div></Tooltip>
                     <Tooltip title={<><div className="dash-tooltip">{"Duration"}</div></>}><div className="presElementBox-time" style={{ display: PresBox.Instance.toolbarWidth > 300 ? "block" : "none" }}>{this.duration}</div></Tooltip>
+                    <Tooltip title={<><div className="dash-tooltip">{"Presentation pin view"}</div></>}><div className="presElementBox-time" style={{ fontWeight: 700, display: this.rootDoc.presPinView && PresBox.Instance.toolbarWidth > 300 ? "block" : "none" }}>V</div></Tooltip>
                     <Tooltip title={<><div className="dash-tooltip">{"Remove from presentation"}</div></>}><div
                         className="presElementBox-closeIcon"
                         onClick={e => {
-- 
cgit v1.2.3-70-g09d2


From b827bdfecc5646b479c7e5654ed98243de91cf9a Mon Sep 17 00:00:00 2001
From: Lionel Han <47760119+IGoByJoe@users.noreply.github.com>
Date: Thu, 6 Aug 2020 17:24:56 -0700
Subject: cleaned up code and fixed bugs

---
 src/client/views/nodes/AudioBox.tsx                | 415 ++++++---------------
 src/client/views/nodes/AudioResizer.scss           |  11 -
 src/client/views/nodes/AudioResizer.tsx            |  48 ---
 .../views/nodes/formattedText/FormattedTextBox.tsx |  18 +-
 4 files changed, 114 insertions(+), 378 deletions(-)
 delete mode 100644 src/client/views/nodes/AudioResizer.scss
 delete mode 100644 src/client/views/nodes/AudioResizer.tsx

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

diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 1d060120e..11dfe5fe6 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -60,7 +60,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     _start: number = 0;
     _hold: boolean = false;
     _left: boolean = false;
-    _amount: number = 1;
     _markers: Array<any> = [];
     _first: boolean = false;
     _dragging = false;
@@ -77,7 +76,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     @observable private _height: number = NumCast(this.layoutDoc.height);
     @observable private _paused: boolean = false;
     @observable private static _scrubTime = 0;
-    @observable private _repeat: boolean = false;
     @computed get audioState(): undefined | "recording" | "paused" | "playing" { return this.dataDoc.audioState as (undefined | "recording" | "paused" | "playing"); }
     set audioState(value) { this.dataDoc.audioState = value; }
     public static SetScrubTime = (timeInMillisFrom1970: number) => { runInAction(() => AudioBox._scrubTime = 0); runInAction(() => AudioBox._scrubTime = timeInMillisFrom1970); };
@@ -126,36 +124,38 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                 const sel = selected.length ? selected[0].props.Document : undefined;
                 let link;
                 if (sel) {
-                    // for determining if the link is created after recording (since it will use linkTIme rather than creation date)
-                    DocListCast(sel.links).map((l, i) => {
+                    // for determining if the link is created after recording (since it will use linkTime rather than creation date)
+                    DocListCast(this.dataDoc.links).map((l, i) => {
                         let la1 = l.anchor1 as Doc;
                         let la2 = l.anchor2 as Doc;
-                        let linkTime = NumCast(l.anchor2_timecode);
-                        let endTime;
-                        if (Doc.AreProtosEqual(la1, this.dataDoc)) {
-                            la1 = l.anchor2 as Doc;
-                            la2 = l.anchor1 as Doc;
-                            linkTime = NumCast(l.anchor1_timecode);
-                        }
-                        if (la2.audioStart) {
-                            linkTime = NumCast(la2.audioStart);
-                        }
+                        if (la1 === sel || la2 === sel) { // if the selected document is linked to this audio 
+                            let linkTime = NumCast(l.anchor2_timecode);
+                            let endTime;
+                            if (Doc.AreProtosEqual(la1, this.dataDoc)) {
+                                la1 = l.anchor2 as Doc;
+                                la2 = l.anchor1 as Doc;
+                                linkTime = NumCast(l.anchor1_timecode);
+                            }
+                            if (la2.audioStart) {
+                                linkTime = NumCast(la2.audioStart);
+                            }
 
-                        if (la1.audioStart) {
-                            linkTime = NumCast(la1.audioStart);
-                        }
+                            if (la1.audioStart) {
+                                linkTime = NumCast(la1.audioStart);
+                            }
 
-                        if (la1.audioEnd) {
-                            endTime = NumCast(la1.audioEnd);
-                        }
+                            if (la1.audioEnd) {
+                                endTime = NumCast(la1.audioEnd);
+                            }
 
-                        if (la2.audioEnd) {
-                            endTime = NumCast(la2.audioEnd);
-                        }
+                            if (la2.audioEnd) {
+                                endTime = NumCast(la2.audioEnd);
+                            }
 
-                        if (linkTime) {
-                            link = true;
-                            this.layoutDoc.playOnSelect && this.recordingStart && sel && !Doc.AreProtosEqual(sel, this.props.Document) && endTime ? this.playFrom(linkTime, endTime) : this.playFrom(linkTime);
+                            if (linkTime) {
+                                link = true;
+                                this.layoutDoc.playOnSelect && this.recordingStart && sel && !Doc.AreProtosEqual(sel, this.props.Document) && (endTime ? this.playFrom(linkTime, endTime) : this.playFrom(linkTime));
+                            }
                         }
                     });
                 }
@@ -189,19 +189,19 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         }
     }
 
+    // pause play back
     pause = action(() => {
-        if (this._repeat) {
-            this.playFrom(0);
-        } else {
-            this._ele!.pause();
-            this.audioState = "paused";
-        }
+        console.log("pause");
+        this._ele!.pause();
+        this.audioState = "paused";
     });
 
+    // play audio for documents created during recording 
     playFromTime = (absoluteTime: number) => {
         this.recordingStart && this.playFrom((absoluteTime - this.recordingStart) / 1000);
     }
 
+    // play back the audio from time
     @action
     playFrom = (seekTimeInSeconds: number, endTime: number = this.dataDoc.duration) => {
         let play;
@@ -220,15 +220,15 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                 this._ele.play();
                 runInAction(() => this.audioState = "playing");
                 if (endTime !== this.dataDoc.duration) {
-                    play = setTimeout(() => this.pause(), (this._duration) * 1000);
+                    play = setTimeout(() => this.pause(), (this._duration) * 1000); // use setTimeout to play a specific duration
                 }
-            } else { // this is getting called because time is greater than duration
+            } else {
                 this.pause();
             }
         }
     }
 
-
+    // update the recording time
     updateRecordTime = () => {
         if (this.audioState === "recording") {
             if (this._paused) {
@@ -241,6 +241,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         }
     }
 
+    // starts recording
     recordAudioAnnotation = async () => {
         this._stream = await navigator.mediaDevices.getUserMedia({ audio: true });
         this._recorder = new MediaRecorder(this._stream);
@@ -259,6 +260,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         setTimeout(() => this._recorder && this.stopRecording(), 60 * 60 * 1000); // stop after an hour
     }
 
+    // context menu
     specificContextMenu = (e: React.MouseEvent): void => {
         const funcs: ContextMenuProps[] = [];
         funcs.push({ description: (this.layoutDoc.playOnSelect ? "Don't play" : "Play") + " when link is selected", event: () => this.layoutDoc.playOnSelect = !this.layoutDoc.playOnSelect, icon: "expand-arrows-alt" });
@@ -268,6 +270,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         ContextMenu.Instance?.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
     }
 
+    // stops the recording 
     stopRecording = action(() => {
         this._recorder.stop();
         this._recorder = undefined;
@@ -278,6 +281,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         ind !== -1 && (DocUtils.ActiveRecordings.splice(ind, 1));
     });
 
+    // button for starting and stopping the recording
     recordClick = (e: React.MouseEvent) => {
         if (e.button === 0 && !e.ctrlKey) {
             this._recorder ? this.stopRecording() : this.recordAudioAnnotation();
@@ -285,14 +289,13 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         }
     }
 
+    // for play button
     onPlay = (e: any) => {
         this.playFrom(this._ele!.paused ? this._ele!.currentTime : -1);
         e.stopPropagation();
     }
-    onStop = (e: any) => {
-        this.layoutDoc.playOnSelect = !this.layoutDoc.playOnSelect;
-        e.stopPropagation();
-    }
+
+    // creates a text document for dictation
     onFile = (e: any) => {
         const newDoc = Docs.Create.TextDocument("", {
             title: "", _chromeStatus: "disabled",
@@ -306,125 +309,21 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         e.stopPropagation();
     }
 
+    // ref for updating time
     setRef = (e: HTMLAudioElement | null) => {
         e?.addEventListener("timeupdate", this.timecodeChanged);
         e?.addEventListener("ended", this.pause);
         this._ele = e;
     }
 
+    // returns the path of the audio file
     @computed get path() {
         const field = Cast(this.props.Document[this.props.fieldKey], AudioField);
         const path = (field instanceof AudioField) ? field.url.href : "";
         return path === nullAudio ? "" : path;
     }
 
-    // @action
-    // buckets = () => {
-    //     let audioCtx = new (window.AudioContext)();
-    //     const buckets: number[] = [];
-
-    //     axios({ url: this.path, responseType: "arraybuffer" })
-    //         .then(response => runInAction(() => {
-    //             let audioData = response.data;
-
-    //             audioCtx.decodeAudioData(audioData, buffer => {
-    //                 let decodedAudioData = buffer.getChannelData(0);
-    //                 const NUMBER_OF_BUCKETS = 100;
-    //                 let bucketDataSize = Math.floor(decodedAudioData.length / NUMBER_OF_BUCKETS);
-
-    //                 for (let i = 0; i < NUMBER_OF_BUCKETS; i++) {
-    //                     let startingPoint = i * bucketDataSize;
-    //                     let endingPoint = i * bucketDataSize + bucketDataSize;
-    //                     let max = 0;
-    //                     for (let j = startingPoint; j < endingPoint; j++) {
-    //                         if (decodedAudioData[j] > max) {
-    //                             max = decodedAudioData[j];
-    //                         }
-    //                     }
-    //                     let size = Math.abs(max);
-    //                     buckets.push(size / 2);
-    //                 }
-
-    //             });
-    //             return buckets
-    //         }));
-    // }
-
-    @action
-    buckets = async () => {
-        let audioCtx = new (window.AudioContext)();
-        const buckets: number[] = [];
-
-        axios({ url: this.path, responseType: "arraybuffer" })
-            .then(response => {
-                let audioData = response.data;
-
-                audioCtx.decodeAudioData(audioData, action(buffer => {
-                    let decodedAudioData = buffer.getChannelData(0);
-                    const NUMBER_OF_BUCKETS = 100;
-                    let bucketDataSize = Math.floor(decodedAudioData.length / NUMBER_OF_BUCKETS);
-
-                    for (let i = 0; i < NUMBER_OF_BUCKETS; i++) {
-                        let startingPoint = i * bucketDataSize;
-                        let endingPoint = i * bucketDataSize + bucketDataSize;
-                        let max = 0;
-                        for (let j = startingPoint; j < endingPoint; j++) {
-                            if (decodedAudioData[j] > max) {
-                                max = decodedAudioData[j];
-                            }
-                        }
-                        let size = Math.abs(max);
-                        buckets.push(size / 2);
-                        this._buckets.push(size / 2);
-                    }
-
-                }));
-                return buckets;
-            });
-    }
-
-    @computed get peaks() {
-        // let audioCtx = new (window.AudioContext)();
-        // let buckets: number[] = [];
-
-        // return (async () => {
-        //     await axios({ url: this.path, responseType: "arraybuffer" })
-        //         .then(response => {
-        //             let audioData = response.data;
-
-        //             audioCtx.decodeAudioData(audioData, buffer => {
-        //                 let decodedAudioData = buffer.getChannelData(0);
-        //                 const NUMBER_OF_BUCKETS = 100;
-        //                 let bucketDataSize = Math.floor(decodedAudioData.length / NUMBER_OF_BUCKETS);
-
-
-
-        //                 for (let i = 0; i < NUMBER_OF_BUCKETS; i++) {
-        //                     let startingPoint = i * bucketDataSize;
-        //                     let endingPoint = i * bucketDataSize + bucketDataSize;
-        //                     let max = 0;
-        //                     for (let j = startingPoint; j < endingPoint; j++) {
-        //                         if (decodedAudioData[j] > max) {
-        //                             max = decodedAudioData[j];
-        //                         }
-        //                     }
-        //                     let size = Math.abs(max);
-        //                     console.log(size);
-        //                     buckets.push(size / 2);
-        //                     console.log(buckets);
-        //                 }
-        //             });
-        //             console.log(buckets);
-        //             return buckets;
-        //         });
-        //     console.log(buckets.length);
-        //     return buckets;
-        // })();
-
-
-        return this.buckets();
-    }
-
+    // returns the html audio element
     @computed get audio() {
         const interactive = this.active() ? "-interactive" : "";
         return <audio ref={this.setRef} className={`audiobox-control${interactive}`}>
@@ -433,12 +332,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         </audio>;
     }
 
-    @action
-    onRepeat = (e: React.MouseEvent) => {
-        this._repeat = !this._repeat;
-        e.stopPropagation();
-    }
-
+    // pause the time during recording phase
     @action
     recordPause = (e: React.MouseEvent) => {
         this._pauseStart = new Date().getTime();
@@ -448,6 +342,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
 
     }
 
+    // continue the recording
     @action
     recordPlay = (e: React.MouseEvent) => {
         this._pauseEnd = new Date().getTime();
@@ -457,12 +352,15 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
 
     }
 
+    // return the total time paused to update the correct time
     @computed get pauseTime() {
         return (this._pauseEnd - this._pauseStart);
     }
 
+    // creates a new label 
     @action
     newMarker(marker: Doc) {
+        marker.data = "";
         if (this.dataDoc[this.annotationKey]) {
             this.dataDoc[this.annotationKey].push(marker);
         } else {
@@ -470,46 +368,43 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         }
     }
 
-    start(marker: number) {
-        console.log("start!");
+    // the starting time of the marker
+    start(startingPoint: number) {
         this._hold = true;
-        this._start = marker;
+        this._start = startingPoint;
     }
 
+    // creates a new marker
     @action
     end(marker: number) {
-        console.log("end!");
         this._hold = false;
-        //this._markers.push(Docs.Create.LabelDocument({ isLabel: false, audioStart: this._start, audioEnd: marker, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document }))
         let newMarker = Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false, useLinkSmallAnchor: true, hideLinkButton: true, audioStart: this._start, audioEnd: marker, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document });
         newMarker.data = "";
         if (this.dataDoc[this.annotationKey]) {
-            this.dataDoc[this.annotationKey].push(newMarker); // onClick: ScriptField.MakeScript(`playFrom(${NumCast(this._start)}, ${NumCast(marker)})`)
+            this.dataDoc[this.annotationKey].push(newMarker);
         } else {
             this.dataDoc[this.annotationKey] = new List<Doc>([newMarker]);
         }
 
-
         this._start = 0;
-        this._amount++;
     }
 
+    // starting the drag event for marker resizing
     onPointerDown = (e: React.PointerEvent, m: any, left: boolean): void => {
         e.stopPropagation();
         e.preventDefault();
         this._isPointerDown = true;
-        console.log("click");
         this._currMarker = m;
         this._timeline?.setPointerCapture(e.pointerId);
         this._left = left;
 
-
         document.removeEventListener("pointermove", this.onPointerMove);
         document.addEventListener("pointermove", this.onPointerMove);
         document.removeEventListener("pointerup", this.onPointerUp);
         document.addEventListener("pointerup", this.onPointerUp);
     }
 
+    // ending the drag event for marker resizing
     @action
     onPointerUp = (e: PointerEvent): void => {
         e.stopPropagation();
@@ -526,6 +421,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         document.removeEventListener("pointerup", this.onPointerUp);
     }
 
+    // resizes the marker while dragging
     onPointerMove = async (e: PointerEvent) => {
         e.stopPropagation();
         e.preventDefault();
@@ -537,24 +433,22 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
 
         const rect = await (e.target as any).getBoundingClientRect();
 
-        // if (e.target as HTMLElement === document.getElementById("timeline")) {
-
         let newTime = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
 
         this.changeMarker(this._currMarker, newTime);
-        // }
     }
 
+    // updates the marker with the new time
     @action
     changeMarker = (m: any, time: any) => {
         for (let i = 0; i < this.dataDoc[this.annotationKey].length; i++) {
             if (this.isSame(this.dataDoc[this.annotationKey][i], m)) {
-                // this._left ? this._markers[i][0] = time : this._markers[i][1] = time;
                 this._left ? this.dataDoc[this.annotationKey][i].audioStart = time : this.dataDoc[this.annotationKey][i].audioEnd = time;
             }
         }
     }
 
+    // checks if the two markers are the same with start and end time
     isSame = (m1: any, m2: any) => {
         if (m1.audioStart === m2.audioStart && m1.audioEnd === m2.audioEnd) {
             return true;
@@ -562,6 +456,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         return false;
     }
 
+    // instantiates a new array of size 500 for marker layout
     markers = () => {
         const increment = NumCast(this.layoutDoc.duration) / 500;
         this._count = [];
@@ -571,38 +466,12 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
 
     }
 
-    // Probably need a better way to format
-    // isOverlap = (m: any, i: number) => {
-    //     console.log("called");
-    //     let counter = 0;
-
-    //     if (this._first) {
-    //         this._markers = [];
-    //         this._first = false;
-    //     }
-    //     for (let i = 0; i < this._markers.length; i++) {
-    //         if ((m.audioEnd > this._markers[i].audioStart && m.audioStart < this._markers[i].audioEnd)) {
-    //             counter++;
-    //             console.log(counter);
-    //         }
-    //     }
-
-    //     if (this.dataDoc.markerAmount < counter) {
-    //         this.dataDoc.markerAmount = counter;
-    //     }
-
-    //     this._markers.push(m);
-
-    //     return counter;
-    // }
-
+    // makes sure no markers overlaps each other by setting the correct position and width
     isOverlap = (m: any) => {
         if (this._first) {
             this._first = false;
             this.markers();
         }
-
-
         let max = 0
 
         for (let i = 0; i < 500; i++) {
@@ -613,8 +482,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                     max = this._count[i][1];
                 }
             }
-
-
         }
 
         for (let i = 0; i < 500; i++) {
@@ -630,76 +497,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         return max - 1
     }
 
-
-    @action
-    onHover = () => {
-        this._dragging = true;
-    }
-
-    @action
-    onLeave = () => {
-        this._dragging = false;
-    }
-    // onMouseOver={this.onHover} onMouseLeave={this.onLeave}
-
-    change = (e: React.PointerEvent) => {
-        e.stopPropagation();
-        e.preventDefault();
-        const rect = (e.target as any).getBoundingClientRect();
-
-        const wasPaused = this.audioState === "paused";
-        this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
-        wasPaused && this.pause();
-        console.log("double!");
-    }
-
-    rangeScript = () => AudioBox.RangeScript;
-
-    labelScript = () => AudioBox.LabelScript;
-
-    // see if time is encapsulated by comparing time on both sides (for moving onto a new row in the timeline for the markers)
-    check = (e: React.PointerEvent) => {
-        if (e.target as HTMLElement === document.getElementById("timeline")) {
-            return true;
-        }
-    }
-
-    reset = () => {
-        this._first = true;
-    }
-
-    @computed get height() {
-        console.log(this.layoutDoc._height);
-        if (this.layoutDoc._height) {
-            return 0.8 * NumCast(this.layoutDoc._height)
-        }
-    }
-
-    // waveform() {
-    //     let wavesurfer: any;
-    //     if (WaveSurfer) {
-    //         this.path ?
-    //             wavesurfer = WaveSurfer.create({
-    //                 container: 'waveform',
-    //                 waveColor: "grey",
-    //                 progressColor: "blue"
-    //             })
-    //             :
-    //             wavesurfer = (null);
-    //     } else {
-    //         console.log("hi");
-    //     }
-
-    //     if (wavesurfer) {
-    //         wavesurfer.on('ready', function () {
-    //             wavesurfer.play();
-    //         });
-
-    //         wavesurfer.load(this.path);
-    //         console.log("hi");
-    //     }
-    // }
-
+    // returns the audio waveform
     @computed get waveform() {
         return <Waveform
             color={"darkblue"}
@@ -712,6 +510,43 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
             progressColor={"blue"} />;
     }
 
+    // decodes the audio file into peaks for generating the waveform
+    @action
+    buckets = async () => {
+        let audioCtx = new (window.AudioContext)();
+
+        axios({ url: this.path, responseType: "arraybuffer" })
+            .then(response => {
+                let audioData = response.data;
+
+                audioCtx.decodeAudioData(audioData, action(buffer => {
+                    let decodedAudioData = buffer.getChannelData(0);
+                    const NUMBER_OF_BUCKETS = 100;
+                    let bucketDataSize = Math.floor(decodedAudioData.length / NUMBER_OF_BUCKETS);
+
+                    for (let i = 0; i < NUMBER_OF_BUCKETS; i++) {
+                        let startingPoint = i * bucketDataSize;
+                        let endingPoint = i * bucketDataSize + bucketDataSize;
+                        let max = 0;
+                        for (let j = startingPoint; j < endingPoint; j++) {
+                            if (decodedAudioData[j] > max) {
+                                max = decodedAudioData[j];
+                            }
+                        }
+                        let size = Math.abs(max);
+                        this._buckets.push(size / 2);
+                    }
+
+                }));
+            });
+    }
+
+    // Returns the peaks of the audio waveform
+    @computed get peaks() {
+        return this.buckets();
+    }
+
+    // for updating the width and height of the waveform with timeline ref
     timelineRef = (timeline: HTMLDivElement) => {
         const observer = new _global.ResizeObserver(action((entries: any) => {
             for (const entry of entries) {
@@ -724,6 +559,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         this._timeline = timeline;
     }
 
+    // update the width and height of the audio waveform
     @action
     update = (width: number, height: number) => {
         if (height) {
@@ -741,8 +577,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                 if (context) {
                     context.scale(ratio1, ratio2)
                 }
-
-
             }
 
             let canvas1 = document.getElementsByTagName("canvas")[1];
@@ -758,36 +592,28 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                 if (context) {
                     context.scale(ratio1, ratio2)
                 }
-
-                // let parent = canvas1.parentElement;
-                // if (parent) {
-                //     parent.style.width = `${NumCast(this.layoutDoc.currentTimecode) / NumCast(this.dataDoc.duration) * width}`;
-                //     parent.style.height = `${this._height}`;
-                // }
             }
         }
     }
 
+    rangeScript = () => AudioBox.RangeScript;
+
+    labelScript = () => AudioBox.LabelScript;
+
+    // for indicating the first marker that is rendered
+    reset = () => this._first = true;
 
     render() {
         trace();
         const interactive = this.active() ? "-interactive" : "";
         this.reset();
-        // this.waveform();
-        this.path && this._buckets.length !== 100 ? this.buckets() : null;
+        this.path && this._buckets.length !== 100 ? this.peaks : null; // render waveform if audio is done recording
         return <div className={`audiobox-container`} onContextMenu={this.specificContextMenu} onClick={!this.path ? this.recordClick : undefined}>
             {!this.path ?
                 <div className="audiobox-buttons">
                     <div className="audiobox-dictation" onClick={this.onFile}>
                         <FontAwesomeIcon style={{ width: "30px", background: this.layoutDoc.playOnSelect ? "yellow" : "rgba(0,0,0,0)" }} icon="file-alt" size={this.props.PanelHeight() < 36 ? "1x" : "2x"} />
                     </div>
-                    {/* <button className={`audiobox-record${interactive}`} style={{ backgroundColor: this.audioState === "recording" ? "lightgrey" : "black" }}>
-                        {this.audioState === "recording" ?
-                            <div className="recording" style={{}}>
-                                10:00
-                                    <FontAwesomeIcon style={{ width: "100%" }} icon={"stop-circle"} size={this.props.PanelHeight() < 36 ? "1x" : "2x"} />
-                                <FontAwesomeIcon style={{ width: "100%" }} icon={"pause"} size={this.props.PanelHeight() < 36 ? "1x" : "2x"} /> </div> : "RECORD"}
-                    </button> */}
                     {this.audioState === "recording" ?
                         <div className="recording" onClick={e => e.stopPropagation()}>
                             <div className="buttons" onClick={this.recordClick}>
@@ -798,19 +624,16 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                             </div>
                             <div className="time">{formatTime(Math.round(NumCast(this.layoutDoc.currentTimecode)))}</div>
                         </div>
-
                         :
                         <button className={`audiobox-record${interactive}`} style={{ backgroundColor: "black" }}>
                             RECORD
                             </button>}
                 </div> :
-                <div className="audiobox-controls" > {/*onClick={this.layoutDoc.playOnSelect ? this.onPlay : undefined}*/}
+                <div className="audiobox-controls" >
                     <div className="audiobox-dictation"></div>
                     <div className="audiobox-player" >
                         <div className="audiobox-playhead" title={this.audioState === "paused" ? "play" : "pause"} onClick={this.onPlay}> <FontAwesomeIcon style={{ width: "100%", position: "absolute", left: "0px", top: "5px", borderWidth: "thin", borderColor: "white" }} icon={this.audioState === "paused" ? "play" : "pause"} size={"1x"} /></div>
-                        {/* <div className="audiobox-playhead" onClick={this.onStop}><FontAwesomeIcon style={{ width: "100%", background: this.layoutDoc.playOnSelect ? "darkgrey" : "" }} icon="hand-point-left" size={this.props.PanelHeight() < 36 ? "1x" : "2x"} /></div>
-                        <div className="audiobox-playhead" onClick={this.onRepeat}><FontAwesomeIcon style={{ width: "100%", background: this._repeat ? "darkgrey" : "" }} icon="redo-alt" size={this.props.PanelHeight() < 36 ? "1x" : "2x"} /></div> */}
-                        <div className="audiobox-timeline" ref={this.timelineRef} onClick={e => { e.stopPropagation(); e.preventDefault(); }} onDoubleClick={e => this.change}
+                        <div className="audiobox-timeline" ref={this.timelineRef} onClick={e => { e.stopPropagation(); e.preventDefault(); }}
                             onPointerDown={e => {
                                 e.stopPropagation();
                                 e.preventDefault();
@@ -834,21 +657,9 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                 }
                             }}>
                             <div className="waveform" id="waveform" style={{ height: `${100}%`, width: "100%", bottom: "0px" }}>
-                                {/* {console.log(this.peaks)} */}
-                                {/* <Waveform
-                                    color={"#000000"}
-                                    height={this._height}
-                                    barWidth={0.1}
-                                    pos={this.layoutDoc.currentTimecode}
-                                    duration={this.dataDoc.duration}
-                                    peaks={this._buckets.length === 100 ? this._buckets : undefined}
-
-                                    progressColor={"#0000ff"} /> */}
                                 {this.waveform}
-                                {/* {this.waveform} */}
                             </div>
                             {DocListCast(this.dataDoc[this.annotationKey]).map((m, i) => {
-                                // let text = Docs.Create.TextDocument("hello", { title: "label", _showSidebar: false, _autoHeight: false });
                                 let rect;
                                 (!m.isLabel) ?
                                     (this.layoutDoc.hideMarkers) ? (null) :
@@ -869,8 +680,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                                 ignoreAutoHeight={false}
                                                 bringToFront={emptyFunction}
                                                 scriptContext={this} />
-                                            {/* <LabelBox {... this.props} Document={m} /> */}
-                                            {/* <div className="click" onClick={e => { this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)) }}></div> */}
                                             <div className="resizer" onPointerDown={e => this.onPointerDown(e, m, false)}></div>
                                         </div>
                                     :
@@ -905,13 +714,12 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                     linkTime = NumCast(l.anchor1_timecode);
                                 }
 
-                                if (la2.audioStart) {
+                                if (la2.audioStart && !la2.audioEnd) {
                                     linkTime = NumCast(la2.audioStart);
                                 }
 
                                 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}%` }} onClick={e => e.stopPropagation()}>
-                                        {/* <div className={this.props.PanelHeight() < 32 ? "audioBox-linker-mini" : "audioBox-linker"} key={"linker" + i}> */}
                                         <DocumentView {...this.props}
                                             Document={l}
                                             NativeHeight={returnZero}
@@ -933,7 +741,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                             })}
                             <div className="audiobox-current" id="current" onClick={e => { e.stopPropagation(); e.preventDefault(); }} style={{ left: `${NumCast(this.layoutDoc.currentTimecode) / NumCast(this.dataDoc.duration, 1) * 100}%`, pointerEvents: "none" }} />
                             {this.audio}
-
                         </div>
                         <div className="current-time">
                             {formatTime(Math.round(NumCast(this.layoutDoc.currentTimecode)))}
diff --git a/src/client/views/nodes/AudioResizer.scss b/src/client/views/nodes/AudioResizer.scss
deleted file mode 100644
index 892ad21e7..000000000
--- a/src/client/views/nodes/AudioResizer.scss
+++ /dev/null
@@ -1,11 +0,0 @@
-.resizer {
-    width: 0px;
-    height: 100%;
-    position: absolute;
-    right: 0px;
-    z-index: 999;
-    cursor: e-resize;
-    content: " ";
-    display: inline-block;
-    border-left: 20px solid transparent;
-}
\ No newline at end of file
diff --git a/src/client/views/nodes/AudioResizer.tsx b/src/client/views/nodes/AudioResizer.tsx
deleted file mode 100644
index f9ab8353f..000000000
--- a/src/client/views/nodes/AudioResizer.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { observer } from "mobx-react"
-import React = require("react");
-import "./AudioResizer.scss";
-
-@observer
-export class AudioResizer extends React.Component {
-    private _isPointerDown = false;
-
-    onPointerDown = (e: React.PointerEvent): void => {
-        e.stopPropagation();
-        e.preventDefault();
-        this._isPointerDown = true;
-        console.log("click");
-
-        document.removeEventListener("pointermove", this.onPointerMove);
-        document.addEventListener("pointermove", this.onPointerMove);
-        document.removeEventListener("pointerup", this.onPointerUp);
-        document.addEventListener("pointerup", this.onPointerUp);
-    }
-
-    onPointerUp = (e: PointerEvent): void => {
-        e.stopPropagation();
-        e.preventDefault();
-        this._isPointerDown = false;
-
-        document.removeEventListener("pointermove", this.onPointerMove);
-        document.removeEventListener("pointerup", this.onPointerUp);
-    }
-
-    onPointerMove = (e: PointerEvent): void => {
-        e.stopPropagation();
-        e.preventDefault();
-        console.log("drag");
-
-        if (!this._isPointerDown) {
-            return;
-        }
-
-        let resize = document.getElementById("resizer");
-        if (resize) {
-            resize.style.right += e.movementX;
-        }
-    }
-
-    render() {
-        return <div className="resizer" onPointerDown={this.onPointerDown}></div>
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 91940466f..fabda4d20 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -206,7 +206,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     dispatchTransaction = (tx: Transaction) => {
         let timeStamp;
         clearTimeout(timeStamp);
-        console.log("hi");
         if (this._editorView) {
 
             const metadata = tx.selection.$from.marks().find((m: Mark) => m.type === schema.marks.metadata);
@@ -255,12 +254,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     (curText !== Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text) && (this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())));
                     if ((!curTemp && !curProto) || curText || curLayout?.Data.includes("dash")) { // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
                         if (json.replace(/"selection":.*/, "") !== curLayout?.Data.replace(/"selection":.*/, "")) {
-                            console.log("type");
                             if (!this._pause && !this.layoutDoc._timeStampOnEnter) {
-                                console.log("started");
-                                timeStamp = setTimeout(() => this.pause(), 10 * 1000);
+                                timeStamp = setTimeout(() => this.pause(), 10 * 1000); // 10 seconds delay for time stamp
                             }
 
+                            // if 10 seconds have passed, insert time stamp the next time you type
                             if (this._pause) {
                                 this._pause = false;
                                 this.insertTime();
@@ -305,6 +303,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         return hours.toString().padStart(2, '0') + ':' + minutes.toString().padStart(2, '0') + ':' + seconds.toString().padStart(2, '0');
     }
 
+    // for inserting timestamps 
     insertTime = () => {
         let linkTime;
         if (this._first) {
@@ -320,13 +319,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 }
 
             })
-
-
-
         }
         this._currentTime = Date.now();
         let time;
-        console.log(this._linkTime);
         this._linkTime ? time = this.formatTime(Math.round(this._linkTime + this._currentTime / 1000 - this._recordingStart / 1000)) : time = null;
 
         if (this._editorView) {
@@ -347,7 +342,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 let value = "";
                 this._break = false;
                 value = this.layoutDoc._timeStampOnEnter ? "[" + time + "] " : "\n" + "[" + time + "] ";
-                console.log(value);
                 const from = state.selection.from;
                 const inserted = state.tr.insertText(value).addMark(from, from + value.length + 1, mark);
                 this._editorView.dispatch(this._editorView.state.tr.insertText(value));
@@ -683,7 +677,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             const recordingStart = DateCast(this.props.Document.recordingStart).date.getTime();
             this._break = false;
             value = "" + (mark.attrs.modified * 1000 - recordingStart) / 1000 + value;
-            console.log(value);
             const from = state.selection.from;
             const inserted = state.tr.insertText(value).addMark(from, from + value.length + 1, mark);
             this._editorView.dispatch(inserted.setSelection(TextSelection.create(inserted.doc, from, from + value.length + 1)));
@@ -1440,11 +1433,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     @computed get sidebarColor() { return StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "transparent")); }
     render() {
         TraceMobx();
-        trace();
-        // if (this.props.Document.recordingStart) {
-        //     console.log(DateCast(this.props.Document.recordingStart).date.getTime());
-        // }
-
         const scale = this.props.ContentScaling() * NumCast(this.layoutDoc._viewScale, 1);
         const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : "";
         const interactive = Doc.GetSelectedTool() === InkTool.None && !this.layoutDoc.isBackground;
-- 
cgit v1.2.3-70-g09d2


From 301b10ba693dc76ebcd42d3fa4020410f2092bee Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 6 Aug 2020 23:13:50 -0400
Subject: fixed lint warnings

---
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 48 +++++++-------
 src/client/views/nodes/AudioBox.tsx                | 75 ++++++++++++----------
 src/client/views/nodes/PresBox.tsx                 |  4 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  3 +-
 4 files changed, 67 insertions(+), 63 deletions(-)

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

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 5b1f3c01c..ef4b7b9d2 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1504,32 +1504,30 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
 
     @computed get presPaths() {
         const presPaths = "presPaths" + (this.props.presPaths ? "" : "-hidden");
-        if (PresBox.Instance) return (
-            <>
-                {!this.props.presPaths ? (null) : <><div>{PresBox.Instance.order}</div>
-                    <svg className={presPaths}>
-                        <defs>
-                            <marker id="arrow" markerWidth="3" overflow="visible" markerHeight="3" refX="5" refY="5" orient="auto" markerUnits="strokeWidth">
-                                <path d="M0,0 L0,6 L9,3 z" fill="#69a6db" />
-                            </marker>
-                            <marker id="square" markerWidth="3" markerHeight="3" overflow="visible"
-                                refX="5" refY="5" orient="auto" markerUnits="strokeWidth">
-                                <path d="M 5,1 L 9,5 5,9 1,5 z" fill="#69a6db" />
-                            </marker>
-                            <marker id="markerSquare" markerWidth="7" markerHeight="7" refX="4" refY="4"
-                                orient="auto" overflow="visible">
-                                <rect x="1" y="1" width="5" height="5" fill="#69a6db" />
-                            </marker>
-
-                            <marker id="markerArrow" markerWidth="5" markerHeight="5" refX="2" refY="7"
-                                orient="auto" overflow="visible">
-                                <path d="M2,2 L2,13 L8,7 L2,2" fill="#69a6db" />
-                            </marker>
-                        </defs>;
+        return !(PresBox.Instance) ? (null) : (<>
+            {!this.props.presPaths ? (null) : <><div>{PresBox.Instance.order}</div>
+                <svg className={presPaths}>
+                    <defs>
+                        <marker id="arrow" markerWidth="3" overflow="visible" markerHeight="3" refX="5" refY="5" orient="auto" markerUnits="strokeWidth">
+                            <path d="M0,0 L0,6 L9,3 z" fill="#69a6db" />
+                        </marker>
+                        <marker id="square" markerWidth="3" markerHeight="3" overflow="visible"
+                            refX="5" refY="5" orient="auto" markerUnits="strokeWidth">
+                            <path d="M 5,1 L 9,5 5,9 1,5 z" fill="#69a6db" />
+                        </marker>
+                        <marker id="markerSquare" markerWidth="7" markerHeight="7" refX="4" refY="4"
+                            orient="auto" overflow="visible">
+                            <rect x="1" y="1" width="5" height="5" fill="#69a6db" />
+                        </marker>
+
+                        <marker id="markerArrow" markerWidth="5" markerHeight="5" refX="2" refY="7"
+                            orient="auto" overflow="visible">
+                            <path d="M2,2 L2,13 L8,7 L2,2" fill="#69a6db" />
+                        </marker>
+                    </defs>;
                     {PresBox.Instance.paths}
-                    </svg></>}
-            </>
-        );
+                </svg></>}
+        </>);
     }
 
     render() {
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 11fecc0c2..eba1046b2 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -23,8 +23,8 @@ import { Networking } from "../../Network";
 import { LinkAnchorBox } from "./LinkAnchorBox";
 import { List } from "../../../fields/List";
 import { Scripting } from "../../util/Scripting";
-import Waveform from "react-audio-waveform"
-import axios from "axios"
+import Waveform from "react-audio-waveform";
+import axios from "axios";
 const _global = (window /* browser */ || global /* node */) as any;
 
 declare class MediaRecorder {
@@ -375,7 +375,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     @action
     end(marker: number) {
         this._hold = false;
-        let newMarker = Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false, useLinkSmallAnchor: true, hideLinkButton: true, audioStart: this._start, audioEnd: marker, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document });
+        const newMarker = Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false, useLinkSmallAnchor: true, hideLinkButton: true, audioStart: this._start, audioEnd: marker, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document });
         newMarker.data = "";
         if (this.dataDoc[this.annotationKey]) {
             this.dataDoc[this.annotationKey].push(newMarker);
@@ -429,7 +429,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
 
         const rect = await (e.target as any).getBoundingClientRect();
 
-        let newTime = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
+        const newTime = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
 
         this.changeMarker(this._currMarker, newTime);
     }
@@ -437,11 +437,11 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     // updates the marker with the new time
     @action
     changeMarker = (m: any, time: any) => {
-        for (let i = 0; i < this.dataDoc[this.annotationKey].length; i++) {
-            if (this.isSame(this.dataDoc[this.annotationKey][i], m)) {
-                this._left ? this.dataDoc[this.annotationKey][i].audioStart = time : this.dataDoc[this.annotationKey][i].audioEnd = time;
+        DocListCast(this.dataDoc[this.annotationKey]).forEach((marker: Doc) => {
+            if (this.isSame(marker, m)) {
+                this._left ? marker.audioStart = time : marker.audioEnd = time;
             }
-        }
+        });
     }
 
     // checks if the two markers are the same with start and end time
@@ -457,7 +457,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         const increment = NumCast(this.layoutDoc.duration) / 500;
         this._count = [];
         for (let i = 0; i < 500; i++) {
-            this._count.push([increment * i, 0])
+            this._count.push([increment * i, 0]);
         }
 
     }
@@ -468,7 +468,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
             this._first = false;
             this.markers();
         }
-        let max = 0
+        let max = 0;
 
         for (let i = 0; i < 500; i++) {
             if (this._count[i][0] >= m.audioStart && this._count[i][0] <= m.audioEnd) {
@@ -490,7 +490,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         if (this.dataDoc.markerAmount < max) {
             this.dataDoc.markerAmount = max;
         }
-        return max - 1
+        return max - 1;
     }
 
     // returns the audio waveform
@@ -509,27 +509,27 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     // decodes the audio file into peaks for generating the waveform
     @action
     buckets = async () => {
-        let audioCtx = new (window.AudioContext)();
+        const audioCtx = new (window.AudioContext)();
 
         axios({ url: this.path, responseType: "arraybuffer" })
             .then(response => {
-                let audioData = response.data;
+                const audioData = response.data;
 
                 audioCtx.decodeAudioData(audioData, action(buffer => {
-                    let decodedAudioData = buffer.getChannelData(0);
+                    const decodedAudioData = buffer.getChannelData(0);
                     const NUMBER_OF_BUCKETS = 100;
-                    let bucketDataSize = Math.floor(decodedAudioData.length / NUMBER_OF_BUCKETS);
+                    const bucketDataSize = Math.floor(decodedAudioData.length / NUMBER_OF_BUCKETS);
 
                     for (let i = 0; i < NUMBER_OF_BUCKETS; i++) {
-                        let startingPoint = i * bucketDataSize;
-                        let endingPoint = i * bucketDataSize + bucketDataSize;
+                        const startingPoint = i * bucketDataSize;
+                        const endingPoint = i * bucketDataSize + bucketDataSize;
                         let max = 0;
                         for (let j = startingPoint; j < endingPoint; j++) {
                             if (decodedAudioData[j] > max) {
                                 max = decodedAudioData[j];
                             }
                         }
-                        let size = Math.abs(max);
+                        const size = Math.abs(max);
                         this._buckets.push(size / 2);
                     }
 
@@ -560,36 +560,36 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     update = (width: number, height: number) => {
         if (height) {
             this._height = 0.8 * NumCast(this.layoutDoc._height);
-            let canvas2 = document.getElementsByTagName("canvas")[0];
+            const canvas2 = document.getElementsByTagName("canvas")[0];
             if (canvas2) {
-                let oldWidth = canvas2.width;
-                let oldHeight = canvas2.height;
+                const oldWidth = canvas2.width;
+                const oldHeight = canvas2.height;
                 canvas2.style.height = `${this._height}`;
                 canvas2.style.width = `${width}`;
 
-                let ratio1 = oldWidth / window.innerWidth;
-                let ratio2 = oldHeight / window.innerHeight;
-                let context = canvas2.getContext('2d');
+                const ratio1 = oldWidth / window.innerWidth;
+                const ratio2 = oldHeight / window.innerHeight;
+                const context = canvas2.getContext('2d');
                 if (context) {
-                    context.scale(ratio1, ratio2)
+                    context.scale(ratio1, ratio2);
                 }
             }
 
-            let canvas1 = document.getElementsByTagName("canvas")[1];
+            const canvas1 = document.getElementsByTagName("canvas")[1];
             if (canvas1) {
-                let oldWidth = canvas1.width;
-                let oldHeight = canvas1.height;
+                const oldWidth = canvas1.width;
+                const oldHeight = canvas1.height;
                 canvas1.style.height = `${this._height}`;
                 canvas1.style.width = `${width}`;
 
-                let ratio1 = oldWidth / window.innerWidth;
-                let ratio2 = oldHeight / window.innerHeight;
-                let context = canvas1.getContext('2d');
+                const ratio1 = oldWidth / window.innerWidth;
+                const ratio2 = oldHeight / window.innerHeight;
+                const context = canvas1.getContext('2d');
                 if (context) {
-                    context.scale(ratio1, ratio2)
+                    context.scale(ratio1, ratio2);
                 }
 
-                let parent = canvas1.parentElement;
+                const parent = canvas1.parentElement;
                 if (parent) {
                     parent.style.width = `${width}`;
                     parent.style.height = `${this._height}`;
@@ -665,7 +665,14 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                 (!m.isLabel) ?
                                     (this.layoutDoc.hideMarkers) ? (null) :
                                         rect =
-                                        <div className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container1"} title={`${formatTime(Math.round(NumCast(m.audioStart)))}` + " - " + `${formatTime(Math.round(NumCast(m.audioEnd)))}`} key={i} id={"audiobox-marker-container1"} style={{ left: `${NumCast(m.audioStart) / NumCast(this.dataDoc.duration, 1) * 100}%`, width: `${(NumCast(m.audioEnd) - NumCast(m.audioStart)) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: `${1 / (this.dataDoc.markerAmount + 1) * 100}%`, top: `${this.isOverlap(m) * 1 / (this.dataDoc.markerAmount + 1) * 100}%` }} onClick={e => { this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)); e.stopPropagation() }} >
+                                        <div key={i} id={"audiobox-marker-container1"} className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container1"}
+                                            title={`${formatTime(Math.round(NumCast(m.audioStart)))}` + " - " + `${formatTime(Math.round(NumCast(m.audioEnd)))}`}
+                                            style={{
+                                                left: `${NumCast(m.audioStart) / NumCast(this.dataDoc.duration, 1) * 100}%`,
+                                                width: `${(NumCast(m.audioEnd) - NumCast(m.audioStart)) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: `${1 / (this.dataDoc.markerAmount + 1) * 100}%`,
+                                                top: `${this.isOverlap(m) * 1 / (this.dataDoc.markerAmount + 1) * 100}%`
+                                            }}
+                                            onClick={e => { this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)); e.stopPropagation(); }} >
                                             <div className="left-resizer" onPointerDown={e => this.onPointerDown(e, m, true)}></div>
                                             <DocumentView {...this.props}
                                                 Document={m}
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 230137584..502fd51f3 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -137,7 +137,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             this.gotoDocument(nextSelected, this.itemIndex);
             const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
             if (activeNext && targetNext.type === DocumentType.AUDIO && activeNext.playAuto) {
-            } else { this._moveOnFromAudio = false };
+            } else this._moveOnFromAudio = false;
         }
     }
 
@@ -1646,7 +1646,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 </select>
                 <div className="presBox-presentPanel" style={{ opacity: this.childDocs.length > 0 ? 1 : 0.3 }}>
                     <span className={`presBox-button ${this.layoutDoc.presStatus === "edit" ? "present" : ""}`}>
-                        <div className="presBox-button-left" onClick={() => { if (this.childDocs.length > 0) this.layoutDoc.presStatus = "manual" }}>
+                        <div className="presBox-button-left" onClick={() => (this.childDocs.length > 0) && (this.layoutDoc.presStatus = "manual")}>
                             <FontAwesomeIcon icon={"play-circle"} />
                             <div style={{ display: this.props.PanelWidth() > 200 ? "inline-flex" : "none" }}>&nbsp; Present</div>
                         </div>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 4b06f2800..b0bf54be6 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -305,7 +305,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
 
     // for inserting timestamps 
     insertTime = () => {
-        let linkTime;
         if (this._first) {
             this._first = false;
             DocListCast(this.dataDoc.links).map((l, i) => {
@@ -318,7 +317,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     this._linkTime = NumCast(l.anchor1_timecode);
                 }
 
-            })
+            });
         }
         this._currentTime = Date.now();
         let time;
-- 
cgit v1.2.3-70-g09d2

