From 0ed7131587c6739483da64a93d9f2ab6fdfbc15a Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 25 Aug 2022 11:06:38 -0400
Subject: fixed crashes in notetaking view and cleaned up code a bit.  fixed
 undo of column deletion.

---
 .../views/collections/CollectionNoteTakingView.tsx | 103 ++++++++-------------
 1 file changed, 41 insertions(+), 62 deletions(-)

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

diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index b359ef420..5a6d899ef 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -11,7 +11,7 @@ import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Ty
 import { TraceMobx } from '../../../fields/util';
 import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, returnZero, smoothScroll, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
-import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
+import { DocumentType } from '../../documents/DocumentTypes';
 import { DragManager, dropActionType } from '../../util/DragManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
@@ -19,7 +19,6 @@ import { undoBatch } from '../../util/UndoManager';
 import { ContextMenu } from '../ContextMenu';
 import { ContextMenuProps } from '../ContextMenuItem';
 import { LightboxView } from '../LightboxView';
-import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView';
 import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from '../nodes/DocumentView';
 import { FieldViewProps } from '../nodes/FieldView';
 import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
@@ -30,13 +29,6 @@ import { CollectionNoteTakingViewDivider } from './CollectionNoteTakingViewDivid
 import { CollectionSubView } from './CollectionSubView';
 const _global = (window /* browser */ || global) /* node */ as any;
 
-export type collectionNoteTakingViewProps = {
-    chromeHidden?: boolean;
-    viewType?: CollectionViewType;
-    NativeWidth?: () => number;
-    NativeHeight?: () => number;
-};
-
 /**
  * CollectionNoteTakingView is a column-based view for displaying documents. In this view, the user can (1)
  * add and remove columns (2) change column sizes and (3) move documents within and between columns. This
@@ -45,28 +37,32 @@ export type collectionNoteTakingViewProps = {
  * the rest of Dash, so it may be worthwhile to transition the headers to simple documents.
  */
 @observer
-export class CollectionNoteTakingView extends CollectionSubView<Partial<collectionNoteTakingViewProps>>() {
+export class CollectionNoteTakingView extends CollectionSubView() {
     _disposers: { [key: string]: IReactionDisposer } = {};
     _masonryGridRef: HTMLDivElement | null = null;
     _draggerRef = React.createRef<HTMLDivElement>();
+    notetakingCategoryField = 'NotetakingCategory';
+    dividerWidth = 16;
     @observable docsDraggedRowCol: number[] = [];
     @observable _cursor: CursorProperty = 'grab';
     @observable _scroll = 0;
     @computed get chromeHidden() {
-        return this.props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden);
+        return BoolCast(this.layoutDoc.chromeHidden);
     }
     // columnHeaders returns the list of SchemaHeaderFields currently being used by the layout doc to render the columns
     @computed get columnHeaders() {
         const columnHeaders = Cast(this.dataDoc.columnHeaders, listSpec(SchemaHeaderField), null);
-        const needsUnsetCategory = this.childDocs.some(d => !d[this.notetakingCategoryField] && !columnHeaders.find(sh => sh.heading === 'unset'));
+        const needsUnsetCategory = this.childDocs.some(d => !d[this.notetakingCategoryField] && !columnHeaders?.find(sh => sh.heading === 'unset'));
         if (needsUnsetCategory) {
-            setTimeout(() => columnHeaders.push(new SchemaHeaderField('unset', undefined, undefined, 1)));
+            setTimeout(() => {
+                const needsUnsetCategory = this.childDocs.some(d => !d[this.notetakingCategoryField] && !columnHeaders?.find(sh => sh.heading === 'unset'));
+                if (needsUnsetCategory) {
+                    if (columnHeaders) columnHeaders.push(new SchemaHeaderField('unset', undefined, undefined, 1));
+                    else this.dataDoc.columnHeaders = new List<SchemaHeaderField>();
+                }
+            });
         }
-        return columnHeaders;
-    }
-    // notetakingCategoryField returns the key to accessing a document's column value
-    @computed get notetakingCategoryField() {
-        return 'NotetakingCategory';
+        return columnHeaders ?? ([] as SchemaHeaderField[]);
     }
     @computed get headerMargin() {
         return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin);
@@ -74,10 +70,6 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
     @computed get xMargin() {
         return NumCast(this.layoutDoc._xMargin, 2 * Math.min(this.gridGap, 0.05 * this.props.PanelWidth()));
     }
-    // dividerWidth returns the width of a CollectionNoteTakingViewDivider
-    @computed get dividerWidth() {
-        return 32;
-    }
     @computed get yMargin() {
         return this.props.yPadding || NumCast(this.layoutDoc._yMargin, 5);
     }
@@ -99,19 +91,10 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
     // availableWidth is the total amount of non-divider width. Since widths are stored relatively,
     // we use availableWidth to convert from a percentage to a pixel count.
     @computed get availableWidth() {
-        const numDividers = this.columnHeaders.length - 1;
+        const numDividers = this.numGroupColumns - 1;
         return this.maxColWidth - numDividers * this.dividerWidth;
     }
 
-    // Documents should NOT have column category fields until entering this view, so the contructor creates the 'New Column'
-    // category for the user to then edit later.
-    constructor(props: any) {
-        super(props);
-        if (this.columnHeaders === undefined) {
-            this.dataDoc.columnHeaders = new List<SchemaHeaderField>([new SchemaHeaderField('New Column', undefined, undefined, 1)]);
-        }
-    }
-
     // children is passed as a prop to the NoteTakingField, which uses this function
     // to render the docs you see within an individual column.
     children = (docs: Doc[]) => {
@@ -149,7 +132,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
             }
         });
         // now we add back in the docs that we're dragging
-        if (rowCol.length) {
+        if (rowCol.length && columnHeaders.length > rowCol[1]) {
             const offset = 0;
             sections.get(columnHeaders[rowCol[1]])?.splice(rowCol[0] - offset, 0, ...DragManager.docsBeingDragged);
         }
@@ -236,9 +219,6 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
             if (this.props.childOpacity) {
                 return this.props.childOpacity();
             }
-            if (this.Document._currentFrame !== undefined) {
-                return CollectionFreeFormDocumentView.getValues(doc, NumCast(this.Document._currentFrame))?.opacity;
-            }
         }
         return this.props.styleProvider?.(doc, props, property);
     };
@@ -392,17 +372,19 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
             });
             // we alter the pivot fields of the docs in case they are moved to a new column.
             const colIndex = this.getColumnFromXCoord(xCoord);
-            const colHeader = StrCast(this.columnHeaders[colIndex].heading);
+            const colHeader = colIndex === undefined ? 'unset' : StrCast(this.columnHeaders[colIndex].heading);
             DragManager.docsBeingDragged.forEach(d => (d[this.notetakingCategoryField] = colHeader));
             // used to notify sections to re-render
             this.docsDraggedRowCol.length = 0;
-            this.docsDraggedRowCol.push(dropInd, this.getColumnFromXCoord(xCoord));
+            const columnFromCoord = this.getColumnFromXCoord(xCoord);
+            columnFromCoord !== undefined && this.docsDraggedRowCol.push(dropInd, columnFromCoord);
         }
     };
 
     // getColumnFromXCoord returns the column index for a given x-coordinate (currently always the client's mouse coordinate).
     // This function is used to know which document a column SHOULD be in while it is being dragged.
-    getColumnFromXCoord = (xCoord: number): number => {
+    getColumnFromXCoord = (xCoord: number): number | undefined => {
+        let colIndex: number | undefined = undefined;
         const numColumns = this.columnHeaders.length;
         const coords = [];
         let colStartXCoord = 0;
@@ -411,7 +393,6 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
             colStartXCoord += this.columnHeaders[i].width * this.availableWidth + this.dividerWidth;
         }
         coords.push(this.PanelWidth);
-        let colIndex = 0;
         for (let i = 0; i < numColumns; i++) {
             if (xCoord > coords[i] && xCoord < coords[i + 1]) {
                 colIndex = i;
@@ -423,20 +404,16 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
 
     // getDocsFromXCoord returns the docs of a column based on the x-coordinate provided.
     getDocsFromXCoord = (xCoord: number): Doc[] => {
-        const colIndex = this.getColumnFromXCoord(xCoord);
-        const colHeader = StrCast(this.columnHeaders[colIndex].heading);
-        // const docs = this.childDocList
-        const docs = this.childDocs;
         const docsMatchingHeader: Doc[] = [];
-        if (docs) {
-            docs.map(d => {
-                if (d instanceof Promise) return;
-                const sectionValue = (d[this.notetakingCategoryField] as object) ?? 'unset';
-                if (sectionValue.toString() == colHeader) {
-                    docsMatchingHeader.push(d);
-                }
-            });
-        }
+        const colIndex = this.getColumnFromXCoord(xCoord);
+        const colHeader = colIndex === undefined ? 'unset' : StrCast(this.columnHeaders[colIndex].heading);
+        this.childDocs?.map(d => {
+            if (d instanceof Promise) return;
+            const sectionValue = (d[this.notetakingCategoryField] as object) ?? 'unset';
+            if (sectionValue.toString() == colHeader) {
+                docsMatchingHeader.push(d);
+            }
+        });
         return docsMatchingHeader;
     };
 
@@ -511,7 +488,7 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
                     this.onPointerMove(true, e.clientX, e.clientY);
                     docus?.map((doc: Doc) => this.addDocument(doc));
                     const newDoc = this.childDocs.lastElement();
-                    const colHeader = StrCast(this.columnHeaders[colInd].heading);
+                    const colHeader = colInd === undefined ? 'unset' : StrCast(this.columnHeaders[colInd].heading);
                     newDoc[this.notetakingCategoryField] = colHeader;
                     const docs = this.childDocList;
                     if (docs && targInd !== -1) {
@@ -570,9 +547,9 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
                 maxColWidth={this.maxColWidth}
                 availableWidth={this.availableWidth}
                 PanelWidth={this.PanelWidth}
-                key={heading?.heading ?? ''}
+                key={heading?.heading ?? 'unset'}
                 headings={this.headings}
-                heading={heading?.heading ?? ''}
+                heading={heading?.heading ?? 'unset'}
                 headingObject={heading}
                 docList={docList}
                 yMargin={this.yMargin}
@@ -589,10 +566,12 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
     @undoBatch
     @action
     addGroup = (value: string) => {
-        for (const header of this.columnHeaders) {
-            if (header.heading == value) {
-                alert('You cannot use an existing column name. Please try a new column name');
-                return value;
+        if (this.columnHeaders) {
+            for (const header of this.columnHeaders) {
+                if (header.heading == value) {
+                    alert('You cannot use an existing column name. Please try a new column name');
+                    return value;
+                }
             }
         }
         const columnHeaders = Cast(this.props.Document.columnHeaders, listSpec(SchemaHeaderField), null);
@@ -678,10 +657,10 @@ export class CollectionNoteTakingView extends CollectionSubView<Partial<collecti
     }
 
     @computed get nativeWidth() {
-        return this.props.NativeWidth?.() ?? Doc.NativeWidth(this.layoutDoc);
+        return Doc.NativeWidth(this.layoutDoc);
     }
     @computed get nativeHeight() {
-        return this.props.NativeHeight?.() ?? Doc.NativeHeight(this.layoutDoc);
+        return Doc.NativeHeight(this.layoutDoc);
     }
 
     @computed get scaling() {
-- 
cgit v1.2.3-70-g09d2


From ef2cd862c062556008a1897b408399dedaee8210 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 25 Aug 2022 17:04:53 -0400
Subject: fixed issues with reloading notetaking view and having columns be
 exactly the same.  fixed adding columns so that changes are actually
 propagated to the DB.  SchemaHeaderFields are bad news...

---
 .../collections/CollectionNoteTakingView.scss      | 32 +++++---
 .../views/collections/CollectionNoteTakingView.tsx | 42 +++++-----
 .../collections/CollectionNoteTakingViewColumn.tsx | 89 +++++++++-------------
 .../CollectionNoteTakingViewDivider.tsx            |  1 -
 4 files changed, 80 insertions(+), 84 deletions(-)

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

diff --git a/src/client/views/collections/CollectionNoteTakingView.scss b/src/client/views/collections/CollectionNoteTakingView.scss
index fe98f307e..5582fd391 100644
--- a/src/client/views/collections/CollectionNoteTakingView.scss
+++ b/src/client/views/collections/CollectionNoteTakingView.scss
@@ -1,7 +1,7 @@
 @import '../global/globalCssVariables';
 
 .collectionNoteTakingView-DocumentButtons {
-    display: flex;
+    display: none;
     justify-content: space-between;
     margin: auto;
 }
@@ -51,6 +51,17 @@
     display: flex;
 }
 
+.collectionNoteTakingViewFieldColumn {
+    height: 100%;
+    display: flex;
+    flex-direction: colum;
+}
+.collectionNoteTakingViewFieldColumn:hover {
+    .collectionNoteTakingView-DocumentButtons {
+        display: flex;
+    }
+}
+
 // TODO:glr Turn this into a seperate class
 .documentButtonMenu {
     position: relative;
@@ -82,7 +93,6 @@
     top: 0;
     overflow-y: auto;
     overflow-x: hidden;
-    flex-wrap: wrap;
     transition: top 0.5s;
 
     > div {
@@ -133,6 +143,16 @@
         margin-left: -5;
     }
 
+    .collectionNoteTakingView-sectionDelete {
+        display: none;
+        position: absolute;
+        right: 0;
+        width: max-content;
+        height: max-content;
+        top: 10;
+        padding: 2;
+    }
+
     // Documents in NoteTaking view
     .collectionNoteTakingView-columnDoc {
         display: flex;
@@ -347,14 +367,6 @@
                 }
             }
         }
-
-        .collectionNoteTakingView-sectionDelete {
-            position: absolute;
-            right: 25px;
-            top: 0;
-            height: 100%;
-            display: none;
-        }
     }
 
     .collectionNoteTakingView-sectionHeader:hover {
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index 5a6d899ef..615141485 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -3,7 +3,7 @@ import { CursorProperty } from 'csstype';
 import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import { DataSym, Doc, Field, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
-import { Id } from '../../../fields/FieldSymbols';
+import { Copy, Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { listSpec } from '../../../fields/Schema';
 import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
@@ -42,7 +42,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     _masonryGridRef: HTMLDivElement | null = null;
     _draggerRef = React.createRef<HTMLDivElement>();
     notetakingCategoryField = 'NotetakingCategory';
-    dividerWidth = 16;
+    public DividerWidth = 16;
     @observable docsDraggedRowCol: number[] = [];
     @observable _cursor: CursorProperty = 'grab';
     @observable _scroll = 0;
@@ -53,10 +53,11 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     @computed get columnHeaders() {
         const columnHeaders = Cast(this.dataDoc.columnHeaders, listSpec(SchemaHeaderField), null);
         const needsUnsetCategory = this.childDocs.some(d => !d[this.notetakingCategoryField] && !columnHeaders?.find(sh => sh.heading === 'unset'));
-        if (needsUnsetCategory) {
+        if (needsUnsetCategory || columnHeaders === undefined || columnHeaders.length === 0) {
             setTimeout(() => {
+                const columnHeaders = Cast(this.dataDoc.columnHeaders, listSpec(SchemaHeaderField), null);
                 const needsUnsetCategory = this.childDocs.some(d => !d[this.notetakingCategoryField] && !columnHeaders?.find(sh => sh.heading === 'unset'));
-                if (needsUnsetCategory) {
+                if (needsUnsetCategory || columnHeaders === undefined || columnHeaders.length === 0) {
                     if (columnHeaders) columnHeaders.push(new SchemaHeaderField('unset', undefined, undefined, 1));
                     else this.dataDoc.columnHeaders = new List<SchemaHeaderField>();
                 }
@@ -68,10 +69,10 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin);
     }
     @computed get xMargin() {
-        return NumCast(this.layoutDoc._xMargin, 2 * Math.min(this.gridGap, 0.05 * this.props.PanelWidth()));
+        return NumCast(this.layoutDoc._xMargin, 5);
     }
     @computed get yMargin() {
-        return this.props.yPadding || NumCast(this.layoutDoc._yMargin, 5);
+        return NumCast(this.layoutDoc._yMargin, 5);
     }
     @computed get gridGap() {
         return NumCast(this.layoutDoc._gridGap, 10);
@@ -86,13 +87,13 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     }
     // maxColWidth returns the maximum column width, which is slightly less than the total available space.
     @computed get maxColWidth() {
-        return this.props.PanelWidth() - 2 * this.xMargin;
+        return this.props.PanelWidth();
     }
     // availableWidth is the total amount of non-divider width. Since widths are stored relatively,
     // we use availableWidth to convert from a percentage to a pixel count.
     @computed get availableWidth() {
         const numDividers = this.numGroupColumns - 1;
-        return this.maxColWidth - numDividers * this.dividerWidth;
+        return this.maxColWidth - numDividers * this.DividerWidth;
     }
 
     // children is passed as a prop to the NoteTakingField, which uses this function
@@ -295,12 +296,9 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         const heading = !d[this.notetakingCategoryField] ? 'unset' : Field.toString(d[this.notetakingCategoryField] as Field);
         const existingHeader = this.columnHeaders.find(sh => sh.heading === heading);
         const existingWidth = existingHeader?.width ? existingHeader.width : 0;
-        const maxWidth = existingWidth > 0 ? existingWidth * this.availableWidth - 2 * this.xMargin : this.maxColWidth - 2 * this.xMargin;
-        if (d.type === DocumentType.RTF) {
-            return maxWidth;
-        }
-        const width = d[WidthSym]();
-        return width < maxWidth ? width : maxWidth;
+        const maxWidth = existingWidth > 0 ? existingWidth * this.availableWidth : this.maxColWidth;
+        const width = d.fitWidth ? maxWidth : d[WidthSym]();
+        return Math.min(maxWidth - CollectionNoteTakingViewColumn.ColumnMargin, width < maxWidth ? width : maxWidth);
     }
 
     // how to get the height of a document. Nothing special here.
@@ -312,8 +310,6 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[WidthSym]() : 0);
         const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[HeightSym]() : 0);
         if (nw && nh) {
-            // const colWid = this.columnWidth / this.numGroupColumns;
-            // const docWid = this.layoutDoc._columnsFill ? colWid : Math.min(this.getDocWidth(d), colWid);
             const docWid = this.getDocWidth(d);
             return Math.min(maxHeight, (docWid * nh) / nw);
         }
@@ -390,7 +386,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         let colStartXCoord = 0;
         for (let i = 0; i < numColumns; i++) {
             coords.push(colStartXCoord);
-            colStartXCoord += this.columnHeaders[i].width * this.availableWidth + this.dividerWidth;
+            colStartXCoord += this.columnHeaders[i].width * this.availableWidth + this.DividerWidth;
         }
         coords.push(this.PanelWidth);
         for (let i = 0; i < numColumns; i++) {
@@ -543,7 +539,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                 numGroupColumns={this.numGroupColumns}
                 gridGap={this.gridGap}
                 pivotField={this.notetakingCategoryField}
-                dividerWidth={this.dividerWidth}
+                dividerWidth={this.DividerWidth}
                 maxColWidth={this.maxColWidth}
                 availableWidth={this.availableWidth}
                 PanelWidth={this.PanelWidth}
@@ -576,7 +572,9 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         }
         const columnHeaders = Cast(this.props.Document.columnHeaders, listSpec(SchemaHeaderField), null);
         const newColWidth = 1 / (this.numGroupColumns + 1);
-        return value && columnHeaders?.push(new SchemaHeaderField(value, undefined, undefined, newColWidth)) && this.resizeColumns(true, newColWidth, this.columnHeaders.length - 1) ? true : false;
+        value && columnHeaders?.push(new SchemaHeaderField(value, undefined, undefined, newColWidth)) && this.resizeColumns(true, newColWidth, this.columnHeaders.length - 1);
+        this.dataDoc.columnHeaders = new List<SchemaHeaderField>(columnHeaders.map(header => header[Copy]()));
+        return true;
     };
 
     onContextMenu = (e: React.MouseEvent): void => {
@@ -621,10 +619,10 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     @computed get buttonMenu() {
         const menuDoc: Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null);
         if (menuDoc) {
-            const width: number = NumCast(menuDoc._width, 30);
-            const height: number = NumCast(menuDoc._height, 30);
+            const width = NumCast(menuDoc._width, 30);
+            const height = NumCast(menuDoc._height, 30);
             return (
-                <div className="buttonMenu-docBtn" style={{ width: width, height: height }}>
+                <div className="buttonMenu-docBtn" style={{ width, height }}>
                     <DocumentView
                         Document={menuDoc}
                         DataDoc={menuDoc}
diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
index c57677683..d951454ff 100644
--- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
+++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
@@ -22,11 +22,6 @@ import { ContextMenuProps } from '../ContextMenuItem';
 import { EditableView } from '../EditableView';
 import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
 import './CollectionNoteTakingView.scss';
-import { List } from '../../../fields/List';
-import { Field } from '../../util/ProsemirrorCopy/prompt';
-const higflyout = require('@hig/flyout');
-export const { anchorPoints } = higflyout;
-export const Flyout = higflyout.default;
 
 interface CSVFieldColumnProps {
     Document: Doc;
@@ -66,19 +61,15 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
 
     // columnWidth returns the width of a column in absolute pixels
     @computed get columnWidth() {
-        if (!this.props.columnHeaders || !this.props.headingObject) {
-            return this.props.maxColWidth;
-        }
-        if (this.props.columnHeaders.length == 1) {
-            return this.props.maxColWidth;
-        }
+        if (!this.props.columnHeaders || !this.props.headingObject || this.props.columnHeaders.length === 1) return '100%';
         const i = this.props.columnHeaders.indexOf(this.props.headingObject);
-        return this.props.columnHeaders[i].width * this.props.availableWidth;
+        return this.props.columnHeaders[i].width * 100 + '%';
     }
 
     private dropDisposer?: DragManager.DragDropDisposer;
     private _headerRef: React.RefObject<HTMLDivElement> = React.createRef();
 
+    public static ColumnMargin = 10;
     @observable _heading = this.props.headingObject ? this.props.headingObject.heading : this.props.heading;
     @observable _color = this.props.headingObject ? this.props.headingObject.color : '#f1efeb';
     _ele: HTMLElement | null = null;
@@ -153,14 +144,14 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
         const acolumnHeaders = Cast(this.props.Document.columnHeaders, listSpec(SchemaHeaderField), null);
         if (acolumnHeaders && this.props.headingObject) {
             const index = acolumnHeaders.indexOf(this.props.headingObject);
-            const columnHeaders = new List<SchemaHeaderField>(acolumnHeaders.map(header => header[Copy]())); // needed for undo to work properly.  otherwise we end up changing field values in the undo stack since they are shared by reference
+            const columnHeaders = acolumnHeaders; // new List<SchemaHeaderField>(acolumnHeaders.map(header => header[Copy]())); // needed for undo to work properly.  otherwise we end up changing field values in the undo stack since they are shared by reference
             const newColIndex = index > 0 ? index - 1 : 1;
             const newColHeader = this.props.columnHeaders ? this.props.columnHeaders[newColIndex] : undefined;
             const newHeading = newColHeader ? newColHeader.heading : 'unset';
             this.props.docList.forEach(d => (d[this.props.pivotField] = newHeading));
             const colWidth = this.props.columnHeaders ? this.props.columnHeaders[index].width : 0;
             columnHeaders.splice(index, 1);
-            Doc.GetProto(this.props.Document).columnHeaders = columnHeaders;
+            //Doc.GetProto(this.props.Document).columnHeaders = columnHeaders;
             this.props.resizeColumns(false, colWidth, index);
         }
     };
@@ -251,9 +242,7 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
                 ref={this._headerRef}
                 style={{
                     marginTop: 2 * this.props.yMargin,
-                    // width: (this.props.columnWidth) /
-                    //     ((uniqueHeadings.length) || 1)
-                    width: this.columnWidth - 20,
+                    width: 'calc(100% - 5px)',
                 }}>
                 <div
                     className="collectionNoteTakingView-sectionHeader-subCont"
@@ -261,48 +250,46 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
                     style={{ background: evContents !== `No Value` ? this._color : 'inherit' }}>
                     <EditableView GetValue={() => evContents} SetValue={this.headingChanged} contents={evContents} oneLine={true} />
                 </div>
+                {(this.props.columnHeaders?.length ?? 0) > 1 && (
+                    <button className="collectionNoteTakingView-sectionDelete" onClick={this.deleteColumn}>
+                        <FontAwesomeIcon icon="trash" size="lg" />
+                    </button>
+                )}
             </div>
         ) : null;
-        const templatecols = `${this.columnWidth}px `;
+        const templatecols = this.columnWidth;
         const type = this.props.Document.type;
         return (
             <>
                 {headingView}
-                {
-                    <div style={{ height: '100%' }}>
-                        <div
-                            key={`${heading}-stack`}
-                            className={`collectionNoteTakingView-Nodes`}
-                            style={{
-                                padding: `${columnYMargin}px ${0}px ${this.props.yMargin}px ${0}px`,
-                                margin: 'auto',
-                                width: 'max-content', //singleColumn ? undefined : `${cols * (style.columnWidth + style.gridGap) + 2 * style.xMargin - style.gridGap}px`,
-                                height: 'max-content',
-                                position: 'relative',
-                                gridGap: this.props.gridGap,
-                                gridTemplateColumns: templatecols,
-                                gridAutoRows: '0px',
-                            }}>
-                            {this.props.renderChildren(this.props.docList)}
-                        </div>
+                <div style={{ height: '100%' }}>
+                    <div
+                        key={`${heading}-stack`}
+                        className={`collectionNoteTakingView-Nodes`}
+                        style={{
+                            padding: `${columnYMargin}px ${0}px ${this.props.yMargin}px ${0}px`,
+                            margin: 'auto',
+                            width: 'max-content',
+                            height: 'max-content',
+                            position: 'relative',
+                            gridGap: this.props.gridGap,
+                            gridTemplateColumns: templatecols,
+                            gridAutoRows: '0px',
+                        }}>
+                        {this.props.renderChildren(this.props.docList)}
+                    </div>
 
-                        {!this.props.chromeHidden && type !== DocumentType.PRES ? (
-                            <div className="collectionNoteTakingView-DocumentButtons" style={{ width: this.columnWidth - 20, marginBottom: 10 }}>
-                                <div key={`${heading}-add-document`} className="collectionNoteTakingView-addDocumentButton">
-                                    <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} textCallback={this.textCallback} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} />
-                                </div>
-                                <div key={`${this.props.Document[Id]}-addGroup`} className="collectionNoteTakingView-addDocumentButton">
-                                    <EditableView {...this.props.editableViewProps()} />
-                                </div>
-                                {this.props.columnHeaders?.length && this.props.columnHeaders.length > 1 && (
-                                    <button className="collectionNoteTakingView-sectionDelete" onClick={this.deleteColumn}>
-                                        <FontAwesomeIcon icon="trash" size="lg" />
-                                    </button>
-                                )}
+                    {!this.props.chromeHidden && type !== DocumentType.PRES ? (
+                        <div className="collectionNoteTakingView-DocumentButtons" style={{ marginBottom: 10 }}>
+                            <div key={`${heading}-add-document`} className="collectionNoteTakingView-addDocumentButton">
+                                <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} textCallback={this.textCallback} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} />
                             </div>
-                        ) : null}
-                    </div>
-                }
+                            <div key={`${this.props.Document[Id]}-addGroup`} className="collectionNoteTakingView-addDocumentButton">
+                                <EditableView {...this.props.editableViewProps()} />
+                            </div>
+                        </div>
+                    ) : null}
+                </div>
             </>
         );
     }
diff --git a/src/client/views/collections/CollectionNoteTakingViewDivider.tsx b/src/client/views/collections/CollectionNoteTakingViewDivider.tsx
index 8d659f790..a1309b11f 100644
--- a/src/client/views/collections/CollectionNoteTakingViewDivider.tsx
+++ b/src/client/views/collections/CollectionNoteTakingViewDivider.tsx
@@ -57,7 +57,6 @@ export class CollectionNoteTakingViewDivider extends React.Component<DividerProp
                         width: 12,
                         borderRight: '4px solid #282828',
                         borderLeft: '4px solid #282828',
-                        margin: '0px 10px',
                     }}
                 />
             </div>
-- 
cgit v1.2.3-70-g09d2


From b1044d1d79c1e06769f74df514e12557426b67be Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 26 Aug 2022 16:16:21 -0400
Subject: trying to clean up transition times for presbox / jumptoDoc, etc.

---
 src/client/util/DocumentManager.ts                 |  18 +-
 .../views/collections/CollectionNoteTakingView.tsx |   2 +-
 .../views/collections/CollectionStackingView.tsx   |   5 +-
 src/client/views/collections/TabDocView.tsx        |   2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   5 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |   1 +
 src/client/views/nodes/trails/PresBox.tsx          | 662 +++++++++------------
 src/client/views/nodes/trails/PresElementBox.tsx   |   9 -
 8 files changed, 287 insertions(+), 417 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 52b643c04..2ca5d1095 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -154,7 +154,7 @@ export class DocumentManager {
         CollectionDockingView.AddSplit(doc, 'right');
         finished?.();
     };
-    public jumpToDocument = async (
+    public jumpToDocument = (
         targetDoc: Doc, // document to display
         willZoom: boolean, // whether to zoom doc to take up most of screen
         createViewFunc = DocumentManager.addView, // how to create a view of the doc if it doesn't exist
@@ -165,8 +165,8 @@ export class DocumentManager {
         finished?: () => void,
         originalTarget?: Doc,
         noSelect?: boolean,
-        presZoom?: number
-    ): Promise<void> => {
+        presZoomScale?: number
+    ): void => {
         originalTarget = originalTarget ?? targetDoc;
         const getFirstDocView = LightboxView.LightboxDoc ? DocumentManager.Instance.getLightboxDocumentView : DocumentManager.Instance.getFirstDocumentView;
         const docView = getFirstDocView(targetDoc, originatingDoc);
@@ -207,7 +207,7 @@ export class DocumentManager {
             finished?.();
         };
         const annoContainerView = (!wasHidden || resolvedTarget !== annotatedDoc) && annotatedDoc && getFirstDocView(annotatedDoc);
-        const contextDocs = docContext.length ? await DocListCastAsync(docContext[0].data) : undefined;
+        const contextDocs = docContext.length ? DocListCast(docContext[0].data) : undefined;
         const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc) || Doc.AreProtosEqual(doc, annotatedDoc)) ? docContext.lastElement() : undefined;
         const targetDocContext = contextDoc || annotatedDoc;
         const targetDocContextView = (targetDocContext && getFirstDocView(targetDocContext)) || (wasHidden && annoContainerView); // if we have an annotation container and the target was hidden, then try again because we just un-hid the document above
@@ -218,7 +218,7 @@ export class DocumentManager {
                     annoContainerView.focus(targetDoc, {
                         originalTarget,
                         willZoom,
-                        scale: presZoom,
+                        scale: presZoomScale,
                         afterFocus: (didFocus: boolean) =>
                             new Promise<ViewAdjustment>(res => {
                                 focusAndFinish(true);
@@ -237,7 +237,7 @@ export class DocumentManager {
                 focusView.focus(originalTarget ?? targetDoc, {
                     originalTarget,
                     willZoom,
-                    scale: presZoom,
+                    scale: presZoomScale,
                     afterFocus: (didFocus: boolean) =>
                         new Promise<ViewAdjustment>(res => {
                             focusAndFinish(forceDidFocus || didFocus);
@@ -265,7 +265,9 @@ export class DocumentManager {
                         afterFocus: async () => {
                             targetDocContext._viewTransition = undefined;
                             if (targetDocContext.layoutKey === 'layout_icon') {
-                                targetDocContextView.iconify(() => this.jumpToDocument(resolvedTarget ?? targetDoc, willZoom, createViewFunc, docContext, linkDoc, closeContextIfNotFound, originatingDoc, finished, originalTarget, noSelect, presZoom));
+                                targetDocContextView.iconify(() =>
+                                    this.jumpToDocument(resolvedTarget ?? targetDoc, willZoom, createViewFunc, docContext, linkDoc, closeContextIfNotFound, originatingDoc, finished, originalTarget, noSelect, presZoomScale)
+                                );
                             }
                             return ViewAdjustment.doNothing;
                         },
@@ -309,7 +311,7 @@ export class DocumentManager {
                         const docContextView = this.getFirstDocumentView(docContext[0]);
                         if (docContextView) {
                             return docContextView.iconify(() =>
-                                this.jumpToDocument(targetDoc, willZoom, createViewFunc, docContext.slice(1, docContext.length), linkDoc, closeContextIfNotFound, originatingDoc, finished, originalTarget, noSelect, presZoom)
+                                this.jumpToDocument(targetDoc, willZoom, createViewFunc, docContext.slice(1, docContext.length), linkDoc, closeContextIfNotFound, originatingDoc, finished, originalTarget, noSelect, presZoomScale)
                             );
                         }
                     }
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index 615141485..92c0bc341 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -201,7 +201,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
             const top = found.getBoundingClientRect().top;
             const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
             if (Math.floor(localTop[1]) !== 0) {
-                smoothScroll((focusSpeed = doc.presTransition || doc.presTransition === 0 ? NumCast(doc.presTransition) : 500), this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
+                smoothScroll((focusSpeed = NumCast(doc.focusSpeed, 500)), this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
             }
         }
         const endFocus = async (moved: boolean) => (options?.afterFocus ? options?.afterFocus(moved) : ViewAdjustment.doNothing);
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 71834607c..7f142727c 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -259,7 +259,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             const top = found.getBoundingClientRect().top;
             const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
             if (Math.floor(localTop[1]) !== 0) {
-                smoothScroll((focusSpeed = doc.presTransition || doc.presTransition === 0 ? NumCast(doc.presTransition) : 500), this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
+                smoothScroll((focusSpeed = NumCast(doc.focusSpeed, 500)), this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
             }
         }
         const endFocus = async (moved: boolean) => options?.afterFocus?.(moved) ?? ViewAdjustment.doNothing;
@@ -494,8 +494,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         super.onExternalDrop(e, {}, (docs: Doc[]) => {
             if (targInd === -1) {
                 this.addDocument(docs);
-            }
-            else {
+            } else {
                 const childDocs = this.childDocList;
                 if (childDocs) {
                     childDocs.splice(targInd, 0, ...docs);
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index f7b48adf6..49228a808 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -366,7 +366,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     focusFunc = (doc: Doc, options?: DocFocusOptions) => {
         const shrinkwrap = options?.originalTarget === this._document && this.view?.ComponentView?.shrinkWrap;
         if (shrinkwrap && this._document) {
-            const focusSpeed = 1000;
+            const focusSpeed = NumCast(this._document.focusSpeed, 500);
             shrinkwrap();
             this._document._viewTransition = `transform ${focusSpeed}ms`;
             setTimeout(
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 210370d39..ede113a9f 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1146,7 +1146,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             }
             // focus on the document in the collection
             const didMove = !cantTransform && !doc.z && (panX !== savedState.panX || panY !== savedState.panY || scale !== savedState.scale);
-            const focusSpeed = options?.instant ? 0 : didMove ? (doc.focusSpeed !== undefined ? Number(doc.focusSpeed) : 500) : 0;
+            const focusSpeed = options?.instant ? 0 : didMove ? NumCast(doc.focusSpeed, 500) : 0;
             // glr: freeform transform speed can be set by adjusting presTransition field - needs a way of knowing when presentation is not active...
             if (didMove) {
                 scale && (this.Document[this.scaleFieldKey] = scale);
@@ -1452,7 +1452,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                     newPos.x !== lastPos.x ||
                     newPos.y !== lastPos.y ||
                     newPos.z !== lastPos.z ||
-                    newPos.zIndex !== lastPos.zIndex
+                    newPos.zIndex !== lastPos.zIndex ||
+                    newPos.transition !== lastPos.transition
                 ) {
                     this._layoutPoolData.set(entry[0], newPos);
                 }
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 82557d36b..c07772b53 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -226,6 +226,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
             PanelWidth: this.panelWidth,
             PanelHeight: this.panelHeight,
         };
+        console.log('WIdth = ' + this.panelWidth() + ' ' + this.dataProvider?.transition);
         return (
             <div
                 className={'collectionFreeFormDocumentView-container'}
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index eb6dad327..ade098917 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -7,7 +7,7 @@ import { ColorState, SketchPicker } from 'react-color';
 import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
 import { Doc, DocListCast, DocListCastAsync, FieldResult } from '../../../../fields/Doc';
 import { Copy } from '../../../../fields/FieldSymbols';
-import { InkField, InkTool } from '../../../../fields/InkField';
+import { InkTool } from '../../../../fields/InkField';
 import { List } from '../../../../fields/List';
 import { ObjectField } from '../../../../fields/ObjectField';
 import { listSpec } from '../../../../fields/Schema';
@@ -90,7 +90,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     constructor(props: any) {
         super(props);
         if ((Doc.ActivePresentation = this.rootDoc)) runInAction(() => (PresBox.Instance = this));
-        this.props.Document.presentationFieldKey = this.fieldKey; // provide info to the presElement script so that it can look up rendering information about the presBox
     }
 
     @observable public static Instance: PresBox;
@@ -127,12 +126,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     @observable _treeViewMap: Map<Doc, number> = new Map();
 
     @computed get tagDocs() {
-        const tagDocs: Doc[] = [];
-        for (const doc of this.childDocs) {
-            const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
-            tagDocs.push(tagDoc);
-        }
-        return tagDocs;
+        return this.childDocs.map(doc => Cast(doc.presentationTargetDoc, Doc, null));
     }
     @computed get itemIndex() {
         return NumCast(this.rootDoc._itemIndex);
@@ -145,11 +139,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     }
     @computed get scrollable(): boolean {
         if (this.targetDoc.type === DocumentType.PDF || this.targetDoc.type === DocumentType.WEB || this.targetDoc.type === DocumentType.RTF || this.targetDoc._viewType === CollectionViewType.Stacking) return true;
-        else return false;
+        return false;
     }
     @computed get panable(): boolean {
         if ((this.targetDoc.type === DocumentType.COL && this.targetDoc._viewType === CollectionViewType.Freeform) || this.targetDoc.type === DocumentType.IMG) return true;
-        else return false;
+        return false;
     }
     @computed get selectedDocumentView() {
         if (SelectionManager.Views().length) return SelectionManager.Views()[0];
@@ -202,8 +196,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
 
     @action
     updateCurrentPresentation = (pres?: Doc) => {
-        if (pres) Doc.ActivePresentation = pres;
-        else Doc.ActivePresentation = this.rootDoc;
+        Doc.ActivePresentation = pres ?? this.rootDoc;
         document.removeEventListener('keydown', PresBox.keyEventsWrapper, true);
         document.addEventListener('keydown', PresBox.keyEventsWrapper, true);
         this._presKeyEventsActive = true;
@@ -318,7 +311,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             const activeItem: Doc = this.activeItem;
             const targetDoc: Doc = this.targetDoc;
             if (activeItem.presActiveFrame !== undefined) {
-                const transTime = NumCast(activeItem.presDuration, 500);
+                const transTime = NumCast(activeItem.presTransition, 500);
                 const context = DocCast(DocCast(activeItem.presentationTargetDoc).context);
                 if (context) {
                     const contextView = DocumentManager.Instance.getFirstDocumentView(context);
@@ -340,12 +333,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             }
             if (targetDoc) {
                 Doc.linkFollowHighlight(targetDoc.annotationOn instanceof Doc ? [targetDoc, targetDoc.annotationOn] : targetDoc);
-                targetDoc &&
-                    runInAction(() => {
-                        if (activeItem.presMovement === PresMovement.Jump) targetDoc.focusSpeed = 0;
-                        else targetDoc.focusSpeed = activeItem.presTransition ? activeItem.presTransition : 500;
-                    });
-                setTimeout(() => (targetDoc.focusSpeed = 500), this.activeItem.presTransition ? NumCast(this.activeItem.presTransition) + 10 : 510);
+                targetDoc && runInAction(() => (targetDoc.focusSpeed = activeItem.presMovement === PresMovement.Jump ? 0 : NumCast(activeItem.presTransition, 500)));
+                setTimeout(() => (targetDoc.focusSpeed = undefined), NumCast(targetDoc.focusSpeed) + 10);
             }
             if (targetDoc?.lastFrame !== undefined) {
                 targetDoc._currentFrame = 0;
@@ -356,14 +345,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             this.onHideDocument(); //Handles hide after/before
         }
     });
-
-    _navTimer!: NodeJS.Timeout;
-    navigateToView = (targetDoc: Doc, activeItem: Doc) => {
-        clearTimeout(this._navTimer);
-        const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document;
-        if (bestTarget) this._navTimer = PresBox.navigateToDoc(bestTarget, activeItem, false);
-    };
-
     static pinDataTypes(target: Doc) {
         const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(target.type as any) || target._viewType === CollectionViewType.Stacking;
         const pannable = [DocumentType.IMG].includes(target.type as any) || (target.type === DocumentType.COL && target._viewType === CollectionViewType.Freeform);
@@ -373,43 +354,29 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const textview = [DocumentType.RTF].includes(target.type as any) && target.activeFrame === undefined;
         return { scrollable, pannable, temporal, clippable, dataview, textview };
     }
-    // navigates to the bestTarget document by making sure it is on screen,
-    // then it applies the view specs stored in activeItem to
+
     @action
-    static navigateToDoc(bestTarget: Doc, activeItem: Doc, jumpToDoc: boolean) {
-        const transTime = NumCast(activeItem.presDuration, 500);
+    static restoreTargetDocView(bestTarget: Doc, activeItem: Doc, jumpToDoc: boolean) {
+        const transTime = NumCast(activeItem.presTransition, 500);
         const presTransitionTime = `all ${transTime}ms`;
         const { scrollable, pannable, temporal, clippable, dataview, textview } = this.pinDataTypes(bestTarget);
         bestTarget._viewTransition = presTransitionTime;
-        bestTarget._dataTransition = dataview || textview ? presTransitionTime : undefined;
-        bestTarget.x = NumCast(activeItem.presX);
-        bestTarget.y = NumCast(activeItem.presY);
-        bestTarget.width = NumCast(activeItem.presWidth);
-        bestTarget.height = NumCast(activeItem.presHeight);
         if (clippable) bestTarget._clipWidth = activeItem.presPinClipWidth;
         if (temporal) bestTarget._currentTimecode = activeItem.presStartTime;
         if (scrollable) bestTarget._scrollTop = activeItem.presPinViewScroll;
         if (dataview) Doc.GetProto(bestTarget).data = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
         if (textview) Doc.GetProto(bestTarget).text = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
         if (pannable) {
-            const contentBounds = Cast(activeItem.contentBounds, listSpec('number'));
+            bestTarget._panX = activeItem.presPinViewX;
+            bestTarget._panY = activeItem.presPinViewY;
+            bestTarget._viewScale = activeItem.presPinViewScale;
+            const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number'));
             if (contentBounds) {
-                bestTarget._panX = (contentBounds[0] + contentBounds[2]) / 2;
-                bestTarget._panY = (contentBounds[1] + contentBounds[3]) / 2;
                 const dv = DocumentManager.Instance.getDocumentView(bestTarget);
-                if (dv) {
-                    bestTarget._viewScale = Math.min(dv.props.PanelHeight() / (contentBounds[3] - contentBounds[1]), dv.props.PanelWidth() / (contentBounds[2] - contentBounds[0]));
-                }
-            } else {
-                bestTarget._panX = activeItem.presPinViewX;
-                bestTarget._panY = activeItem.presPinViewY;
-                bestTarget._viewScale = activeItem.presPinViewScale;
+                dv && (bestTarget._viewScale = Math.min(dv.props.PanelHeight() / (contentBounds[3] - contentBounds[1]), dv.props.PanelWidth() / (contentBounds[2] - contentBounds[0])));
             }
         }
-        return setTimeout(() => {
-            bestTarget._viewTransition = undefined;
-            if (dataview || textview) bestTarget._dataTransition = undefined;
-        }, transTime + 10);
+        return setTimeout(() => (bestTarget._viewTransition = undefined), transTime + 10);
     }
 
     /// copies values from the targetDoc (which is the prototype of the pinDoc) to
@@ -424,7 +391,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             pinDoc.presPinViewX = bounds.left + bounds.width / 2;
             pinDoc.presPinViewY = bounds.top + bounds.height / 2;
             pinDoc.presPinViewScale = pinProps.pinWithView.scale;
-            pinDoc.contentBounds = new List<number>([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]);
+            pinDoc.presPinViewBounds = new List<number>([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]);
         }
         if (pinProps?.pinDocView) {
             const { scrollable, pannable, temporal, clippable, dataview, textview } = this.pinDataTypes(pinDoc);
@@ -446,7 +413,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 const ph = NumCast(pinProps.panelHeight);
                 const ps = NumCast(pinDoc._viewScale);
                 if (pw && ph && ps) {
-                    pinDoc.contentBounds = new List<number>([panX - pw / 2 / ps, panY - ph / 2 / ps, panX + pw / 2 / ps, panY + ph / 2 / ps]);
+                    pinDoc.presPinViewBounds = new List<number>([panX - pw / 2 / ps, panY - ph / 2 / ps, panX + pw / 2 / ps, panY + ph / 2 / ps]);
                 }
                 pinDoc.presPinViewX = panX;
                 pinDoc.presPinViewY = panY;
@@ -455,6 +422,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         }
     }
 
+    _navTimer!: NodeJS.Timeout;
     /**
      * This method makes sure that cursor navigates to the element that
      * has the option open and last in the group.
@@ -504,38 +472,31 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 finished?.();
             }
         };
-        // If openDocument is selected then it should open the document for the user
-        if (activeItem.openDocument) {
-            LightboxView.SetLightboxDoc(targetDoc);
-            // openInTab(targetDoc);
-        } else if (curDoc.presMovement === PresMovement.Pan && targetDoc) {
-            LightboxView.SetLightboxDoc(undefined);
-            const transTime = NumCast(activeItem.presDuration, 500);
+        if (activeItem.presPinView && DocCast(targetDoc.context)?._currentFrame === undefined) {
+            const transTime = NumCast(activeItem.presTransition, 500);
             const presTransitionTime = `all ${transTime}ms`;
             targetDoc._dataTransition = presTransitionTime;
-            targetDoc.x = NumCast(activeItem.presX);
-            targetDoc.y = NumCast(activeItem.presY);
-            targetDoc.width = NumCast(activeItem.presWidth);
-            targetDoc.height = NumCast(activeItem.presHeight);
-            await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true); // documents open in new tab instead of on right
-        } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) {
+            targetDoc.x = NumCast(activeItem.presX, NumCast(targetDoc.x));
+            targetDoc.y = NumCast(activeItem.presY, NumCast(targetDoc.y));
+            targetDoc.width = NumCast(activeItem.presWidth, NumCast(targetDoc.width));
+            targetDoc.height = NumCast(activeItem.presHeight, NumCast(targetDoc.height));
+            setTimeout(() => (targetDoc._dataTransition = undefined), transTime + 10);
+        }
+        // If openDocument is selected then it should open the document for the user
+        if (activeItem.openDocument) {
+            LightboxView.SetLightboxDoc(targetDoc); // openInTab(targetDoc);
+        } else if (targetDoc && curDoc.presMovement !== PresMovement.None && targetDoc) {
             LightboxView.SetLightboxDoc(undefined);
-
-            const transTime = NumCast(activeItem.presDuration, 500);
-            const presTransitionTime = `all ${transTime}ms`;
-            targetDoc._dataTransition = presTransitionTime;
-            targetDoc.x = NumCast(activeItem.presX);
-            targetDoc.y = NumCast(activeItem.presY);
-            targetDoc.width = NumCast(activeItem.presWidth);
-            targetDoc.height = NumCast(activeItem.presHeight);
-            //awaiting jump so that new scale can be found, since jumping is async
-            await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom)); // documents open in new tab instead of on right
+            const zooming = curDoc.presMovement !== PresMovement.Pan;
+            DocumentManager.Instance.jumpToDocument(targetDoc, zooming, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom));
         }
         // 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.
         if (activeItem.presPinView) {
             // if targetDoc is not displayed but one of its aliases is, then we need to modify that alias, not the original target
-            this.navigateToView(targetDoc, activeItem);
+            clearTimeout(this._navTimer);
+            const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document;
+            if (bestTarget) this._navTimer = PresBox.restoreTargetDocView(bestTarget, activeItem, false);
         }
     };
 
@@ -1488,12 +1449,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                     style={{ display: targetDoc.type === DocumentType.AUDIO ? 'none' : 'block' }}
                                     className={'toolbar-slider'}
                                     id="duration-slider"
-                                    onPointerDown={() => {
-                                        this._batch = UndoManager.StartBatch('presDuration');
-                                    }}
-                                    onPointerUp={() => {
-                                        if (this._batch) this._batch.end();
-                                    }}
+                                    onPointerDown={() => (this._batch = UndoManager.StartBatch('presDuration'))}
+                                    onPointerUp={() => this._batch?.end()}
                                     onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                                         e.stopPropagation();
                                         this.setDurationTime(e.target.value);
@@ -1650,28 +1607,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         });
     };
 
-    @computed get mediaStopSlides() {
-        const activeItem: Doc = this.activeItem;
-        const list = this.childDocs.map((doc, i) => {
-            if (i > this.itemIndex) {
-                return (
-                    <option>
-                        {i + 1}. {StrCast(doc.title)}
-                    </option>
-                );
-            }
-        });
-        return list;
-    }
-
     @computed get mediaOptionsDropdown() {
         const activeItem: Doc = this.activeItem;
         const targetDoc: Doc = this.targetDoc;
         const clipStart: number = NumCast(activeItem.clipStart);
         const clipEnd: number = NumCast(activeItem.clipEnd);
-        const duration = Math.round(NumCast(activeItem[`${Doc.LayoutFieldKey(activeItem)}-duration`]) * 10);
         const mediaStopDocInd: number = NumCast(activeItem.mediaStopDoc);
-        const mediaStopDocStr: string = mediaStopDocInd ? mediaStopDocInd + '. ' + this.childDocs[mediaStopDocInd - 1].title : '';
         if (activeItem && targetDoc) {
             return (
                 <div>
@@ -1842,55 +1783,53 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
 
     @computed get newDocumentToolbarDropdown() {
         return (
-            <div>
-                <div
-                    className={'presBox-toolbar-dropdown'}
-                    style={{ display: this.newDocumentTools && this.layoutDoc.presStatus === 'edit' ? 'inline-flex' : 'none' }}
-                    onClick={e => e.stopPropagation()}
-                    onPointerUp={e => e.stopPropagation()}
-                    onPointerDown={e => e.stopPropagation()}>
-                    <div className="layout-container" style={{ height: 'max-content' }}>
-                        <div
-                            className="layout"
-                            style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
-                            onClick={action(() => {
-                                this.layout = 'blank';
-                                this.createNewSlide(this.layout);
-                            })}
-                        />
-                        <div
-                            className="layout"
-                            style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
-                            onClick={action(() => {
-                                this.layout = 'title';
-                                this.createNewSlide(this.layout);
-                            })}>
-                            <div className="title">Title</div>
-                            <div className="subtitle">Subtitle</div>
-                        </div>
-                        <div
-                            className="layout"
-                            style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
-                            onClick={action(() => {
-                                this.layout = 'header';
-                                this.createNewSlide(this.layout);
-                            })}>
-                            <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>
-                                Section header
-                            </div>
+            <div
+                className={'presBox-toolbar-dropdown'}
+                style={{ display: this.newDocumentTools && this.layoutDoc.presStatus === 'edit' ? 'inline-flex' : 'none' }}
+                onClick={e => e.stopPropagation()}
+                onPointerUp={e => e.stopPropagation()}
+                onPointerDown={e => e.stopPropagation()}>
+                <div className="layout-container" style={{ height: 'max-content' }}>
+                    <div
+                        className="layout"
+                        style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+                        onClick={action(() => {
+                            this.layout = 'blank';
+                            this.createNewSlide(this.layout);
+                        })}
+                    />
+                    <div
+                        className="layout"
+                        style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+                        onClick={action(() => {
+                            this.layout = 'title';
+                            this.createNewSlide(this.layout);
+                        })}>
+                        <div className="title">Title</div>
+                        <div className="subtitle">Subtitle</div>
+                    </div>
+                    <div
+                        className="layout"
+                        style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+                        onClick={action(() => {
+                            this.layout = 'header';
+                            this.createNewSlide(this.layout);
+                        })}>
+                        <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>
+                            Section header
                         </div>
-                        <div
-                            className="layout"
-                            style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
-                            onClick={action(() => {
-                                this.layout = 'content';
-                                this.createNewSlide(this.layout);
-                            })}>
-                            <div className="title" style={{ alignSelf: 'center' }}>
-                                Title
-                            </div>
-                            <div className="content">Text goes here</div>
+                    </div>
+                    <div
+                        className="layout"
+                        style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+                        onClick={action(() => {
+                            this.layout = 'content';
+                            this.createNewSlide(this.layout);
+                        })}>
+                        <div className="title" style={{ alignSelf: 'center' }}>
+                            Title
                         </div>
+                        <div className="content">Text goes here</div>
                     </div>
                 </div>
             </div>
@@ -1904,73 +1843,71 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
 
     @computed get newDocumentDropdown() {
         return (
-            <div>
-                <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
-                    <div className="ribbon-box">
-                        Slide Title: <br></br>
-                        <input
-                            className="ribbon-textInput"
-                            placeholder="..."
-                            type="text"
-                            name="fname"
-                            onChange={e => {
-                                e.stopPropagation();
-                                e.preventDefault();
-                                runInAction(() => (this.title = e.target.value));
-                            }}></input>
+            <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+                <div className="ribbon-box">
+                    Slide Title: <br></br>
+                    <input
+                        className="ribbon-textInput"
+                        placeholder="..."
+                        type="text"
+                        name="fname"
+                        onChange={e => {
+                            e.stopPropagation();
+                            e.preventDefault();
+                            runInAction(() => (this.title = e.target.value));
+                        }}></input>
+                </div>
+                <div className="ribbon-box">
+                    Choose type:
+                    <div className="ribbon-doubleButton">
+                        <div title="Text" className={'ribbon-toggle'} style={{ background: this.addFreeform ? '' : Colors.LIGHT_BLUE }} onClick={action(() => (this.addFreeform = !this.addFreeform))}>
+                            Text
+                        </div>
+                        <div title="Freeform" className={'ribbon-toggle'} style={{ background: this.addFreeform ? Colors.LIGHT_BLUE : '' }} onClick={action(() => (this.addFreeform = !this.addFreeform))}>
+                            Freeform
+                        </div>
                     </div>
-                    <div className="ribbon-box">
-                        Choose type:
-                        <div className="ribbon-doubleButton">
-                            <div title="Text" className={'ribbon-toggle'} style={{ background: this.addFreeform ? '' : Colors.LIGHT_BLUE }} onClick={action(() => (this.addFreeform = !this.addFreeform))}>
-                                Text
-                            </div>
-                            <div title="Freeform" className={'ribbon-toggle'} style={{ background: this.addFreeform ? Colors.LIGHT_BLUE : '' }} onClick={action(() => (this.addFreeform = !this.addFreeform))}>
-                                Freeform
+                </div>
+                <div className="ribbon-box" style={{ display: this.addFreeform ? 'grid' : 'none' }}>
+                    Preset layouts:
+                    <div className="layout-container" style={{ height: this.openLayouts ? 'max-content' : '75px' }}>
+                        <div className="layout" style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'blank'))} />
+                        <div className="layout" style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'title'))}>
+                            <div className="title">Title</div>
+                            <div className="subtitle">Subtitle</div>
+                        </div>
+                        <div className="layout" style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'header'))}>
+                            <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>
+                                Section header
                             </div>
                         </div>
-                    </div>
-                    <div className="ribbon-box" style={{ display: this.addFreeform ? 'grid' : 'none' }}>
-                        Preset layouts:
-                        <div className="layout-container" style={{ height: this.openLayouts ? 'max-content' : '75px' }}>
-                            <div className="layout" style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'blank'))} />
-                            <div className="layout" style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'title'))}>
-                                <div className="title">Title</div>
-                                <div className="subtitle">Subtitle</div>
+                        <div className="layout" style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'content'))}>
+                            <div className="title" style={{ alignSelf: 'center' }}>
+                                Title
                             </div>
-                            <div className="layout" style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'header'))}>
-                                <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>
-                                    Section header
-                                </div>
+                            <div className="content">Text goes here</div>
+                        </div>
+                        <div className="layout" style={{ border: this.layout === 'twoColumns' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'twoColumns'))}>
+                            <div className="title" style={{ alignSelf: 'center', gridColumn: '1/3' }}>
+                                Title
                             </div>
-                            <div className="layout" style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'content'))}>
-                                <div className="title" style={{ alignSelf: 'center' }}>
-                                    Title
-                                </div>
-                                <div className="content">Text goes here</div>
+                            <div className="content" style={{ gridColumn: 1, gridRow: 2 }}>
+                                Column one text
                             </div>
-                            <div className="layout" style={{ border: this.layout === 'twoColumns' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'twoColumns'))}>
-                                <div className="title" style={{ alignSelf: 'center', gridColumn: '1/3' }}>
-                                    Title
-                                </div>
-                                <div className="content" style={{ gridColumn: 1, gridRow: 2 }}>
-                                    Column one text
-                                </div>
-                                <div className="content" style={{ gridColumn: 2, gridRow: 2 }}>
-                                    Column two text
-                                </div>
+                            <div className="content" style={{ gridColumn: 2, gridRow: 2 }}>
+                                Column two text
                             </div>
                         </div>
-                        <div className="open-layout" onClick={action(() => (this.openLayouts = !this.openLayouts))}>
-                            <FontAwesomeIcon style={{ transition: 'all 0.3s', transform: this.openLayouts ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={'caret-down'} size={'lg'} />
-                        </div>
                     </div>
-                    <div className="ribbon-final-box">
-                        <div
-                            className={this.title !== '' && ((this.addFreeform && this.layout !== '') || !this.addFreeform) ? 'ribbon-final-button-hidden' : 'ribbon-final-button'}
-                            onClick={() => this.createNewSlide(this.layout, this.title, this.addFreeform)}>
-                            Create New Slide
-                        </div>
+                    <div className="open-layout" onClick={action(() => (this.openLayouts = !this.openLayouts))}>
+                        <FontAwesomeIcon style={{ transition: 'all 0.3s', transform: this.openLayouts ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={'caret-down'} size={'lg'} />
+                    </div>
+                </div>
+                <div className="ribbon-final-box">
+                    <div
+                        className={this.title !== '' && ((this.addFreeform && this.layout !== '') || !this.addFreeform) ? 'ribbon-final-button-hidden' : 'ribbon-final-button'}
+                        onClick={() => this.createNewSlide(this.layout, this.title, this.addFreeform)}>
+                        Create New Slide
                     </div>
                 </div>
             </div>
@@ -2105,115 +2042,109 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             const activeFontColor = targetDoc['pres-text-color'] ? StrCast(targetDoc['pres-text-color']) : 'Black';
             const viewedFontColor = targetDoc['pres-text-viewed-color'] ? StrCast(targetDoc['pres-text-viewed-color']) : 'Black';
             return (
-                <div>
-                    <div
-                        className={`presBox-ribbon ${this.progressivizeTools && this.layoutDoc.presStatus === 'edit' ? 'active' : ''}`}
-                        onClick={e => e.stopPropagation()}
-                        onPointerUp={e => e.stopPropagation()}
-                        onPointerDown={e => e.stopPropagation()}>
-                        <div className="ribbon-box">
-                            {this.stringType} selected
-                            <div
-                                className="ribbon-doubleButton"
-                                style={{
-                                    borderTop: 'solid 1px darkgrey',
-                                    display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.RTF ? 'inline-flex' : 'none',
-                                }}>
-                                <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeChild}>
-                                    Contents
-                                </div>
-                                <div className="ribbon-toggle" style={{ opacity: activeItem.presProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editProgressivize}>
-                                    Edit
-                                </div>
-                            </div>
-                            <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? 'inline-flex' : 'none' }}>
-                                <div className="presBox-subheading">Active text color</div>
-                                <div
-                                    className="ribbon-colorBox"
-                                    style={{ backgroundColor: activeFontColor, height: 15, width: 15 }}
-                                    onClick={action(() => {
-                                        this.openActiveColorPicker = !this.openActiveColorPicker;
-                                    })}></div>
+                <div className={`presBox-ribbon ${this.progressivizeTools && this.layoutDoc.presStatus === 'edit' ? 'active' : ''}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+                    <div className="ribbon-box">
+                        {this.stringType} selected
+                        <div
+                            className="ribbon-doubleButton"
+                            style={{
+                                borderTop: 'solid 1px darkgrey',
+                                display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.RTF ? 'inline-flex' : 'none',
+                            }}>
+                            <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeChild}>
+                                Contents
                             </div>
-                            {this.activeColorPicker}
-                            <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? 'inline-flex' : 'none' }}>
-                                <div className="presBox-subheading">Viewed font color</div>
-                                <div className="ribbon-colorBox" style={{ backgroundColor: viewedFontColor, height: 15, width: 15 }} onClick={action(() => (this.openViewedColorPicker = !this.openViewedColorPicker))}></div>
+                            <div className="ribbon-toggle" style={{ opacity: activeItem.presProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editProgressivize}>
+                                Edit
                             </div>
-                            {this.viewedColorPicker}
+                        </div>
+                        <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? 'inline-flex' : 'none' }}>
+                            <div className="presBox-subheading">Active text color</div>
                             <div
-                                className="ribbon-doubleButton"
-                                style={{ borderTop: 'solid 1px darkgrey', display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG ? 'inline-flex' : 'none' }}>
-                                <div className="ribbon-toggle" style={{ backgroundColor: activeItem.zoomProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeZoom}>
-                                    Zoom
-                                </div>
-                                <div className="ribbon-toggle" style={{ opacity: activeItem.zoomProgressivize ? 1 : 0.4, backgroundColor: activeItem.editZoomProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editZoomProgressivize}>
-                                    Edit
-                                </div>
+                                className="ribbon-colorBox"
+                                style={{ backgroundColor: activeFontColor, height: 15, width: 15 }}
+                                onClick={action(() => {
+                                    this.openActiveColorPicker = !this.openActiveColorPicker;
+                                })}></div>
+                        </div>
+                        {this.activeColorPicker}
+                        <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? 'inline-flex' : 'none' }}>
+                            <div className="presBox-subheading">Viewed font color</div>
+                            <div className="ribbon-colorBox" style={{ backgroundColor: viewedFontColor, height: 15, width: 15 }} onClick={action(() => (this.openViewedColorPicker = !this.openViewedColorPicker))}></div>
+                        </div>
+                        {this.viewedColorPicker}
+                        <div
+                            className="ribbon-doubleButton"
+                            style={{ borderTop: 'solid 1px darkgrey', display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG ? 'inline-flex' : 'none' }}>
+                            <div className="ribbon-toggle" style={{ backgroundColor: activeItem.zoomProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeZoom}>
+                                Zoom
                             </div>
-                            <div
-                                className="ribbon-doubleButton"
-                                style={{
-                                    borderTop: 'solid 1px darkgrey',
-                                    display: targetDoc._viewType === 'stacking' || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF ? 'inline-flex' : 'none',
-                                }}>
-                                <div className="ribbon-toggle" style={{ backgroundColor: activeItem.scrollProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeScroll}>
-                                    Scroll
-                                </div>
-                                <div className="ribbon-toggle" style={{ opacity: activeItem.scrollProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editScrollProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editScrollProgressivize}>
-                                    Edit
-                                </div>
+                            <div className="ribbon-toggle" style={{ opacity: activeItem.zoomProgressivize ? 1 : 0.4, backgroundColor: activeItem.editZoomProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editZoomProgressivize}>
+                                Edit
                             </div>
                         </div>
-                        <div className="ribbon-final-box">
-                            Frames
-                            <div className="ribbon-doubleButton">
-                                <div className="ribbon-frameSelector">
-                                    <div
-                                        key="back"
-                                        title="back frame"
-                                        className="backKeyframe"
-                                        onClick={e => {
-                                            e.stopPropagation();
-                                            this.prevKeyframe(targetDoc, activeItem);
-                                        }}>
-                                        <FontAwesomeIcon icon={'caret-left'} size={'lg'} />
-                                    </div>
-                                    <div
-                                        key="num"
-                                        title="toggle view all"
-                                        className="numKeyframe"
-                                        style={{ color: targetDoc.keyFrameEditing ? 'white' : 'black', backgroundColor: targetDoc.keyFrameEditing ? Colors.MEDIUM_BLUE : Colors.LIGHT_BLUE }}
-                                        onClick={action(() => (targetDoc.keyFrameEditing = !targetDoc.keyFrameEditing))}>
-                                        {NumCast(targetDoc._currentFrame)}
-                                    </div>
-                                    <div
-                                        key="fwd"
-                                        title="forward frame"
-                                        className="fwdKeyframe"
-                                        onClick={e => {
-                                            e.stopPropagation();
-                                            this.nextKeyframe(targetDoc, activeItem);
-                                        }}>
-                                        <FontAwesomeIcon icon={'caret-right'} size={'lg'} />
-                                    </div>
-                                </div>
-                                <Tooltip
-                                    title={
-                                        <>
-                                            <div className="dash-tooltip">{'Last frame'}</div>
-                                        </>
-                                    }>
-                                    <div className="ribbon-property">{NumCast(targetDoc.lastFrame)}</div>
-                                </Tooltip>
+                        <div
+                            className="ribbon-doubleButton"
+                            style={{
+                                borderTop: 'solid 1px darkgrey',
+                                display: targetDoc._viewType === 'stacking' || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF ? 'inline-flex' : 'none',
+                            }}>
+                            <div className="ribbon-toggle" style={{ backgroundColor: activeItem.scrollProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeScroll}>
+                                Scroll
                             </div>
-                            <div className="ribbon-frameList">
-                                {this.frameListHeader}
-                                {this.frameList}
+                            <div className="ribbon-toggle" style={{ opacity: activeItem.scrollProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editScrollProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editScrollProgressivize}>
+                                Edit
                             </div>
-                            <div className="ribbon-toggle" style={{ height: 20, backgroundColor: Colors.LIGHT_BLUE }} onClick={() => console.log(' TODO: play frames')}>
-                                Play
+                        </div>
+                    </div>
+                    <div className="ribbon-final-box">
+                        Frames
+                        <div className="ribbon-doubleButton">
+                            <div className="ribbon-frameSelector">
+                                <div
+                                    key="back"
+                                    title="back frame"
+                                    className="backKeyframe"
+                                    onClick={e => {
+                                        e.stopPropagation();
+                                        this.prevKeyframe(targetDoc, activeItem);
+                                    }}>
+                                    <FontAwesomeIcon icon={'caret-left'} size={'lg'} />
+                                </div>
+                                <div
+                                    key="num"
+                                    title="toggle view all"
+                                    className="numKeyframe"
+                                    style={{ color: targetDoc.keyFrameEditing ? 'white' : 'black', backgroundColor: targetDoc.keyFrameEditing ? Colors.MEDIUM_BLUE : Colors.LIGHT_BLUE }}
+                                    onClick={action(() => (targetDoc.keyFrameEditing = !targetDoc.keyFrameEditing))}>
+                                    {NumCast(targetDoc._currentFrame)}
+                                </div>
+                                <div
+                                    key="fwd"
+                                    title="forward frame"
+                                    className="fwdKeyframe"
+                                    onClick={e => {
+                                        e.stopPropagation();
+                                        this.nextKeyframe(targetDoc, activeItem);
+                                    }}>
+                                    <FontAwesomeIcon icon={'caret-right'} size={'lg'} />
+                                </div>
                             </div>
+                            <Tooltip
+                                title={
+                                    <>
+                                        <div className="dash-tooltip">{'Last frame'}</div>
+                                    </>
+                                }>
+                                <div className="ribbon-property">{NumCast(targetDoc.lastFrame)}</div>
+                            </Tooltip>
+                        </div>
+                        <div className="ribbon-frameList">
+                            {this.frameListHeader}
+                            {this.frameList}
+                        </div>
+                        <div className="ribbon-toggle" style={{ height: 20, backgroundColor: Colors.LIGHT_BLUE }} onClick={() => console.log(' TODO: play frames')}>
+                            Play
                         </div>
                     </div>
                 </div>
@@ -2233,7 +2164,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     @undoBatch
     @action
     switchPresented = (color: ColorState) => {
-        const activeItem: Doc = this.activeItem;
         const targetDoc: Doc = this.targetDoc;
         const val = String(color.hex);
         targetDoc['pres-text-viewed-color'] = val;
@@ -2241,25 +2171,21 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     };
 
     @computed get activeColorPicker() {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
         return !this.openActiveColorPicker ? null : (
             <SketchPicker
                 onChange={this.switchActive}
                 presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']}
-                color={StrCast(targetDoc['pres-text-color'])}
+                color={StrCast(this.targetDoc['pres-text-color'])}
             />
         );
     }
 
     @computed get viewedColorPicker() {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
         return !this.openViewedColorPicker ? null : (
             <SketchPicker
                 onChange={this.switchPresented}
                 presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']}
-                color={StrCast(targetDoc['pres-text-viewed-color'])}
+                color={StrCast(this.targetDoc['pres-text-viewed-color'])}
             />
         );
     }
@@ -2422,10 +2348,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     };
 
     @observable
-    toggleDisplayMovement = (doc: Doc) => {
-        if (doc.displayMovement) doc.displayMovement = false;
-        else doc.displayMovement = true;
-    };
+    toggleDisplayMovement = (doc: Doc) => (doc.displayMovement = !doc.displayMovement);
 
     @action
     checkList = (doc: Doc, list: any): number => {
@@ -2538,24 +2461,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         }
     };
 
-    @computed get moreInfoDropdown() {
-        return <div></div>;
-    }
-
     @computed
     get toolbarWidth(): number {
-        const width = this.props.PanelWidth();
-        return width;
+        return this.props.PanelWidth();
     }
 
     @action
-    toggleProperties = () => {
-        if (SettingsManager.propertiesWidth > 0) {
-            SettingsManager.propertiesWidth = 0;
-        } else {
-            SettingsManager.propertiesWidth = 250;
-        }
-    };
+    toggleProperties = () => (SettingsManager.propertiesWidth = SettingsManager.propertiesWidth > 0 ? 0 : 250);
 
     @computed get toolbar() {
         const propIcon = SettingsManager.propertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left';
@@ -2677,10 +2589,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     }
 
     @action
-    getList = (list: any): List<number> => {
-        const x: List<number> = list;
-        return x;
-    };
+    getList = (list: any): List<number> => list;
 
     @action
     updateList = (list: any): List<number> => {
@@ -2709,12 +2618,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             <div className="frameList-header">
                 &nbsp; Frames {this.panable ? <i>Panable</i> : this.scrollable ? <i>Scrollable</i> : null}
                 <div className={'frameList-headerButtons'}>
-                    <Tooltip
-                        title={
-                            <>
-                                <div className="dash-tooltip">{'Add frame by example'}</div>
-                            </>
-                        }>
+                    <Tooltip title={<div className="dash-tooltip">{'Add frame by example'}</div>}>
                         <div
                             className={'headerButton'}
                             onClick={e => {
@@ -2724,12 +2628,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             <FontAwesomeIcon icon={'plus'} onPointerDown={e => e.stopPropagation()} />
                         </div>
                     </Tooltip>
-                    <Tooltip
-                        title={
-                            <>
-                                <div className="dash-tooltip">{'Edit in collection'}</div>
-                            </>
-                        }>
+                    <Tooltip title={<div className="dash-tooltip">{'Edit in collection'}</div>}>
                         <div
                             className={'headerButton'}
                             onClick={e => {
@@ -2746,7 +2645,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
 
     @computed get frameList() {
         const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
         const frameList: List<number> = this.getList(activeItem.frameList);
         if (frameList) {
             const frameItems = frameList.map(value => <div className="framList-item"></div>);
@@ -2755,18 +2653,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     }
 
     @computed get playButtonFrames() {
-        const targetDoc: Doc = this.targetDoc;
-        return (
-            <>
-                {this.targetDoc ? (
-                    <div className="presPanel-button-frame" style={{ display: targetDoc.lastFrame !== undefined && targetDoc.lastFrame >= 0 ? 'inline-flex' : 'none' }}>
-                        <div>{NumCast(targetDoc._currentFrame)}</div>
-                        <div className="presPanel-divider" style={{ border: 'solid 0.5px white', height: '60%' }}></div>
-                        <div>{NumCast(targetDoc.lastFrame)}</div>
-                    </div>
-                ) : null}
-            </>
-        );
+        const targetDoc = this.targetDoc;
+        return this.targetDoc ? (
+            <div className="presPanel-button-frame" style={{ display: targetDoc.lastFrame !== undefined && targetDoc.lastFrame >= 0 ? 'inline-flex' : 'none' }}>
+                <div>{NumCast(targetDoc._currentFrame)}</div>
+                <div className="presPanel-divider" style={{ border: 'solid 0.5px white', height: '60%' }}></div>
+                <div>{NumCast(targetDoc.lastFrame)}</div>
+            </div>
+        ) : null;
     }
 
     @computed get playButtons() {
@@ -2775,12 +2669,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         // Case 1: There are still other frames and should go through all frames before going to next slide
         return (
             <div className="presPanelOverlay" style={{ display: this.layoutDoc.presStatus !== 'edit' ? 'inline-flex' : 'none' }}>
-                <Tooltip
-                    title={
-                        <>
-                            <div className="dash-tooltip">{'Loop'}</div>
-                        </>
-                    }>
+                <Tooltip title={<div className="dash-tooltip">{'Loop'}</div>}>
                     <div className="presPanel-button" style={{ color: this.layoutDoc.presLoop ? Colors.MEDIUM_BLUE : 'white' }} onClick={() => (this.layoutDoc.presLoop = !this.layoutDoc.presLoop)}>
                         <FontAwesomeIcon icon={'redo-alt'} />
                     </div>
@@ -2798,12 +2687,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     }}>
                     <FontAwesomeIcon icon={'arrow-left'} />
                 </div>
-                <Tooltip
-                    title={
-                        <>
-                            <div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div>
-                        </>
-                    }>
+                <Tooltip title={<div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div>}>
                     <div className="presPanel-button" onClick={this.startOrPause}>
                         <FontAwesomeIcon icon={this.layoutDoc.presStatus === PresStatus.Autoplay ? 'pause' : 'play'} />
                     </div>
@@ -2821,12 +2705,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     <FontAwesomeIcon icon={'arrow-right'} />
                 </div>
                 <div className="presPanel-divider"></div>
-                <Tooltip
-                    title={
-                        <>
-                            <div className="dash-tooltip">{'Click to return to 1st slide'}</div>
-                        </>
-                    }>
+                <Tooltip title={<div className="dash-tooltip">{'Click to return to 1st slide'}</div>}>
                     <div className="presPanel-button" style={{ border: 'solid 1px white' }} onClick={() => this.gotoDocument(0, this.activeItem)}>
                         <b>1</b>
                     </div>
@@ -2931,12 +2810,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return DocListCast(Doc.MyOverlayDocs?.data).includes(this.rootDoc) ? (
             <div className="miniPres" onClick={e => e.stopPropagation()}>
                 <div className="presPanelOverlay" style={{ display: 'inline-flex', height: 30, background: '#323232', top: 0, zIndex: 3000000, boxShadow: presKeyEvents ? '0 0 0px 3px ' + Colors.MEDIUM_BLUE : undefined }}>
-                    <Tooltip
-                        title={
-                            <>
-                                <div className="dash-tooltip">{'Loop'}</div>
-                            </>
-                        }>
+                    <Tooltip title={<div className="dash-tooltip">{'Loop'}</div>}>
                         <div
                             className="presPanel-button"
                             style={{ color: this.layoutDoc.presLoop ? Colors.MEDIUM_BLUE : undefined }}
@@ -2948,12 +2822,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     <div className="presPanel-button" style={{ opacity: presStart ? 0.4 : 1 }} onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.prevClicked, false, false)}>
                         <FontAwesomeIcon icon={'arrow-left'} />
                     </div>
-                    <Tooltip
-                        title={
-                            <>
-                                <div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div>
-                            </>
-                        }>
+                    <Tooltip title={<div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div>}>
                         <div className="presPanel-button" onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.startOrPause, false, false)}>
                             <FontAwesomeIcon icon={this.layoutDoc.presStatus === 'auto' ? 'pause' : 'play'} />
                         </div>
@@ -2962,12 +2831,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         <FontAwesomeIcon icon={'arrow-right'} />
                     </div>
                     <div className="presPanel-divider"></div>
-                    <Tooltip
-                        title={
-                            <>
-                                <div className="dash-tooltip">{'Click to return to 1st slide'}</div>
-                            </>
-                        }>
+                    <Tooltip title={<div className="dash-tooltip">{'Click to return to 1st slide'}</div>}>
                         <div className="presPanel-button" style={{ border: 'solid 1px white' }} onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, () => this.gotoDocument(0, this.activeItem), false, false)}>
                             <b>1</b>
                         </div>
@@ -3033,5 +2897,17 @@ ScriptingGlobals.add(function navigateToDoc(bestTarget: Doc, activeItem: Doc) {
         CollectionDockingView.AddSplit(doc, 'right');
         finished?.();
     };
-    DocumentManager.Instance.jumpToDocument(bestTarget, true, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, () => PresBox.navigateToDoc(bestTarget, activeItem, true), undefined, true, NumCast(activeItem.presZoom));
+    DocumentManager.Instance.jumpToDocument(
+        bestTarget,
+        true,
+        openInTab,
+        srcContext ? [srcContext] : [],
+        undefined,
+        undefined,
+        undefined,
+        () => PresBox.restoreTargetDocView(bestTarget, activeItem, true),
+        undefined,
+        true,
+        NumCast(activeItem.presZoom)
+    );
 });
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 38a87c34b..c78828a78 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -162,15 +162,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
         ));
         return groupSlides;
     }
-    @computed get duration() {
-        let durationInS: number;
-        if (this.rootDoc.type === DocumentType.AUDIO || this.rootDoc.type === DocumentType.VID) {
-            durationInS = NumCast(this.rootDoc.presEndTime) - NumCast(this.rootDoc.presStartTime);
-            durationInS = Math.round(durationInS * 10) / 10;
-        } else if (this.rootDoc.presDuration) durationInS = NumCast(this.rootDoc.presDuration) / 1000;
-        else durationInS = 2;
-        return 'D: ' + durationInS + 's';
-    }
 
     @computed get transition() {
         let transitionInS: number;
-- 
cgit v1.2.3-70-g09d2


From 4580a4193edb451f628eee8be2d3c31d06b1a3a7 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 27 Sep 2022 14:56:28 -0400
Subject: fixed so that following link to video doesn't zoom the video (works
 the same way as PDFs or web pages -- if the document is 'scrollable', then
 don't zoom in on it as well).

---
 src/client/documents/Documents.ts                  |  2 +-
 src/client/util/DocumentManager.ts                 |  4 +-
 .../views/collections/CollectionNoteTakingView.tsx |  2 +-
 .../collections/CollectionStackedTimeline.tsx      |  6 +-
 .../views/collections/CollectionStackingView.tsx   |  2 +-
 src/client/views/collections/TabDocView.tsx        |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  8 +--
 src/client/views/nodes/DocumentView.tsx            | 83 +++++++++++-----------
 8 files changed, 55 insertions(+), 54 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index f046af684..fb68fba38 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1307,7 +1307,7 @@ export namespace DocUtils {
         });
     }
 
-    export function DefaultFocus(doc: Doc, options?: DocFocusOptions) {
+    export function DefaultFocus(doc: Doc, options: DocFocusOptions) {
         options?.afterFocus?.(false);
     }
 
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 3a6c43773..50190061a 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -228,7 +228,7 @@ export class DocumentManager {
                 );
                 return;
             } else if (!docView && targetDoc.type !== DocumentType.MARKER) {
-                annoContainerView.focus(targetDoc); // this allows something like a PDF view to remove its doc filters to expose the target so that it can be found in the retry code below
+                annoContainerView.focus(targetDoc, {}); // this allows something like a PDF view to remove its doc filters to expose the target so that it can be found in the retry code below
             }
         }
         if (focusView) {
@@ -337,7 +337,7 @@ export function DocFocusOrOpen(doc: Doc, collectionDoc?: Doc) {
         const showDoc = context || doc;
         const bestAlias = showDoc === Doc.GetProto(showDoc) ? DocListCast(showDoc.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail) : showDoc;
 
-        CollectionDockingView.AddSplit(bestAlias ? bestAlias : Doc.MakeAlias(showDoc), 'right') && context && setTimeout(() => DocumentManager.Instance.getDocumentView(Doc.GetProto(doc))?.focus(doc));
+        CollectionDockingView.AddSplit(bestAlias ? bestAlias : Doc.MakeAlias(showDoc), 'right') && context && setTimeout(() => DocumentManager.Instance.getDocumentView(Doc.GetProto(doc))?.focus(doc, {}));
     }
 }
 ScriptingGlobals.add(DocFocusOrOpen);
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index 92c0bc341..b0f64ed60 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -193,7 +193,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     };
 
     // let's dive in and get the actual document we want to drag/move around
-    focusDocument = (doc: Doc, options?: DocFocusOptions) => {
+    focusDocument = (doc: Doc, options: DocFocusOptions) => {
         Doc.BrushDoc(doc);
         let focusSpeed = 0;
         const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]);
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index c694e17fb..7bf798656 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -23,7 +23,7 @@ import { AudioWaveform } from '../AudioWaveform';
 import { CollectionSubView } from '../collections/CollectionSubView';
 import { Colors } from '../global/globalEnums';
 import { LightboxView } from '../LightboxView';
-import { DocAfterFocusFunc, DocFocusFunc, DocumentView, DocumentViewProps, DocumentViewSharedProps } from '../nodes/DocumentView';
+import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps, DocumentViewSharedProps } from '../nodes/DocumentView';
 import { LabelBox } from '../nodes/LabelBox';
 import './CollectionStackedTimeline.scss';
 import { VideoBox } from '../nodes/VideoBox';
@@ -828,9 +828,9 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
     // renders anchor LabelBox
     renderInner = computedFn(function (this: StackedTimelineAnchor, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), screenXf: () => Transform, width: () => number, height: () => number) {
         const anchor = observable({ view: undefined as any });
-        const focusFunc = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc, docTransform?: Transform) => {
+        const focusFunc = (doc: Doc, options: DocFocusOptions) => {
             this.props.playLink(mark);
-            this.props.focus(doc, { willZoom, scale, afterFocus, docTransform });
+            this.props.focus(doc, options);
         };
         return {
             anchor,
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index cc006c734..ba29b1d6f 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -251,7 +251,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
     };
 
     // let's dive in and get the actual document we want to drag/move around
-    focusDocument = (doc: Doc, options?: DocFocusOptions) => {
+    focusDocument = (doc: Doc, options: DocFocusOptions) => {
         Doc.BrushDoc(doc);
 
         let focusSpeed = 0;
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 35edbe684..b1f57f3fd 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -367,7 +367,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         return NumCast(Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex].presentationTargetDoc, Doc, null)._currentFrame);
     };
     @action
-    focusFunc = (doc: Doc, options?: DocFocusOptions) => {
+    focusFunc = (doc: Doc, options: DocFocusOptions) => {
         const shrinkwrap = options?.originalTarget === this._document && this.view?.ComponentView?.shrinkWrap;
         if (options?.willZoom !== false && shrinkwrap && this._document) {
             const focusSpeed = NumCast(this._document.focusSpeed, 500);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index e9d0826cd..7b6944e1e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1112,7 +1112,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         return new Promise<number>(res => setTimeout(() => res(runInAction(() => (this._viewTransition = 0))), this._viewTransition)); // set transition to be smooth, then reset
     }
 
-    focusDocument = (doc: Doc, options?: DocFocusOptions) => {
+    focusDocument = (doc: Doc, options: DocFocusOptions) => {
         const state = HistoryUtil.getState();
 
         // TODO This technically isn't correct if type !== "doc", as
@@ -1131,13 +1131,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         // if (SelectionManager.Views().length !== 1 || SelectionManager.Views()[0].Document !== doc) {
         //     SelectionManager.DeselectAll();
         // }
-        if (this.props.Document.scrollHeight || this.props.Document.scrollTop !== undefined) {
+        if (this.props.Document.scrollHeight || this.props.Document.scrollTop !== undefined || this.props.Document.currentTimecode !== undefined) {
             this.props.focus(doc, options);
         } else {
             const xfToCollection = options?.docTransform ?? Transform.Identity();
             const savedState = { panX: NumCast(this.Document._panX), panY: NumCast(this.Document._panY), scale: options?.willZoom ? this.Document[this.scaleFieldKey] : undefined };
             const newState = HistoryUtil.getState();
-            const cantTransform = /*this.props.isAnnotationOverlay ||*/ (this.rootDoc._isGroup || this.layoutDoc._lockedTransform) && !LightboxView.LightboxDoc;
+            const cantTransform = (this.rootDoc._isGroup || this.layoutDoc._lockedTransform) && !LightboxView.LightboxDoc;
             const { panX, panY, scale } = cantTransform ? savedState : this.calculatePanIntoView(doc, xfToCollection, options?.willZoom ? options?.scale || 0.75 : undefined);
             if (!cantTransform) {
                 // only pan and zoom to focus on a document if the document is not an annotation in an annotation overlay collection
@@ -1175,7 +1175,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 ? new Transform(NumCast(this.rootDoc.x), NumCast(this.rootDoc.y), this.rootDoc[WidthSym]() / Doc.NativeWidth(this.rootDoc))
                 : new Transform(NumCast(this.rootDoc.x) + this.rootDoc[WidthSym]() / 2 - NumCast(this.rootDoc._panX), NumCast(this.rootDoc.y) + this.rootDoc[HeightSym]() / 2 - NumCast(this.rootDoc._panY), 1);
 
-            this.props.focus(cantTransform ? doc : this.rootDoc, {
+            this.props.focus(!cantTransform ? this.rootDoc : doc, {
                 ...options,
                 docTransform: xf,
                 afterFocus: (didFocus: boolean) => new Promise<ViewAdjustment>(res => setTimeout(async () => res(await endFocus(didMove || didFocus)), Math.max(0, focusSpeed - (Date.now() - startTime)))),
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f18fd8024..ba061ce8f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -80,7 +80,7 @@ export interface DocFocusOptions {
     instant?: boolean; // whether focus should happen instantly (as opposed to smooth zoom)
 }
 export type DocAfterFocusFunc = (notFocused: boolean) => Promise<ViewAdjustment>;
-export type DocFocusFunc = (doc: Doc, options?: DocFocusOptions) => void;
+export type DocFocusFunc = (doc: Doc, options: DocFocusOptions) => void;
 export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => any;
 export interface DocComponentView {
     updateIcon?: () => void; // updates the icon representation of the document
@@ -534,7 +534,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         }
     };
 
-    focus = (anchor: Doc, options?: DocFocusOptions) => {
+    focus = (anchor: Doc, options: DocFocusOptions) => {
         LightboxView.SetCookie(StrCast(anchor['cookies-set']));
         // copying over VIEW fields immediately allows the view type to switch to create the right _componentView
         Array.from(Object.keys(Doc.GetProto(anchor)))
@@ -1259,46 +1259,47 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             SharingManager.Instance.users.find(users => users.user.email === this.dataDoc.author)?.sharingDoc.userColor,
             Doc.UserDoc().showTitle && [DocumentType.RTF, DocumentType.COL].includes(this.rootDoc.type as any) ? StrCast(Doc.SharingDoc().userColor) : 'rgba(0,0,0,0.4)'
         );
-        const titleView = !showTitle || Doc.noviceMode ? null : (
-            <div
-                className={`documentView-titleWrapper${showTitleHover ? '-hover' : ''}`}
-                key="title"
-                style={{
-                    position: this.headerMargin ? 'relative' : 'absolute',
-                    height: this.titleHeight,
-                    width: !this.headerMargin ? `calc(100% - 18px)` : '100%', // leave room for annotation button
-                    color: lightOrDark(background),
-                    background,
-                    pointerEvents: this.onClickHandler || this.Document.ignoreClick ? 'none' : this.isContentActive() || this.props.isDocumentActive?.() ? 'all' : undefined,
-                }}>
-                <EditableView
-                    ref={this._titleRef}
-                    contents={showTitle
-                        .split(';')
-                        .map(field => field.trim())
-                        .map(field => targetDoc[field]?.toString())
-                        .join('\\')}
-                    display={'block'}
-                    fontSize={10}
-                    GetValue={() => (showTitle.split(';').length === 1 ? showTitle + '=' + Field.toString(targetDoc[showTitle.split(';')[0]] as any as Field) : '#' + showTitle)}
-                    SetValue={undoBatch((input: string) => {
-                        if (input?.startsWith('#')) {
-                            if (this.props.showTitle) {
-                                this.rootDoc._showTitle = input?.substring(1) ? input.substring(1) : undefined;
+        const titleView =
+            !showTitle || Doc.noviceMode ? null : (
+                <div
+                    className={`documentView-titleWrapper${showTitleHover ? '-hover' : ''}`}
+                    key="title"
+                    style={{
+                        position: this.headerMargin ? 'relative' : 'absolute',
+                        height: this.titleHeight,
+                        width: !this.headerMargin ? `calc(100% - 18px)` : '100%', // leave room for annotation button
+                        color: lightOrDark(background),
+                        background,
+                        pointerEvents: this.onClickHandler || this.Document.ignoreClick ? 'none' : this.isContentActive() || this.props.isDocumentActive?.() ? 'all' : undefined,
+                    }}>
+                    <EditableView
+                        ref={this._titleRef}
+                        contents={showTitle
+                            .split(';')
+                            .map(field => field.trim())
+                            .map(field => targetDoc[field]?.toString())
+                            .join('\\')}
+                        display={'block'}
+                        fontSize={10}
+                        GetValue={() => (showTitle.split(';').length === 1 ? showTitle + '=' + Field.toString(targetDoc[showTitle.split(';')[0]] as any as Field) : '#' + showTitle)}
+                        SetValue={undoBatch((input: string) => {
+                            if (input?.startsWith('#')) {
+                                if (this.props.showTitle) {
+                                    this.rootDoc._showTitle = input?.substring(1) ? input.substring(1) : undefined;
+                                } else {
+                                    Doc.UserDoc().showTitle = input?.substring(1) ? input.substring(1) : 'creationDate';
+                                }
                             } else {
-                                Doc.UserDoc().showTitle = input?.substring(1) ? input.substring(1) : 'creationDate';
+                                var value = input.replace(new RegExp(showTitle + '='), '') as string | number;
+                                if (showTitle !== 'title' && Number(value).toString() === value) value = Number(value);
+                                if (showTitle.includes('Date') || showTitle === 'author') return true;
+                                Doc.SetInPlace(targetDoc, showTitle, value, true);
                             }
-                        } else {
-                            var value = input.replace(new RegExp(showTitle + '='), '') as string | number;
-                            if (showTitle !== 'title' && Number(value).toString() === value) value = Number(value);
-                            if (showTitle.includes('Date') || showTitle === 'author') return true;
-                            Doc.SetInPlace(targetDoc, showTitle, value, true);
-                        }
-                        return true;
-                    })}
-                />
-            </div>
-        );
+                            return true;
+                        })}
+                    />
+                </div>
+            );
         return this.props.hideTitle || (!showTitle && !showCaption) ? (
             this.contents
         ) : (
@@ -1557,7 +1558,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     }
 
     toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight());
-    focus = (doc: Doc, options?: DocFocusOptions) => this.docView?.focus(doc, options);
+    focus = (doc: Doc, options: DocFocusOptions) => this.docView?.focus(doc, options);
     getBounds = () => {
         if (!this.docView || !this.docView.ContentDiv || this.props.Document.presBox || this.docView.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) {
             return undefined;
-- 
cgit v1.2.3-70-g09d2

