From 3f5fb2e5dc258312e10698f3223239815959d7b6 Mon Sep 17 00:00:00 2001
From: Geireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>
Date: Sun, 18 Oct 2020 00:56:01 +0800
Subject: test commit of changes that might clash with merge

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

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

diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index d9924c299..faa341ed9 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -421,7 +421,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         const presPinWithViewIcon = <img src={`/assets/pinWithView.png`} style={{ margin: "auto", width: 19 }} />;
         const targetDoc = this.selectedDoc;
         {/* return (!targetDoc || (targetDoc._viewType !== CollectionViewType.Freeform && targetDoc.type !== DocumentType.IMG)) ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top"> */ }
-        return (targetDoc && (targetDoc._viewType === CollectionViewType.Freeform || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF)) ? <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top">
+        return (targetDoc && (targetDoc._viewType === CollectionViewType.Freeform || targetDoc._viewType === CollectionViewType.Stacking || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF)) ? <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top">
             <button className="antimodeMenu-button" style={{ borderRight: "1px solid gray", borderLeft: "1px solid gray", justifyContent: 'center' }}
                 onClick={() => this.pinWithView(targetDoc)}>
                 {presPinWithViewIcon}
-- 
cgit v1.2.3-70-g09d2


From 0721e65bc4403b96a8f905c93b51c6eda2371e4a Mon Sep 17 00:00:00 2001
From: Geireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>
Date: Sun, 18 Oct 2020 03:03:52 +0800
Subject: Comparison box pin with view

---
 src/client/views/collections/CollectionMenu.tsx      | 10 +++++++---
 src/client/views/nodes/ComparisonBox.scss            |  2 ++
 src/client/views/nodes/PresBox.tsx                   |  2 ++
 src/client/views/presentationview/PresElementBox.tsx | 13 +++++++++++--
 4 files changed, 22 insertions(+), 5 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 63a55e168..d08b31340 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -400,11 +400,11 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         if (targetDoc) {
             TabDocView.PinDoc(targetDoc, false);
             const activeDoc = PresBox.Instance.childDocs[PresBox.Instance.childDocs.length - 1];
-            if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB) {
+            if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) {
                 const scroll = targetDoc._scrollTop;
                 activeDoc.presPinView = true;
                 activeDoc.presPinViewScroll = scroll;
-            } else {
+            } else if ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG) {
                 const x = targetDoc._panX;
                 const y = targetDoc._panY;
                 const scale = targetDoc._viewScale;
@@ -412,6 +412,10 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
                 activeDoc.presPinViewX = x;
                 activeDoc.presPinViewY = y;
                 activeDoc.presPinViewScale = scale;
+            } else if (targetDoc.type === DocumentType.COMPARISON) {
+                const width = targetDoc._clipWidth;
+                activeDoc.presPinClipWidth = width;
+                activeDoc.presPinView = true;
             }
         }
     }
@@ -421,7 +425,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         const presPinWithViewIcon = <img src={`/assets/pinWithView.png`} style={{ margin: "auto", width: 19 }} />;
         const targetDoc = this.selectedDoc;
         {/* return (!targetDoc || (targetDoc._viewType !== CollectionViewType.Freeform && targetDoc.type !== DocumentType.IMG)) ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top"> */ }
-        return (targetDoc && (targetDoc._viewType === CollectionViewType.Freeform || targetDoc._viewType === CollectionViewType.Stacking || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF)) ? <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top">
+        return (targetDoc && (targetDoc._viewType === CollectionViewType.Freeform || targetDoc._viewType === CollectionViewType.Stacking || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.COMPARISON)) ? <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top">
             <button className="antimodeMenu-button" style={{ borderRight: "1px solid gray", borderLeft: "1px solid gray", justifyContent: 'center' }}
                 onClick={() => this.pinWithView(targetDoc)}>
                 {presPinWithViewIcon}
diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss
index acf6b1636..44cf5d046 100644
--- a/src/client/views/nodes/ComparisonBox.scss
+++ b/src/client/views/nodes/ComparisonBox.scss
@@ -13,6 +13,7 @@
         left: 0;
         height: 100%;
         overflow: hidden;
+        transition: 200ms;
 
         .beforeBox-cont {
             height: 100%;
@@ -26,6 +27,7 @@
         width: 3px;
         display: inline-block;
         background: white;
+        transition: 200ms;
 
         .slide-handle {
             position: absolute;
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 43a3b2db4..3b7794815 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -317,6 +317,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             bestTarget && runInAction(() => {
                 if (bestTarget.type === DocumentType.PDF || bestTarget.type === DocumentType.WEB || bestTarget.type === DocumentType.RTF || bestTarget._viewType === CollectionViewType.Stacking) {
                     bestTarget._scrollY = activeItem.presPinViewScroll;
+                } else if (bestTarget.type === DocumentType.COMPARISON) {
+                    bestTarget._clipWidth = activeItem.presPinClipWidth;
                 } else {
                     bestTarget._viewTransition = activeItem.presTransition ? `transform ${activeItem.presTransition}ms` : 'all 0.5s';
                     bestTarget._panX = activeItem.presPinViewX;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 3c2761a2e..aea00f812 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -245,13 +245,22 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
         PresBox.Instance._dragArray.push(this._dragRef.current!);
     }
 
+    /**
+     * Method called for updating the view of the currently selected document
+     * 
+     * @param targetDoc 
+     * @param activeItem 
+     */
     @undoBatch
     @action
-    pinWithView = (targetDoc: Doc, activeItem: Doc) => {
+    updateView = (targetDoc: Doc, activeItem: Doc) => {
         console.log(targetDoc.type);
         if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
             const scroll = targetDoc._scrollTop;
             activeItem.presPinViewScroll = scroll;
+        } else if (targetDoc.type === DocumentType.COMPARISON) {
+            const clipWidth = targetDoc._clipWidth;
+            activeItem.presPinClipWidth = clipWidth;
         } else {
             const x = targetDoc._panX;
             const y = targetDoc._panY;
@@ -319,7 +328,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                     <div className={"presItem-slideButtons"}>
                         <Tooltip title={<><div className="dash-tooltip">{"Update view"}</div></>}>
                             <div className="slideButton"
-                                onClick={() => this.pinWithView(targetDoc, activeItem)}
+                                onClick={() => this.updateView(targetDoc, activeItem)}
                                 style={{ fontWeight: 700, display: activeItem.presPinView ? "flex" : "none" }}>V</div>
                         </Tooltip>
                         <Tooltip title={<><div className="dash-tooltip">{this.rootDoc.presExpandInlineButton ? "Minimize" : "Expand"}</div></>}><div className={"slideButton"} onClick={e => { e.stopPropagation(); this.presExpandDocumentClick(); }}>
-- 
cgit v1.2.3-70-g09d2


From 37fc6beb4662be195b8aa551cc1042b04f2c24a8 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 17 Oct 2020 22:01:53 -0400
Subject: fixed rubberbadning ink shapes not to get cutoff. fixed animating
 annotations.   fixed ink masks. fixed warnings.

---
 src/client/views/InkingStroke.tsx                            |  4 +---
 src/client/views/collections/CollectionMenu.tsx              |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx            |  6 ++++--
 src/client/views/nodes/PresBox.tsx                           | 12 ++++++------
 src/client/views/pdf/PDFViewer.tsx                           |  6 +++++-
 src/server/websocket.ts                                      |  4 ++--
 6 files changed, 19 insertions(+), 15 deletions(-)

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

diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 186406424..7e424d8f0 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -38,7 +38,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
         this.props.Document._backgroundColor = "rgba(0,0,0,0.7)";
         this.props.Document.mixBlendMode = "hard-light";
         this.props.Document.color = "#9b9b9bff";
-        this.props.Document._stayInCollection = true;
+        //this.props.Document._stayInCollection = true;
         this.props.Document.isInkMask = true;
     }
 
@@ -190,8 +190,6 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
 
         return (
             <svg className="inkingStroke"
-                width={Math.max(width, height)}
-                height={Math.max(width, height)}
                 style={{
                     pointerEvents: this.props.Document.isInkMask ? "all" : "none",
                     transform: this.props.Document.isInkMask ? `translate(${InkingStroke.MaskDim / 2}px, ${InkingStroke.MaskDim / 2}px)` : undefined,
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index d08b31340..a4f5118d6 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -533,7 +533,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     }
     get document() { return this.props.docView.props.Document; }
     @computed get dataField() {
-        return this.document[this.props.docView.LayoutFieldKey];
+        return this.document[this.props.docView.LayoutFieldKey + (this.props.isOverlay ? "-annotations" : "")];
     }
     @computed get childDocs() {
         return DocListCast(this.dataField);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index c863addd2..56624f42d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -202,13 +202,15 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
     @action
     internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData, xp: number, yp: number) {
         if (!super.onInternalDrop(e, de)) return false;
+        const refDoc = docDragData.droppedDocuments[0];
         const [xpo, ypo] = this.getTransformOverlay().transformPoint(de.x, de.y);
-        const z = NumCast(docDragData.droppedDocuments[0].z);
+        const z = NumCast(refDoc.z);
         const x = (z ? xpo : xp) - docDragData.offset[0];
         const y = (z ? ypo : yp) - docDragData.offset[1];
         const zsorted = this.childLayoutPairs.map(pair => pair.layout).slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex));
         zsorted.forEach((doc, index) => doc.zIndex = doc.isInkMask ? 5000 : index + 1);
-        const dropPos = [NumCast(docDragData.droppedDocuments[0].x), NumCast(docDragData.droppedDocuments[0].y)];
+        const dvals = CollectionFreeFormDocumentView.getValues(refDoc, NumCast(refDoc.activeFrame, 1000));
+        const dropPos = this.Document._currentFrame !== undefined ? [dvals.x, dvals.y] : [NumCast(refDoc.x), NumCast(refDoc.y)];
         for (let i = 0; i < docDragData.droppedDocuments.length; i++) {
             const d = docDragData.droppedDocuments[i];
             const layoutDoc = Doc.Layout(d);
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 3b7794815..01a7bed8c 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -288,7 +288,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const willZoom = false;
         const openInTab = () => {
             collectionDocView ? collectionDocView.props.addDocTab(activeItem, "replace") : this.props.addDocTab(activeItem, "replace:left");
-        }
+        };
         // If openDocument is selected then it should open the document for the user
         if (activeItem.openDocument) {
             openInTab();
@@ -299,10 +299,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             } else if (docToJump === curDoc) {
                 //checking if curDoc has navigation open
                 if (curDoc.presMovement === PresMovement.Pan && targetDoc) {
-                    await DocumentManager.Instance.jumpToDocument(targetDoc, false, () => { openInTab() }, srcContext); // documents open in new tab instead of on right
+                    await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext); // documents open in new tab instead of on right
                 } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) {
                     //awaiting jump so that new scale can be found, since jumping is async
-                    await DocumentManager.Instance.jumpToDocument(targetDoc, true, () => { openInTab() }, srcContext); // documents open in new tab instead of on right
+                    await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext); // documents open in new tab instead of on right
                 }
             } else {
                 //awaiting jump so that new scale can be found, since jumping is async
@@ -442,7 +442,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 }
             }
         };
-        this.layoutDoc.presStatus = PresStatus.Auto;
+        this.layoutDoc.presStatus = PresStatus.Autoplay;
         this.startPresentation(startSlide);
         this.gotoDocument(startSlide, this.itemIndex);
         load();
@@ -450,7 +450,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
 
     @action
     pauseAutoPres = () => {
-        if (this.layoutDoc.presStatus === PresStatus.Auto) {
+        if (this.layoutDoc.presStatus === PresStatus.Autoplay) {
             if (this._presTimer) clearTimeout(this._presTimer);
             this.layoutDoc.presStatus = PresStatus.Manual;
             this.layoutDoc.presLoop = false;
@@ -611,7 +611,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         return true;
     }
     childLayoutTemplate = () => this.rootDoc._viewType !== CollectionViewType.Stacking ? undefined : this.presElement;
-    removeDocument = (doc: Doc) => { return Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc); };
+    removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc);
     getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight
     panelHeight = () => this.props.PanelHeight() - 40;
     active = (outsideReaction?: boolean) => ((Doc.GetSelectedTool() === InkTool.None && !this.layoutDoc._isBackground) &&
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index d278612b1..76b218972 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -730,7 +730,11 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
     panelHeight = () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document);
     @computed get overlayLayer() {
         return <div className={`pdfViewerDash-overlay${Doc.GetSelectedTool() !== InkTool.None || SnappingManager.GetIsDragging() ? "-inking" : ""}`}
-            style={{ pointerEvents: SnappingManager.GetIsDragging() ? "all" : undefined, transform: `scale(${this._zoomed})` }}>
+            style={{
+                pointerEvents: SnappingManager.GetIsDragging() ? "all" : undefined,
+                mixBlendMode: this.allAnnotations.some(anno => anno.mixBlendMode) ? "hard-light" : undefined,
+                transform: `scale(${this._zoomed})`
+            }}>
             <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
                 LibraryPath={this.props.ContainingCollectionView?.props.LibraryPath ?? emptyPath}
                 annotationsKey={this.annotationKey}
diff --git a/src/server/websocket.ts b/src/server/websocket.ts
index 490760441..6ceb9e29f 100644
--- a/src/server/websocket.ts
+++ b/src/server/websocket.ts
@@ -278,8 +278,8 @@ export namespace WebSocket {
         diff.diff.$set = diff.diff.$addToSet; delete diff.diff.$addToSet;// convert add to set to a query of the current fields, and then a set of the composition of the new fields with the old ones
         const updatefield = Array.from(Object.keys(diff.diff.$set))[0];
         const newListItems = diff.diff.$set[updatefield].fields;
-        const curList = (curListItems as any)?.fields?.[updatefield.replace("fields.", "")]?.fields || [];
-        diff.diff.$set[updatefield].fields = [...curList, ...newListItems.filter((newItem: any) => !curList.some((curItem: any) => curItem.fieldId ? curItem.fieldId === newItem.fieldId : curItem.heading ? curItem.heading === newItem.heading : curItem === newItem))];
+        const curList = (curListItems as any)?.fields?.[updatefield.replace("fields.", "")]?.fields.filter((item: any) => item !== undefined) || [];
+        diff.diff.$set[updatefield].fields = [...curList, ...newListItems.filter((newItem: any) => newItem && !curList.some((curItem: any) => curItem.fieldId ? curItem.fieldId === newItem.fieldId : curItem.heading ? curItem.heading === newItem.heading : curItem === newItem))];
         const sendBack = diff.diff.length !== diff.diff.$set[updatefield].fields.length;
         delete diff.diff.length;
         Database.Instance.update(diff.id, diff.diff,
-- 
cgit v1.2.3-70-g09d2


From d489ed1071b989ffee1b476d15d36fb2dfb5797a Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 18 Oct 2020 21:41:31 -0400
Subject: resets scrollTop when navigating to a new webpage in WebBox.  set url
 on proto's data field when creating a webPage, not delegate.

---
 src/client/views/collections/CollectionMenu.tsx    | 1 +
 src/client/views/collections/CollectionSubView.tsx | 3 +--
 2 files changed, 2 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index a4f5118d6..3f55cf103 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -761,6 +761,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
                         } else {
                             history.push(this._url);
                         }
+                        this.props.docView.props.Document._scrollTop = 0;
                         future && (future.length = 0);
                     }
                     this._url = url;
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index f3e563422..f0cf54db4 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -406,7 +406,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                     this.addDocument(alias);
                 } else {
                     console.log("Adding ...");
-                    const newDoc = Docs.Create.WebDocument(uriList, {
+                    const newDoc = Docs.Create.WebDocument(uriList.split("#annotations:")[0], {// clean hypothes.is URLs that reference a specific annotation (eg. https://en.wikipedia.org/wiki/Cartoon#annotations:t7qAeNbCEeqfG5972KR2Ig)
                         ...options,
                         _fitWidth: true,
                         title: uriList.split("#annotations:")[0],
@@ -416,7 +416,6 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                         useCors: true
                     });
                     console.log(" ... " + newDoc.title);
-                    newDoc.data = new WebField(uriList.split("#annotations:")[0]); // clean hypothes.is URLs that reference a specific annotation (eg. https://en.wikipedia.org/wiki/Cartoon#annotations:t7qAeNbCEeqfG5972KR2Ig)
                     console.log(" ... " + this.addDocument(newDoc) + " " + newDoc.title);
                 }
                 return;
-- 
cgit v1.2.3-70-g09d2


From e73cf54b9dfea74ff34d9d6227f209efdb1f23e4 Mon Sep 17 00:00:00 2001
From: Geireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>
Date: Wed, 21 Oct 2020 03:40:32 +0800
Subject: not possible to change pres document perspective

+ removing unessecary doc actions + progressivize
---
 src/client/views/PropertiesView.tsx                |  6 ++--
 src/client/views/collections/CollectionMenu.tsx    |  9 ++---
 .../collections/collectionFreeForm/MarqueeView.tsx |  2 +-
 src/client/views/nodes/PresBox.tsx                 | 40 +++++++++++++++-------
 .../views/presentationview/PresElementBox.scss     |  6 ++--
 5 files changed, 39 insertions(+), 24 deletions(-)

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

diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 39a4d293b..e93173c9e 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1010,7 +1010,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             {PresBox.Instance.transitionDropdown}
                         </div> : null}
                     </div>}
-                    {!selectedItem || type === DocumentType.VID || type === DocumentType.AUDIO ? (null) : <div className="propertiesView-presTrails">
+                    {/* {!selectedItem || type === DocumentType.VID || type === DocumentType.AUDIO ? (null) : <div className="propertiesView-presTrails">
                         <div className="propertiesView-presTrails-title"
                             onPointerDown={action(() => this.openPresProgressivize = !this.openPresProgressivize)}
                             style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}>
@@ -1022,8 +1022,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         {this.openPresProgressivize ? <div className="propertiesView-presTrails-content">
                             {PresBox.Instance.progressivizeDropdown}
                         </div> : null}
-                    </div>}
-                    {!selectedItem || (type !== DocumentType.COL && type !== DocumentType.VID && type !== DocumentType.AUDIO) ? (null) : <div className="propertiesView-presTrails">
+                    </div>} */}
+                    {!selectedItem || (type !== DocumentType.COL && type !== DocumentType.AUDIO) ? (null) : <div className="propertiesView-presTrails">
                         <div className="propertiesView-presTrails-title"
                             onPointerDown={action(() => { this.openSlideOptions = !this.openSlideOptions; })}
                             style={{ backgroundColor: this.openSlideOptions ? "black" : "" }}>
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 3f55cf103..34fb2bdee 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -344,7 +344,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
     @computed get viewModes() {
         const excludedViewTypes = Doc.UserDoc().noviceMode ? [CollectionViewType.Invalid, CollectionViewType.Docking, CollectionViewType.Pile, CollectionViewType.Map, CollectionViewType.Linear, CollectionViewType.Time] :
             [CollectionViewType.Invalid, CollectionViewType.Docking, CollectionViewType.Pile, CollectionViewType.Linear];
-        return <div className="collectionViewBaseChrome-viewModes" >
+        const isPres: boolean = (this.document && this.document.type === DocumentType.PRES);
+        return isPres ? (null) : (<div className="collectionViewBaseChrome-viewModes" >
             <Tooltip title={<div className="dash-tooltip">drop document to apply or drag to create button</div>} placement="bottom">
                 <div className="commandEntry-outerDiv" ref={this._viewRef} onPointerDown={this.dragViewDown}>
                     <button className={"antimodeMenu-button"}>
@@ -367,7 +368,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
                     </select>
                 </div>
             </Tooltip>
-        </div>;
+        </div>);
     }
 
     @computed get selectedDocumentView() {
@@ -425,7 +426,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         const presPinWithViewIcon = <img src={`/assets/pinWithView.png`} style={{ margin: "auto", width: 19 }} />;
         const targetDoc = this.selectedDoc;
         {/* return (!targetDoc || (targetDoc._viewType !== CollectionViewType.Freeform && targetDoc.type !== DocumentType.IMG)) ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top"> */ }
-        return (targetDoc && (targetDoc._viewType === CollectionViewType.Freeform || targetDoc._viewType === CollectionViewType.Stacking || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.COMPARISON)) ? <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top">
+        return (targetDoc && targetDoc.type !== DocumentType.PRES && (targetDoc._viewType === CollectionViewType.Freeform || targetDoc._viewType === CollectionViewType.Stacking || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.COMPARISON)) ? <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top">
             <button className="antimodeMenu-button" style={{ borderRight: "1px solid gray", borderLeft: "1px solid gray", justifyContent: 'center' }}
                 onClick={() => this.pinWithView(targetDoc)}>
                 {presPinWithViewIcon}
@@ -472,7 +473,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
     @computed
     get aliasButton() {
         const targetDoc = this.selectedDoc;
-        return !targetDoc ? (null) : <Tooltip title={<div className="dash-tooltip">{"Tap or Drag to create an alias"}</div>} placement="top">
+        return !targetDoc || targetDoc.type === DocumentType.PRES ? (null) : <Tooltip title={<div className="dash-tooltip">{"Tap or Drag to create an alias"}</div>} placement="top">
             <button className="antimodeMenu-button" onPointerDown={this.onAliasButtonDown} onClick={this.onAlias} style={{ cursor: "drag" }}>
                 <FontAwesomeIcon className="documentdecorations-icon" icon="copy" size="lg" />
             </button>
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index f95c21972..42a601aa2 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -397,7 +397,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             pinDoc.presentationTargetDoc = doc;
             pinDoc.presMovement = PresMovement.Zoom;
             pinDoc.context = curPres;
-            pinDoc.title = curPres.title;
+            pinDoc.title = doc.title;
             Doc.AddDocToList(curPres, "data", pinDoc);
             if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
             if (!DocumentManager.Instance.getDocumentView(curPres)) {
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 521a3796b..7bf3ec0d7 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -476,10 +476,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             this._pathBoolean = false;
             srcContext.presPathView = false;
         } else {
-            undoBatch(() => {
-                runInAction(() => this._pathBoolean = !this._pathBoolean);
-                srcContext.presPathView = this._pathBoolean;
-            })
+            runInAction(() => this._pathBoolean = !this._pathBoolean);
+            srcContext.presPathView = this._pathBoolean;
         }
     }
 
@@ -562,8 +560,26 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
      * When the movement dropdown is changes
      */
     @undoBatch
-    updateMovement = action((movement: any) => {
-        if (this._selectedArray) this._selectedArray.forEach((doc) => {
+    updateMovement = action((movement: any, all?: boolean) => {
+        if (all) {
+            this.childDocs.forEach((doc) => {
+                switch (movement) {
+                    case PresMovement.Zoom: //Pan and zoom
+                        doc.presMovement = PresMovement.Zoom;
+                        break;
+                    case PresMovement.Pan: //Pan
+                        doc.presMovement = PresMovement.Pan;
+                        break;
+                    case PresMovement.Jump: //Jump Cut
+                        doc.presJump = true;
+                        doc.presMovement = PresMovement.Jump;
+                        break;
+                    case PresMovement.None: default:
+                        doc.presMovement = PresMovement.None;
+                        break;
+                }
+            })
+        } else if (this._selectedArray) this._selectedArray.forEach((doc) => {
             switch (movement) {
                 case PresMovement.Zoom: //Pan and zoom
                     doc.presMovement = PresMovement.Zoom;
@@ -1008,6 +1024,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     applyTo = (array: Doc[]) => {
         const activeItem: Doc = this.activeItem;
         const targetDoc: Doc = this.targetDoc;
+        this.updateMovement(activeItem.presMovement, true);
         array.forEach((doc) => {
             const curDoc = Cast(doc, Doc, null);
             const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
@@ -1016,9 +1033,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 curDoc.presDuration = activeItem.presDuration;
                 tagDoc.presEffect = targetDoc.presEffect;
                 tagDoc.presEffectDirection = targetDoc.presEffectDirection;
-                tagDoc.presMovement = targetDoc.presMovement;
-                curDoc.presMovement = activeItem.presMovement;
-                this.updateMovement(activeItem.presMovement, curDoc, tagDoc);
                 curDoc.presHideTillShownButton = activeItem.presHideTillShownButton;
                 curDoc.presHideAfterButton = activeItem.presHideAfterButton;
             }
@@ -1033,12 +1047,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 <div>
                     <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
                         <div className="ribbon-box">
-                            <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.AUDIO ? "inline-flex" : "none" }}>
+                            <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.AUDIO ? "inline-flex" : "none" }}>
                                 <div className="ribbon-toggle" style={{ backgroundColor: activeItem.playAuto ? "#aedef8" : "" }} onClick={() => activeItem.playAuto = !activeItem.playAuto}>Play automatically</div>
                                 <div className="ribbon-toggle" style={{ display: "flex", backgroundColor: activeItem.playAuto ? "" : "#aedef8" }} onClick={() => activeItem.playAuto = !activeItem.playAuto}>Play on next</div>
                             </div>
-                            {targetDoc.type === DocumentType.VID ? <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presVidFullScreen ? "#aedef8" : "" }} onClick={() => activeItem.presVidFullScreen = !activeItem.presVidFullScreen}>Full screen</div> : (null)}
-                            {targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.AUDIO ? <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                            {/* {targetDoc.type === DocumentType.VID ? <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presVidFullScreen ? "#aedef8" : "" }} onClick={() => activeItem.presVidFullScreen = !activeItem.presVidFullScreen}>Full screen</div> : (null)} */}
+                            {targetDoc.type === DocumentType.AUDIO ? <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
                                 <div className="presBox-subheading">Start time</div>
                                 <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
                                     <input className="presBox-input"
@@ -1047,7 +1061,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                         onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presStartTime = Number(e.target.value); })} />
                                 </div>
                             </div> : (null)}
-                            {targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.AUDIO ? <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                            {targetDoc.type === DocumentType.AUDIO ? <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
                                 <div className="presBox-subheading">End time</div>
                                 <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
                                     <input className="presBox-input"
diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss
index 6152c56e9..86ab9efad 100644
--- a/src/client/views/presentationview/PresElementBox.scss
+++ b/src/client/views/presentationview/PresElementBox.scss
@@ -25,7 +25,7 @@ $slide-active: #5B9FDD;
     align-items: center;
 
     .presItem-number {
-        margin-top: 7px;
+        margin-top: 3.5px;
         font-size: 12px;
         font-weight: 700;
         text-align: center;
@@ -51,9 +51,9 @@ $slide-active: #5B9FDD;
     .presItem-name {
         min-width: 20px;
         z-index: 300;
-        top: 1px;
+        top: 2px;
         align-self: center;
-        font-size: 12px;
+        font-size: 11px;
         font-family: Roboto;
         font-weight: 500;
         position: relative;
-- 
cgit v1.2.3-70-g09d2


From ffd6c9eadd0097b3a27fac183d0b7c223301a7c4 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 22 Oct 2020 18:18:28 -0400
Subject: added pinwithView for videos

---
 src/client/views/DocumentButtonBar.tsx               | 2 ++
 src/client/views/collections/CollectionMenu.tsx      | 5 ++++-
 src/client/views/nodes/PresBox.tsx                   | 2 ++
 src/client/views/presentationview/PresElementBox.tsx | 2 ++
 4 files changed, 10 insertions(+), 1 deletion(-)

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

diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index ed248c473..3b22cf51c 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -205,6 +205,8 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                 const scroll = targetDoc._scrollTop;
                 activeDoc.presPinView = true;
                 activeDoc.presPinViewScroll = scroll;
+            } else if (targetDoc.type === DocumentType.VID) {
+                activeDoc.presPinTimecode = targetDoc._currentTimecode;
             } else if ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG) {
                 const x = targetDoc._panX;
                 const y = targetDoc._panY;
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 34fb2bdee..fed9be062 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -413,6 +413,9 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
                 activeDoc.presPinViewX = x;
                 activeDoc.presPinViewY = y;
                 activeDoc.presPinViewScale = scale;
+            } else if (targetDoc.type === DocumentType.VID) {
+                activeDoc.presPinTimecode = targetDoc._currentTimecode;
+                activeDoc.presPinView = true;
             } else if (targetDoc.type === DocumentType.COMPARISON) {
                 const width = targetDoc._clipWidth;
                 activeDoc.presPinClipWidth = width;
@@ -426,7 +429,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         const presPinWithViewIcon = <img src={`/assets/pinWithView.png`} style={{ margin: "auto", width: 19 }} />;
         const targetDoc = this.selectedDoc;
         {/* return (!targetDoc || (targetDoc._viewType !== CollectionViewType.Freeform && targetDoc.type !== DocumentType.IMG)) ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top"> */ }
-        return (targetDoc && targetDoc.type !== DocumentType.PRES && (targetDoc._viewType === CollectionViewType.Freeform || targetDoc._viewType === CollectionViewType.Stacking || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.COMPARISON)) ? <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top">
+        return (targetDoc && targetDoc.type !== DocumentType.PRES && (targetDoc._viewType === CollectionViewType.Freeform || targetDoc._viewType === CollectionViewType.Stacking || targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.VIDEO || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.COMPARISON)) ? <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top">
             <button className="antimodeMenu-button" style={{ borderRight: "1px solid gray", borderLeft: "1px solid gray", justifyContent: 'center' }}
                 onClick={() => this.pinWithView(targetDoc)}>
                 {presPinWithViewIcon}
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index d05674d69..4d0749635 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -337,6 +337,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                     bestTarget._scrollY = activeItem.presPinViewScroll;
                 } else if (bestTarget.type === DocumentType.COMPARISON) {
                     bestTarget._clipWidth = activeItem.presPinClipWidth;
+                } else if (bestTarget.type === DocumentType.VID) {
+                    bestTarget._currentTimecode = activeItem.presPinTimecode;
                 } else {
                     bestTarget._viewTransition = activeItem.presTransition ? `transform ${activeItem.presTransition}ms` : 'all 0.5s';
                     bestTarget._panX = activeItem.presPinViewX;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index ce97b65b7..b47e9c88a 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -252,6 +252,8 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
         if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
             const scroll = targetDoc._scrollTop;
             activeItem.presPinViewScroll = scroll;
+        } else if (targetDoc.type === DocumentType.VID) {
+            activeItem.presPinTimecode = targetDoc._currentTimecode;
         } else if (targetDoc.type === DocumentType.COMPARISON) {
             const clipWidth = targetDoc._clipWidth;
             activeItem.presPinClipWidth = clipWidth;
-- 
cgit v1.2.3-70-g09d2


From 749873972fba8ed8d5b34b73b43947d6356b882e Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 22 Oct 2020 22:23:39 -0400
Subject: added more caching for linkManager queries.

---
 src/client/util/CurrentUserUtils.ts                |   4 +-
 src/client/util/LinkManager.ts                     | 106 ++++++---------------
 src/client/views/collections/CollectionMenu.tsx    |   2 +-
 src/client/views/collections/CollectionSubView.tsx |   2 +-
 src/client/views/collections/TabDocView.tsx        |   2 +-
 5 files changed, 33 insertions(+), 83 deletions(-)

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

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 07447b93c..5886aa13f 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1125,7 +1125,7 @@ export class CurrentUserUtils {
                 DocListCastAsync(importDocs.data).then(async list => {
                     const results = await DocUtils.uploadFilesToDocs(Array.from(input.files || []), {});
                     if (results.length !== input.files?.length) {
-                        alert("Error uploading files - possibly due to unsupported file types")
+                        alert("Error uploading files - possibly due to unsupported file types");
                     }
                     list?.splice(0, 0, ...results);
                     disposer();
@@ -1212,7 +1212,5 @@ Scripting.addGlobal(function createNewPresentation() { return MainView.Instance.
     "creates a new presentation when called");
 Scripting.addGlobal(function links(doc: any) { return new List(LinkManager.Instance.getAllRelatedLinks(doc)); },
     "returns all the links to the document or its annotations", "(doc: any)");
-Scripting.addGlobal(function directLinks(doc: any) { return new List(LinkManager.Instance.getAllDirectLinks(doc)); },
-    "returns all the links directly to the document", "(doc: any)");
 Scripting.addGlobal(function importDocument() { return CurrentUserUtils.importDocument(); },
     "imports files from device directly into the import sidebar");
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 1ba6cff6d..c3ab7c6e7 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -25,94 +25,52 @@ export class LinkManager {
 
     public static currentLink: Opt<Doc>;
 
-    public static get Instance(): LinkManager {
-        return this._instance || (this._instance = new this());
-    }
-
-    private constructor() {
-    }
-
+    public static get Instance(): LinkManager { return this._instance || (this._instance = new this()); }
 
-    public getAllLinks(): Doc[] {
-        const lset = new Set<Doc>(DocListCast(Doc.LinkDBDoc().data));
-        SharingManager.Instance.users.forEach(user => {
-            DocListCast(user.linkDatabase?.data).map(doc => {
-                lset.add(doc);
-            });
-        });
-        return Array.from(lset);
-    }
+    public addLink(linkDoc: Doc) { return Doc.AddDocToList(Doc.LinkDBDoc(), "data", linkDoc); }
 
-    public addLink(linkDoc: Doc): boolean {
-        return Doc.AddDocToList(Doc.LinkDBDoc(), "data", linkDoc);
-    }
+    public deleteLink(linkDoc: Doc) { return Doc.RemoveDocFromList(Doc.LinkDBDoc(), "data", linkDoc); }
 
-    public deleteLink(linkDoc: Doc): boolean {
-        return Doc.RemoveDocFromList(Doc.LinkDBDoc(), "data", linkDoc);
-    }
+    public deleteAllLinksOnAnchor(anchor: Doc) { LinkManager.Instance.getAllRelatedLinks(anchor).forEach(linkDoc => LinkManager.Instance.deleteLink(linkDoc)); }
 
-    // finds all links that contain the given anchor
-    public getAllDirectLinks(anchor: Doc): Doc[] {
-        const related = LinkManager.Instance.getAllLinks().filter(link => link).filter(link => {
-            const a1 = Cast(link.anchor1, Doc, null);
-            const a2 = Cast(link.anchor2, Doc, null);
-            const protomatch1 = Doc.AreProtosEqual(anchor, a1);
-            const protomatch2 = Doc.AreProtosEqual(anchor, a2);
-            return ((a1?.author !== undefined && a2?.author !== undefined) || link.author === Doc.CurrentUserEmail) && (protomatch1 || protomatch2 || Doc.AreProtosEqual(link, anchor));
-        });
-        return related;
-    }
+    public getAllRelatedLinks(anchor: Doc) { return this.relatedLinker(anchor); } // finds all links that contain the given anchor
 
-    relatedLinker = computedFn(function realtedLinker(this: any, anchor: Doc) {
-        const related = LinkManager.Instance.getAllDirectLinks(anchor);
-        DocListCast(anchor[Doc.LayoutFieldKey(anchor) + "-annotations"]).map(anno => {
-            related.push(...LinkManager.Instance.getAllRelatedLinks(anno));
-        });
-        return related;
-    }.bind(this), true);
+    public getAllDirectLinks(anchor: Doc): Doc[] { return this.directLinker(anchor); }  // finds all links that contain the given anchor
 
-    // finds all links that contain the given anchor
-    public getAllRelatedLinks(anchor: Doc): Doc[] {
-        return this.relatedLinker(anchor);
-    }
+    public getAllLinks(): Doc[] { return this.allLinks(); }
 
-    public deleteAllLinksOnAnchor(anchor: Doc) {
-        const related = LinkManager.Instance.getAllRelatedLinks(anchor);
-        related.forEach(linkDoc => LinkManager.Instance.deleteLink(linkDoc));
-    }
+    allLinks = computedFn(function allLinks(this: any) {
+        const lset = new Set<Doc>(DocListCast(Doc.LinkDBDoc().data));
+        SharingManager.Instance.users.forEach(user => DocListCast(user.linkDatabase?.data).map(doc => lset.add(doc)));
+        return Array.from(lset);
+    }, true);
 
-    // gets the groups associates with an anchor in a link
-    public getAnchorGroups(linkDoc: Doc, anchor?: Doc): Array<Doc> {
-        if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, null))) {
-            return DocListCast(linkDoc.anchor1Groups);
-        } else {
-            return DocListCast(linkDoc.anchor2Groups);
-        }
-    }
-    public addGroupToAnchor(linkDoc: Doc, anchor: Doc, groupDoc: Doc, replace: boolean = false) {
-        Doc.GetProto(linkDoc).linkRelationship = groupDoc.linkRelationship;
-    }
+    directLinker = computedFn(function directLinker(this: any, anchor: Doc) {
+        return LinkManager.Instance.getAllLinks().filter(link => {
+            const a1 = Cast(link?.anchor1, Doc, null);
+            const a2 = Cast(link?.anchor2, Doc, null);
+            return link && ((a1?.author !== undefined && a2?.author !== undefined) || link.author === Doc.CurrentUserEmail) && (Doc.AreProtosEqual(anchor, a1) || Doc.AreProtosEqual(anchor, a2) || Doc.AreProtosEqual(link, anchor));
+        });
+    }, true);
 
-    // removes group doc of given group type only from given anchor on given link
-    public removeGroupFromAnchor(linkDoc: Doc, anchor: Doc, groupType: string) {
-        Doc.GetProto(linkDoc).linkRelationship = "-ungrouped-";
-    }
+    relatedLinker = computedFn(function relatedLinker(this: any, anchor: Doc) {
+        const related = LinkManager.Instance.directLinker(anchor);
+        DocListCast(anchor[Doc.LayoutFieldKey(anchor) + "-annotations"]).map(anno => related.push(...LinkManager.Instance.getAllRelatedLinks(anno)));
+        return related;
+    }, true);
 
     // returns map of group type to anchor's links in that group type
     public getRelatedGroupedLinks(anchor: Doc): Map<string, Array<Doc>> {
-        const related = this.getAllRelatedLinks(anchor);
         const anchorGroups = new Map<string, Array<Doc>>();
-        related.forEach(link => {
+        this.getAllRelatedLinks(anchor).forEach(link => {
             if (!link.linkRelationship || link?.linkRelationship !== "-ungrouped-") {
                 const group = anchorGroups.get(StrCast(link.linkRelationship));
                 anchorGroups.set(StrCast(link.linkRelationship), group ? [...group, link] : [link]);
-
             } else {
                 // if link is in no groups then put it in default group
                 const group = anchorGroups.get("*");
                 anchorGroups.set("*", group ? [...group, link] : [link]);
             }
-
         });
         return anchorGroups;
     }
@@ -120,21 +78,15 @@ export class LinkManager {
     // returns a list of all metadata docs associated with the given group type
     public getAllMetadataDocsInGroup(groupType: string): Array<Doc> {
         const md: Doc[] = [];
-        const allLinks = LinkManager.Instance.getAllLinks();
-        allLinks.forEach(linkDoc => {
-            if (StrCast(linkDoc.linkRelationship).toUpperCase() === groupType.toUpperCase()) { md.push(linkDoc); }
-        });
+        LinkManager.Instance.getAllLinks().forEach(linkDoc => StrCast(linkDoc.linkRelationship).toUpperCase() === groupType.toUpperCase() && md.push(linkDoc));
         return md;
     }
 
     // checks if a link with the given anchors exists
     public doesLinkExist(anchor1: Doc, anchor2: Doc): boolean {
-        const allLinks = LinkManager.Instance.getAllLinks();
-        const index = allLinks.findIndex(linkDoc => {
-            return (Doc.AreProtosEqual(Cast(linkDoc.anchor1, Doc, null), anchor1) && Doc.AreProtosEqual(Cast(linkDoc.anchor2, Doc, null), anchor2)) ||
-                (Doc.AreProtosEqual(Cast(linkDoc.anchor1, Doc, null), anchor2) && Doc.AreProtosEqual(Cast(linkDoc.anchor2, Doc, null), anchor1));
-        });
-        return index !== -1;
+        return -1 !== LinkManager.Instance.getAllLinks().findIndex(linkDoc =>
+            (Doc.AreProtosEqual(Cast(linkDoc.anchor1, Doc, null), anchor1) && Doc.AreProtosEqual(Cast(linkDoc.anchor2, Doc, null), anchor2)) ||
+            (Doc.AreProtosEqual(Cast(linkDoc.anchor1, Doc, null), anchor2) && Doc.AreProtosEqual(Cast(linkDoc.anchor2, Doc, null), anchor1)));
     }
 
     // finds the opposite anchor of a given anchor in a link
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index fed9be062..abad23e0d 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -429,7 +429,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         const presPinWithViewIcon = <img src={`/assets/pinWithView.png`} style={{ margin: "auto", width: 19 }} />;
         const targetDoc = this.selectedDoc;
         {/* return (!targetDoc || (targetDoc._viewType !== CollectionViewType.Freeform && targetDoc.type !== DocumentType.IMG)) ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top"> */ }
-        return (targetDoc && targetDoc.type !== DocumentType.PRES && (targetDoc._viewType === CollectionViewType.Freeform || targetDoc._viewType === CollectionViewType.Stacking || targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.VIDEO || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.COMPARISON)) ? <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top">
+        return (targetDoc && targetDoc.type !== DocumentType.PRES && (targetDoc._viewType === CollectionViewType.Freeform || targetDoc._viewType === CollectionViewType.Stacking || targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.COMPARISON)) ? <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top">
             <button className="antimodeMenu-button" style={{ borderRight: "1px solid gray", borderLeft: "1px solid gray", justifyContent: 'center' }}
                 onClick={() => this.pinWithView(targetDoc)}>
                 {presPinWithViewIcon}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 0dd033e47..f88ebd9ac 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -483,7 +483,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                 if (text && !text.includes("https://")) {
                     UndoManager.RunInBatch(() => this.addDocument(Docs.Create.TextDocument(text, { ...options, title: text.substring(0, 20), _width: 400, _height: 315 })), "drop");
                 } else {
-                    alert("Document updloaded failed - possibly an unsupported file type.")
+                    alert("Document updloaded failed - possibly an unsupported file type.");
                 }
             }
             disposer();
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index ff1e077ff..5bdf19a31 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -218,7 +218,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     }
     @computed get panelWidth() {
         return this.layoutDoc?.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), Doc.NativeWidth(this.layoutDoc)), this._panelWidth) :
-            (this.NativeAspect() && this.NativeAspect() < this._panelWidth / this._panelHeight ? this._panelHeight * this.NativeAspect() : this._panelWidth)
+            (this.NativeAspect() && this.NativeAspect() < this._panelWidth / this._panelHeight ? this._panelHeight * this.NativeAspect() : this._panelWidth);
     }
     @computed get _nativeWidth() { return !this.layoutDoc?._fitWidth ? Doc.NativeWidth(this.layoutDoc) || this._panelWidth : 0; }
     @computed get _nativeHeight() { return !this.layoutDoc?._fitWidth ? Doc.NativeHeight(this.layoutDoc) || this._panelHeight : 0; }
-- 
cgit v1.2.3-70-g09d2


From 7096b3a4c888816db9196f56a7bc01b89558d0ce Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 23 Oct 2020 15:04:25 -0400
Subject: improved selection/play/context menu behavior of youtube videos. 
 fixed youtube videos to pinwithview better by capturing timecode after a seek
 drag event so that you can pin with view.

---
 src/client/views/collections/CollectionMenu.tsx | 2 +-
 src/client/views/nodes/DocumentView.tsx         | 2 +-
 src/client/views/nodes/VideoBox.tsx             | 4 ++++
 3 files changed, 6 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index abad23e0d..34a1c0697 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -400,7 +400,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
     pinWithView = (targetDoc: Opt<Doc>) => {
         if (targetDoc) {
             TabDocView.PinDoc(targetDoc, false);
-            const activeDoc = PresBox.Instance.childDocs[PresBox.Instance.childDocs.length - 1];
+            const activeDoc = PresBox.Instance?.childDocs[PresBox.Instance?.childDocs.length - 1];
             if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) {
                 const scroll = targetDoc._scrollTop;
                 activeDoc.presPinView = true;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 08a4a7e23..96ae1dc2b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -889,7 +889,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 e?.stopPropagation(); // DocumentViews should stop propagation of this event
             }
             cm.displayMenu((e?.pageX || pageX || 0) - 15, (e?.pageY || pageY || 0) - 15);
-            !this.isSelected(true) && SelectionManager.SelectDoc(this, false);
+            !this.isSelected(true) && setTimeout(() => SelectionManager.SelectDoc(this, false), 300); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up.  by delaying the selection until hopefully after the pointer up, the context menu will appear.
         });
     }
 
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 30e8db645..250595db5 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -20,6 +20,7 @@ import "./VideoBox.scss";
 import { documentSchema } from "../../../fields/documentSchemas";
 import { Networking } from "../../Network";
 import { SnappingManager } from "../../util/SnappingManager";
+import { SelectionManager } from "../../util/SelectionManager";
 const path = require('path');
 
 export const timeSchema = createSchema({
@@ -75,6 +76,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
         update && this.player?.pause();
         update && this._youtubePlayer?.pauseVideo();
         this._youtubePlayer && this._playTimer && clearInterval(this._playTimer);
+        this._youtubePlayer?.seekTo(this._youtubePlayer?.getCurrentTime(), true);
+        this._youtubePlayer && SelectionManager.DeselectAll(); // if we don't deselect the player, then we get an annoying YouTube spinner I guess telling us we're paused.
         this._playTimer = undefined;
         this.updateTimecode();
     }
@@ -346,6 +349,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
         const style = "videoBox-content-YouTube" + (this._fullScreen ? "-fullScreen" : "");
         const start = untracked(() => Math.round((this.layoutDoc._currentTimecode || 0)));
         return <iframe key={this._youtubeIframeId} id={`${this.youtubeVideoId + this._youtubeIframeId}-player`}
+            onPointerLeave={this.updateTimecode}
             onLoad={this.youtubeIframeLoaded} className={`${style}`} width={Doc.NativeWidth(this.layoutDoc) || 640} height={Doc.NativeHeight(this.layoutDoc) || 390}
             src={`https://www.youtube.com/embed/${this.youtubeVideoId}?enablejsapi=1&rel=0&showinfo=1&autoplay=0&mute=1&start=${start}&modestbranding=1&controls=${VideoBox._showControls ? 1 : 0}`} />;
     }
-- 
cgit v1.2.3-70-g09d2


From ee1f52496d44baa8566b03a05eb24d67fe80a89a Mon Sep 17 00:00:00 2001
From: Geireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>
Date: Tue, 27 Oct 2020 12:43:00 +0800
Subject: Performance updates for up/down arrows

Only calls resetSelection when necessary
---
 src/client/util/DocumentManager.ts                 | 11 +---
 src/client/views/collections/CollectionMenu.tsx    |  5 +-
 src/client/views/collections/TabDocView.tsx        |  7 ++-
 .../collections/collectionFreeForm/MarqueeView.tsx |  7 ++-
 src/client/views/nodes/PresBox.tsx                 | 65 +++++++++-------------
 5 files changed, 45 insertions(+), 50 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 805e0e897..14aaeaec0 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -128,14 +128,9 @@ export class DocumentManager {
     }
 
 
-    static addView = (doc: Doc, finished?: () => void, presCollection?: Doc) => {
-        if (presCollection) {
-            const collectionDocView = DocumentManager.Instance.getDocumentView(presCollection);
-            if (collectionDocView) collectionDocView.props.addDocTab(doc, "replace");
-        } else {
-            CollectionDockingView.AddSplit(doc, "right");
-            finished?.();
-        }
+    static addView = (doc: Doc, finished?: () => void) => {
+        CollectionDockingView.AddSplit(doc, "right");
+        finished?.();
     }
     public jumpToDocument = async (
         targetDoc: Doc,        // document to display
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 34a1c0697..338b067fa 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -400,7 +400,10 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
     pinWithView = (targetDoc: Opt<Doc>) => {
         if (targetDoc) {
             TabDocView.PinDoc(targetDoc, false);
-            const activeDoc = PresBox.Instance?.childDocs[PresBox.Instance?.childDocs.length - 1];
+            const presArray: Doc[] = PresBox.Instance?.sortArray();
+            const size: number = PresBox.Instance?._selectedArray.size;
+            const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined;
+            const activeDoc = presSelected ? PresBox.Instance?.childDocs[PresBox.Instance?.childDocs.indexOf(presSelected) + 1] : PresBox.Instance?.childDocs[PresBox.Instance?.childDocs.length - 1];
             if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) {
                 const scroll = targetDoc._scrollTop;
                 activeDoc.presPinView = true;
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index dcd94a7e6..82530c26d 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -134,7 +134,10 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             pinDoc.title = doc.title + " - Slide";
             pinDoc.presMovement = PresMovement.Zoom;
             pinDoc.context = curPres;
-            Doc.AddDocToList(curPres, "data", pinDoc);
+            const presArray: Doc[] = PresBox.Instance?.sortArray();
+            const size: number = PresBox.Instance?._selectedArray.size;
+            const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined;
+            Doc.AddDocToList(curPres, "data", pinDoc, presSelected);
             if (pinDoc.type === "audio" && !audioRange) {
                 pinDoc.presStartTime = 0;
                 pinDoc.presEndTime = doc.duration;
@@ -149,6 +152,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 tabdocs?.push(curPres);  // bcz: Argh! this is annoying.  if multiple documents are pinned, this will get called multiple times before the presentation view is drawn.  Thus it won't be in the tabdocs list and it will get created multple times.  so need to explicilty add the presbox to the list of open tabs
                 CollectionDockingView.AddSplit(curPres, "right");
             }
+            PresBox.Instance?._selectedArray.clear();
+            pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Update selected array
             DocumentManager.Instance.jumpToDocument(doc, false, undefined);
             batch.end();
         }
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index c6d1c9da2..efbe85f1a 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -25,7 +25,7 @@ import "./MarqueeView.scss";
 import React = require("react");
 import { Id } from "../../../../fields/FieldSymbols";
 import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
-import { PresMovement } from "../../nodes/PresBox";
+import { PresBox, PresMovement } from "../../nodes/PresBox";
 
 interface MarqueeViewProps {
     getContainerTransform: () => Transform;
@@ -399,7 +399,10 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             pinDoc.presMovement = PresMovement.Zoom;
             pinDoc.context = curPres;
             pinDoc.title = doc.title + " - Slide";
-            Doc.AddDocToList(curPres, "data", pinDoc);
+            const presArray: Doc[] = PresBox.Instance?.sortArray();
+            const size: number = PresBox.Instance?._selectedArray.size;
+            const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined;
+            Doc.AddDocToList(curPres, "data", pinDoc, presSelected);
             if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
             if (!DocumentManager.Instance.getDocumentView(curPres)) {
                 CollectionDockingView.AddSplit(curPres, "right");
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 0dad502e1..914c5270d 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -155,9 +155,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         this.layoutDoc.presStatus = PresStatus.Edit;
         this.layoutDoc._gridGap = 0;
         this.layoutDoc._yMargin = 0;
-        document.removeEventListener("keydown", PresBox.keyEventsWrapper, true);
-        document.addEventListener("keydown", PresBox.keyEventsWrapper, true);
-        this._presKeyEventsActive = true;
         this.turnOffEdit(true);
         DocListCastAsync((Doc.UserDoc().myPresentations as Doc).data).then(pres =>
             !pres?.includes(this.rootDoc) && Doc.AddDocToList(Doc.UserDoc().myPresentations as Doc, "data", this.rootDoc));
@@ -172,6 +169,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         else Doc.UserDoc().activePresentation = this.rootDoc;
         document.removeEventListener("keydown", PresBox.keyEventsWrapper, true);
         document.addEventListener("keydown", PresBox.keyEventsWrapper, true);
+        this._presKeyEventsActive = true;
         PresBox.Instance = this;
     }
 
@@ -264,17 +262,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             this.rootDoc._itemIndex = index;
             const activeItem: Doc = this.activeItem;
             const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null);
-            if (activeItem.presPinView) {
-                const bestTarget = DocumentManager.Instance.getFirstDocumentView(presTargetDoc)?.props.Document;
-                bestTarget && runInAction(() => {
-                    if (activeItem.presMovement === PresMovement.Jump) {
-                        bestTarget._viewTransition = '0s';
-                    } else {
-                        bestTarget._viewTransition = activeItem.presTransition ? `transform ${activeItem.presTransition}ms` : 'all 1s';
-                        setTimeout(() => bestTarget._viewTransition = undefined, activeItem.presTransition ? NumCast(activeItem.presTransition) + 10 : 1010);
-                    }
-                });
-            } else if (presTargetDoc) {
+            if (presTargetDoc) {
                 presTargetDoc && runInAction(() => {
                     if (activeItem.presMovement === PresMovement.Jump) presTargetDoc.focusSpeed = 0;
                     else presTargetDoc.focusSpeed = activeItem.presTransition ? activeItem.presTransition : 500;
@@ -291,11 +279,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         }
     });
 
-
+    _navTimer!: NodeJS.Timeout;
     navigateToView = (targetDoc: Doc, activeItem: Doc) => {
+        clearTimeout(this._navTimer);
         const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document;
         bestTarget && runInAction(() => {
             if (bestTarget.type === DocumentType.PDF || bestTarget.type === DocumentType.WEB || bestTarget.type === DocumentType.RTF || bestTarget._viewType === CollectionViewType.Stacking) {
+                bestTarget._viewTransition = activeItem.presTransition ? `transform ${activeItem.presTransition}ms` : 'all 0.5s';
                 bestTarget._scrollY = activeItem.presPinViewScroll;
             } else if (bestTarget.type === DocumentType.COMPARISON) {
                 bestTarget._clipWidth = activeItem.presPinClipWidth;
@@ -307,8 +297,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 bestTarget._panY = activeItem.presPinViewY;
                 bestTarget._viewScale = activeItem.presPinViewScale;
             }
+            this._navTimer = setTimeout(() => bestTarget._viewTransition = undefined, activeItem.presTransition ? NumCast(activeItem.presTransition) + 10 : 510);
         });
-        setTimeout(() => targetDoc._viewTransition = undefined, 1010);
     }
 
     /**
@@ -325,14 +315,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const srcContext = await DocCastAsync(targetDoc?.context);
         const presCollection = Cast(this.layoutDoc.presCollection, Doc, null);
         const collectionDocView = presCollection ? DocumentManager.Instance.getDocumentView(presCollection) : undefined;
+        const includesDoc: boolean = DocListCast(presCollection?.data).includes(targetDoc);
         this.turnOffEdit();
-        if (this.itemIndex >= 0) {
-            if (srcContext && targetDoc) {
-                this.layoutDoc.presCollection = srcContext;
-            } else if (targetDoc) this.layoutDoc.presCollection = targetDoc;
-        }
-        const docToJump = curDoc;
-        const willZoom = false;
+        if (includesDoc) {
+            this.layoutDoc.presCollection = srcContext;
+        } else if (targetDoc) this.layoutDoc.presCollection = targetDoc;
         const presStatus = this.rootDoc.presStatus;
         const selViewCache = Array.from(this._selectedArray.keys());
         const dragViewCache = Array.from(this._dragArray);
@@ -356,19 +343,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         // If openDocument is selected then it should open the document for the user
         if (activeItem.openDocument) {
             openInTab();
-        } else {
-            if (docToJump === curDoc) {
-                //checking if curDoc has navigation open
-                if (curDoc.presMovement === PresMovement.Pan && targetDoc) {
-                    await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext); // documents open in new tab instead of on right
-                } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) {
-                    //awaiting jump so that new scale can be found, since jumping is async
-                    await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext, undefined, undefined, undefined, resetSelection); // documents open in new tab instead of on right
-                }
-            } else {
-                //awaiting jump so that new scale can be found, since jumping is async
-                targetDoc && await DocumentManager.Instance.jumpToDocument(targetDoc, willZoom, undefined, srcContext);
-            }
+        } else if (curDoc.presMovement === PresMovement.Pan && targetDoc) {
+            await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext, undefined, undefined, undefined, includesDoc ? undefined : resetSelection); // documents open in new tab instead of on right
+        } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) {
+            //awaiting jump so that new scale can be found, since jumping is async
+            await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext, undefined, undefined, undefined, includesDoc ? undefined : resetSelection); // documents open in new tab instead of on right
         }
         // After navigating to the document, if it is added as a presPinView then it will
         // adjust the pan and scale to that of the pinView when it was added.
@@ -688,10 +667,20 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             this._selectedArray.set(doc, undefined);
             this._eleArray.push(ref);
             this._dragArray.push(drag);
+        } else {
+            this._selectedArray.delete(doc);
+            this.removeFromArray(this._eleArray, doc);
+            this.removeFromArray(this._dragArray, doc);
         }
         this.selectPres();
     }
 
+    removeFromArray = (arr: any[], val: any) => {
+        const index: number = arr.indexOf(val);
+        const ret: any[] = arr.splice(index, 1);
+        arr = ret;
+    }
+
     //Shift click
     @action
     shiftSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => {
@@ -1614,12 +1603,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
 
     @action
     turnOffEdit = (paths?: boolean) => {
+        // Turn off paths
         if (paths) {
-            // Turn off paths
             const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
             if (srcContext) this.togglePath(srcContext, true);
         }
-        // Turn off the progressivize editors for each
+        // Turn off the progressivize editors for each document
         this.childDocs.forEach((doc) => {
             doc.editSnapZoomProgressivize = false;
             doc.editZoomProgressivize = false;
-- 
cgit v1.2.3-70-g09d2


From e65c32301dc99268a4f0746581ef70fef0077a0a Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 30 Oct 2020 13:02:34 -0400
Subject: fixed bookmarked views to not break when there's no current frame.
 (caused the bug with the large bookmark icon after having created and invoked
 a previous bookmark icon)

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

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

diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 338b067fa..b44b85183 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -1324,5 +1324,5 @@ Scripting.addGlobal(function gotoFrame(doc: any, newFrame: any) {
         CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
     }
     CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0);
-    doc._currentFrame = Math.max(0, newFrame);
+    doc._currentFrame = newFrame === undefined ? 0 : Math.max(0, newFrame);
 });
-- 
cgit v1.2.3-70-g09d2


From d000fe7a7f89cb7252c8a23e0f88a61775ba2933 Mon Sep 17 00:00:00 2001
From: Geireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>
Date: Sun, 1 Nov 2020 21:07:31 +0800
Subject: Remove any attempt at auto playing audio

---
 src/client/views/collections/CollectionMenu.tsx    |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 62 ++++++++++++++++------
 .../collectionFreeForm/MarqueeOptionsMenu.tsx      |  2 +-
 src/client/views/nodes/PresBox.tsx                 | 33 ++++++------
 4 files changed, 65 insertions(+), 34 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 338b067fa..38817a601 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -432,7 +432,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         const presPinWithViewIcon = <img src={`/assets/pinWithView.png`} style={{ margin: "auto", width: 19 }} />;
         const targetDoc = this.selectedDoc;
         {/* return (!targetDoc || (targetDoc._viewType !== CollectionViewType.Freeform && targetDoc.type !== DocumentType.IMG)) ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top"> */ }
-        return (targetDoc && targetDoc.type !== DocumentType.PRES && (targetDoc._viewType === CollectionViewType.Freeform || targetDoc._viewType === CollectionViewType.Stacking || targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.COMPARISON)) ? <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top">
+        return (targetDoc && targetDoc.type !== DocumentType.PRES && (targetDoc._viewType === CollectionViewType.Freeform || targetDoc._viewType === CollectionViewType.Stacking || targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.COMPARISON)) ? <Tooltip title={<><div className="dash-tooltip">{"Pin with current view"}</div></>} placement="top">
             <button className="antimodeMenu-button" style={{ borderRight: "1px solid gray", borderLeft: "1px solid gray", justifyContent: 'center' }}
                 onClick={() => this.pinWithView(targetDoc)}>
                 {presPinWithViewIcon}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index fdcfb00d8..6f8c13794 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1657,6 +1657,30 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
         </>;
     }
 
+    @computed get presPathsOutsideCollection() {
+        const presPaths = "presPaths" + (this.props.presPaths ? "" : "-hidden");
+        return !PresBox.Instance || !this.props.presPaths ? (null) : <>
+            <div key="presorder">{PresBox.Instance.order}</div>
+            <svg key="svg" className={presPaths}>
+                <defs>
+                    <marker id="markerSquare" markerWidth="3" markerHeight="3" refX="1.5" refY="1.5"
+                        orient="auto" overflow="visible">
+                        <rect x="0" y="0" width="3" height="3" stroke="#69a6db" strokeWidth="1" fill="white" fillOpacity="0.8" />
+                    </marker>
+                    <marker id="markerSquareFilled" markerWidth="3" markerHeight="3" refX="1.5" refY="1.5"
+                        orient="auto" overflow="visible">
+                        <rect x="0" y="0" width="3" height="3" stroke="#69a6db" strokeWidth="1" fill="#69a6db" />
+                    </marker>
+                    <marker id="markerArrow" markerWidth="3" markerHeight="3" refX="2" refY="4"
+                        orient="auto" overflow="visible">
+                        <path d="M2,2 L2,6 L6,4 L2,2 Z" stroke="#69a6db" strokeLinejoin="round" strokeWidth="1" fill="white" fillOpacity="0.8" />
+                    </marker>
+                </defs>
+                {PresBox.Instance.paths}
+            </svg>
+        </>;
+    }
+
     render() {
         // trace();
         const freeformclass = "collectionfreeformview" + (this.props.viewDefDivClick ? "-viewDef" : "-none");
@@ -1665,22 +1689,26 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
         const panx = -this.props.panX();
         const pany = -this.props.panY();
         const zoom = this.props.zoomScaling();
-        return <div className={freeformclass}
-            onScroll={e => {
-                const target = e.target as any;
-                if (getComputedStyle(target)?.overflow === "visible") {  // if collection is visible, then scrolling will mess things up since there are no scroll bars
-                    target.scrollTop = target.scrollLeft = 0;
-                }
-            }}
-            style={{
-                transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}) translate(${panx}px, ${pany}px)`,
-                transition: this.props.transition,
-                //willChange: "transform"
-            }}>
-            {this.props.children()}
-            {this.presPaths}
-            {this.progressivize}
-            {this.zoomProgressivize}
-        </div>;
+        return (
+            <>
+                <div className={freeformclass}
+                    onScroll={e => {
+                        const target = e.target as any;
+                        if (getComputedStyle(target)?.overflow === "visible") {  // if collection is visible, then scrolling will mess things up since there are no scroll bars
+                            target.scrollTop = target.scrollLeft = 0;
+                        }
+                    }}
+                    style={{
+                        transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}) translate(${panx}px, ${pany}px)`,
+                        transition: this.props.transition,
+                        //willChange: "transform"
+                    }}>
+                    {this.props.children()}
+                    {this.presPaths}
+                    {this.progressivize}
+                    {this.zoomProgressivize}
+                </div>
+                {/* <div>{this.presPathsOutsideCollection}</div> */}
+            </>);
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
index d8e44e781..cedeb1112 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
@@ -54,7 +54,7 @@ export class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> {
                     <FontAwesomeIcon icon="font" size="lg" />
                 </button>
             </Tooltip>,
-            <Tooltip key="pinWithView" title={<><div className="dash-tooltip">Pin the selected region to presentation</div></>} placement="bottom">
+            <Tooltip key="pinWithView" title={<><div className="dash-tooltip">Pin with selected region</div></>} placement="bottom">
                 <button
                     className="antimodeMenu-button"
                     onPointerDown={this.pinWithView}>
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index d7f15166f..c96fad28c 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -193,16 +193,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     // No more frames in current doc and next slide is defined, therefore move to next slide 
     nextSlide = (targetDoc: Doc, activeNext: Doc) => {
         const nextSelected = this.itemIndex + 1;
-        if (targetDoc.type === DocumentType.AUDIO) { if (AudioBox.Instance._ele) AudioBox.Instance.pause(); }
-        // if (targetDoc.type === DocumentType.VID) { if (AudioBox.Instance._ele) VideoBox.Instance.Pause(); }
-        const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
-        // If next slide is audio / video 'Play automatically' then the next slide should be played
-        if (activeNext && (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) && activeNext.playAuto) {
-            console.log('play next automatically');
-            if (targetNext.type === DocumentType.AUDIO) AudioBox.Instance.playFrom(NumCast(activeNext.presStartTime));
-            // if (targetNext.type === DocumentType.VID) { VideoBox.Instance.Play() };
-        } else if (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) { activeNext.playNow = true; console.log('play next after it is navigated to'); }
         this.gotoDocument(nextSelected);
+
+        // const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
+        // If next slide is audio / video 'Play automatically' then the next slide should be played
+        // if (activeNext && (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) && activeNext.playAuto) {
+        //     console.log('play next automatically');
+        //     if (targetNext.type === DocumentType.AUDIO) AudioBox.Instance.playFrom(NumCast(activeNext.presStartTime));
+        //     // if (targetNext.type === DocumentType.VID) { VideoBox.Instance.Play() };
+        // } else if (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) { activeNext.playNow = true; console.log('play next after it is navigated to'); }
     }
 
     // Called when the user activates 'next' - to move to the next part of the pres. trail
@@ -215,13 +214,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const curFrame = NumCast(targetDoc?._currentFrame);
         let internalFrames: boolean = false;
         if (activeItem.presProgressivize || activeItem.zoomProgressivize || targetDoc.scrollProgressivize) internalFrames = true;
-
         if (internalFrames && lastFrame !== undefined && curFrame < lastFrame) {
             // Case 1: There are still other frames and should go through all frames before going to next slide
             this.nextInternalFrame(targetDoc, activeItem);
-        } else if ((targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && !activeItem.playAuto && activeItem.playNow && this.layoutDoc.presStatus !== PresStatus.Autoplay) {
-            // Case 2: 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played
-            this.nextAudioVideo(targetDoc, activeItem);
         } 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 
             this.nextSlide(targetDoc, activeNext);
@@ -229,6 +224,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             // Case 4: Last slide and presLoop is toggled ON
             this.gotoDocument(0);
         }
+        // else if ((targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && !activeItem.playAuto && activeItem.playNow && this.layoutDoc.presStatus !== PresStatus.Autoplay) {
+        //     // Case 2: 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played
+        //     this.nextAudioVideo(targetDoc, activeItem);
+        // } 
     }
 
     // Called when the user activates 'back' - to move to the previous part of the pres. trail
@@ -240,14 +239,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const prevTargetDoc = Cast(prevItem.presentationTargetDoc, Doc, null);
         const lastFrame = Cast(targetDoc.lastFrame, "number", null);
         const curFrame = NumCast(targetDoc._currentFrame);
+        let prevSelected = this.itemIndex;
         if (lastFrame !== undefined && curFrame >= 1) {
             // Case 1: There are still other frames and should go through all frames before going to previous slide
             this.prevKeyframe(targetDoc, activeItem);
-        } else if (activeItem) {
-            let prevSelected = this.itemIndex;
+        } else if (activeItem && this.childDocs[this.itemIndex - 1] !== undefined) {
+            // Case 2: There are no other frames so it should go to the previous slide
             prevSelected = Math.max(0, prevSelected - 1);
             this.gotoDocument(prevSelected);
             if (NumCast(prevTargetDoc.lastFrame) > 0) prevTargetDoc._currentFrame = NumCast(prevTargetDoc.lastFrame);
+        } else if (this.childDocs[this.itemIndex - 1] === undefined && this.layoutDoc.presLoop) {
+            // Case 3: Pres loop is on so it should go to the last slide
+            this.gotoDocument(this.childDocs.length - 1);
         }
     }
 
-- 
cgit v1.2.3-70-g09d2


From ae55833bb1730c992530dc3f50010588787d386e Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 2 Nov 2020 20:19:25 -0500
Subject: fixed display of text controls for nested text boxes like captions.

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

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

diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 1dbafbd61..cf94a93d3 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -551,7 +551,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     }
     @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
     @computed get isText() {
-        return this.selectedDoc?.type === DocumentType.RTF || (RichTextMenu.Instance?.view as any)?.focused ? true : false;
+        return this.selectedDoc?.type === DocumentType.RTF || (RichTextMenu.Instance?.view as any) ? true : false;
     }
 
     @undoBatch
-- 
cgit v1.2.3-70-g09d2


From aba91357df33b49e9c09208a53b757ef8f8dc724 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 8 Nov 2020 21:35:16 -0500
Subject: added an optional background grid for collections.

---
 src/client/views/MainView.tsx                      |  4 +--
 src/client/views/collections/CollectionMenu.tsx    | 13 ++++++--
 .../collectionFreeForm/CollectionFreeFormView.scss |  7 ++++
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 37 +++++++++++++++++++++-
 src/client/views/nodes/PresBox.tsx                 |  4 +--
 5 files changed, 57 insertions(+), 8 deletions(-)

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

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 3a3dbc68f..452ce61ff 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -133,7 +133,7 @@ export class MainView extends React.Component {
         }
 
         library.add(fa.faEdit, fa.faTrash, fa.faTrashAlt, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faCalendar,
-            fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faMapMarker, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock,
+            fa.faSquare, far.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faMapMarker, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock,
             fa.faLock, fa.faLaptopCode, fa.faMale, fa.faCopy, fa.faHandPointLeft, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone, fa.faKeyboard,
             fa.faQuestion, fa.faTasks, fa.faPalette, fa.faAngleLeft, fa.faAngleRight, fa.faBell, fa.faCamera, fa.faExpand, fa.faCaretDown, fa.faCaretLeft, fa.faCaretRight,
             fa.faCaretSquareDown, fa.faCaretSquareRight, fa.faArrowsAltH, fa.faPlus, fa.faMinus, fa.faTerminal, fa.faToggleOn, fa.faFile, fa.faLocationArrow,
@@ -151,7 +151,7 @@ export class MainView extends React.Component {
             fa.faAngleDown, fa.faPlayCircle, fa.faClock, fa.faRocket, fa.faExchangeAlt, faBuffer, fa.faHashtag, fa.faAlignJustify, fa.faCheckSquare, fa.faListUl,
             fa.faWindowMinimize, fa.faWindowRestore, fa.faTextWidth, fa.faTextHeight, fa.faClosedCaptioning, fa.faInfoCircle, fa.faTag, fa.faSyncAlt, fa.faPhotoVideo,
             fa.faArrowAltCircleDown, fa.faArrowAltCircleUp, fa.faArrowAltCircleLeft, fa.faArrowAltCircleRight, fa.faStopCircle, fa.faCheckCircle, fa.faGripVertical,
-            fa.faSortUp, fa.faSortDown, fa.faTable, fa.faTh, fa.faThList, fa.faProjectDiagram, fa.faSignature, fa.faColumns, fa.faChevronCircleUp, fa.faUpload,
+            fa.faSortUp, fa.faSortDown, fa.faTable, fa.faTh, fa.faThList, fa.faProjectDiagram, fa.faSignature, fa.faColumns, fa.faChevronCircleUp, fa.faUpload, fa.faBorderAll,
             fa.faBraille, fa.faChalkboard, fa.faPencilAlt, fa.faEyeSlash, fa.faSmile, fa.faIndent, fa.faOutdent, fa.faChartBar, fa.faBan, fa.faPhoneSlash, fa.faGripLines);
         this.initAuthenticationRouters();
     }
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index cf94a93d3..b2b23115f 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -489,13 +489,19 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
     @computed get lightboxButton() {
         const targetDoc = this.selectedDoc;
         return !targetDoc ? (null) : <Tooltip title={<div className="dash-tooltip">{"Show Lightbox of Images"}</div>} placement="top">
-            <button className="antimodeMenu-button" onPointerDown={action(() => targetDoc._isLightboxOpen = true)} onClick={this.onAlias}>
+            <button className="antimodeMenu-button" onPointerDown={action(() => targetDoc._isLightboxOpen = true)}>
                 <FontAwesomeIcon className="documentdecorations-icon" icon="desktop" size="lg" />
             </button>
         </Tooltip>;
     }
-
-
+    @computed get gridbackgroundButton() {
+        const targetDoc = this.selectedDoc;
+        return !targetDoc ? (null) : <Tooltip title={<div className="dash-tooltip">{"Toggle background grid"}</div>} placement="top">
+            <button className="antimodeMenu-button" onPointerDown={action(() => targetDoc["_backgroundGrid-show"] = !targetDoc["_backgroundGrid-show"])}>
+                <FontAwesomeIcon className="documentdecorations-icon" icon={targetDoc["_backgroundGrid-show"] ? "border-all" : ["far", "square"]} size="lg" />
+            </button>
+        </Tooltip>;
+    }
 
     render() {
         return (
@@ -513,6 +519,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
                                 </button>
                             </Tooltip>}
                         {this.notACollection ? (null) : this.lightboxButton}
+                        {this.notACollection ? (null) : this.gridbackgroundButton}
                         {this.aliasButton}
                         {/* {this.pinButton} */}
                         {this.pinWithViewButton}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index e92100c50..a50b41198 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -12,6 +12,13 @@
     border-radius: inherit;
 }
 
+.collectionfreeformview-grid {
+    transform-origin: top left;
+    position: absolute;
+    top: 0;
+    left: 0;
+}
+
 .collectionfreeformview-viewdef {
     >.collectionFreeFormDocumentView-container {
         pointer-events: none;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 703776e72..8a4ce826f 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1434,6 +1434,38 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         }
         return false;
     });
+    @computed get grid() {
+        const gridSpace = NumCast(this.layoutDoc["_backgroundGrid-space"], 50);
+        const shiftX = this.props.isAnnotationOverlay ? 0 : -(this.panX()) % gridSpace - gridSpace;
+        const shiftY = this.props.isAnnotationOverlay ? 0 : -(this.panY()) % gridSpace - gridSpace;
+        const cx = this.centeringShiftX();
+        const cy = this.centeringShiftY();
+        const w = this.props.PanelWidth() / this.zoomScaling() + 3 * gridSpace;
+        const h = this.props.PanelHeight() / this.zoomScaling() + 3 * gridSpace;
+        return <canvas className="collectionFreeFormView-grid" width={w} height={h} style={{ transform: `scale(${this.zoomScaling()}) translate(${shiftX}px, ${shiftY}px)` }}
+            ref={(el) => {
+                const ctx = el?.getContext('2d');
+                if (ctx) {
+                    const Cx = (cx / this.zoomScaling()) % gridSpace - 0;
+                    const Cy = (cy / this.zoomScaling()) % gridSpace - 0;
+                    ctx.clearRect(0, 0, w, h);
+                    if (ctx) {
+                        ctx.strokeStyle = "rgba(0, 0, 0, 0.5)";
+                        ctx.lineWidth = Math.min(1, Math.max(0.5, 0.5 / this.zoomScaling()));
+                        ctx.beginPath();
+                        for (let x = Cx; x <= -Cx + w; x += gridSpace) {
+                            ctx.moveTo(x, Cy - h);
+                            ctx.lineTo(x, Cy + h);
+                        }
+                        for (let y = Cy; y <= -Cy + h; y += gridSpace) {
+                            ctx.moveTo(Cx - w, y);
+                            ctx.lineTo(Cx + w, y);
+                        }
+                        ctx.stroke();
+                    }
+                }
+            }} />;
+    }
     @computed get marqueeView() {
         return <MarqueeView
             {...this.props}
@@ -1447,6 +1479,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             getTransform={this.getTransform}
             isAnnotationOverlay={this.isAnnotationOverlay}>
             <div ref={this._marqueeRef}>
+                {this.layoutDoc["_backgroundGrid-show"] ? this.grid : (null)}
                 <CollectionFreeFormViewPannableContents
                     centeringShiftX={this.centeringShiftX}
                     centeringShiftY={this.centeringShiftY}
@@ -1463,6 +1496,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         </MarqueeView>;
     }
 
+
     @computed get contentScaling() {
         if (this.props.annotationsKey && !this.props.forceScaling) return 0;
         const nw = returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.Document));
@@ -1635,7 +1669,7 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
     }
 
     @computed get zoomProgressivize() {
-        return PresBox.Instance && PresBox.Instance.activeItem && PresBox.Instance.activeItem.presPinView && PresBox.Instance.layoutDoc.presStatus === 'edit' ? this.zoomProgressivizeContainer : (null);
+        return PresBox.Instance?.activeItem?.presPinView && PresBox.Instance.layoutDoc.presStatus === 'edit' ? this.zoomProgressivizeContainer : (null);
     }
 
     @computed get progressivize() {
@@ -1666,6 +1700,7 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
         </>;
     }
 
+
     render() {
         // trace();
         const freeformclass = "collectionfreeformview" + (this.props.viewDefDivClick ? "-viewDef" : "-none");
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 52e09a469..683cb938a 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -426,7 +426,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             if (tagDoc) tagDoc.opacity = 1;
             const itemIndexes: number[] = this.getAllIndexes(this.tagDocs, tagDoc);
             const curInd: number = itemIndexes.indexOf(index);
-            if (tagDoc === this.layoutDoc.presCollection) { tagDoc.opacity = 1 }
+            if (tagDoc === this.layoutDoc.presCollection) { tagDoc.opacity = 1; }
             else {
                 if (itemIndexes.length > 1 && curDoc.presHideBefore && curInd !== 0) { }
                 else if (curDoc.presHideBefore) {
@@ -1210,7 +1210,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const targetDoc: Doc = this.targetDoc;
         this.updateMovement(activeItem.presMovement, true);
         this.updateEffect(targetDoc.presEffect, true);
-        this.updateEffectDirection(targetDoc.presEffectDirection, true)
+        this.updateEffectDirection(targetDoc.presEffectDirection, true);
         array.forEach((doc) => {
             const curDoc = Cast(doc, Doc, null);
             const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
-- 
cgit v1.2.3-70-g09d2

