From 3573a81d334cf8cc13d19b04c6f2094c24c43932 Mon Sep 17 00:00:00 2001 From: Aubrey Li Date: Thu, 3 Mar 2022 18:12:13 -0500 Subject: edit: lightbox opens tab in the same stack --- src/client/views/collections/CollectionDockingView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index f543d924d..79e036a0e 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -449,7 +449,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) { alert('cant delete the last stack'); } })); - stack.header?.controlsContainer.find('.lm_popout') //get the close icon + stack.header?.controlsContainer.find('.lm_popout') //get the popout icon .off('click') //unbind the current click handler .click(action(() => { // stack.config.fixed = !stack.config.fixed; // force the stack to have a fixed size -- cgit v1.2.3-70-g09d2 From 51d7ce5f71465f2f578a08a998b2df353242ff4d Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 5 Apr 2022 13:54:26 -0400 Subject: fixes to allow dragging golden layout windows to be aborted with 'esc'. some code cleanup as well to avoid rebuilding golden layout when tabs are closed. Fixes for undo and goldenlayout --- src/client/goldenLayout.js | 32 ++++-- src/client/util/DragManager.ts | 25 ++--- src/client/views/DocumentDecorations.tsx | 7 +- src/client/views/GlobalKeyHandler.ts | 1 + .../views/collections/CollectionDockingView.tsx | 109 +++++++++++++-------- src/client/views/collections/TabDocView.tsx | 3 +- 6 files changed, 108 insertions(+), 69 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/goldenLayout.js b/src/client/goldenLayout.js index 896237e1d..295875ef6 100644 --- a/src/client/goldenLayout.js +++ b/src/client/goldenLayout.js @@ -366,6 +366,7 @@ this._nOriginalY = 0; this._bDragging = false; + this._bAborting = false; this._fMove = lm.utils.fnBind(this.onMouseMove, this); this._fUp = lm.utils.fnBind(this.onMouseUp, this); @@ -427,6 +428,24 @@ } }, + AbortDrag: function () { + if (this._timeout != null) { + clearTimeout(this._timeout); + this._eBody.removeClass('lm_dragging'); + this._eElement.removeClass('lm_dragging'); + this._oDocument.find('iframe').css('pointer-events', ''); + this._oDocument.unbind('mousemove touchmove', this._fMove); + this._oDocument.unbind('mouseup touchend', this._fUp); + + if (this._bDragging === true) { + this._bDragging = false; + this._bAborting = true; + this.emit('dragStop', { pageX: 0, pageY: 0 }, this._nOriginalX + this._nX); + this._bAborting = false; + } + } + }, + onMouseUp: function (oEvent) { if (this._timeout != null) { clearTimeout(this._timeout); @@ -2178,18 +2197,18 @@ */ _onDrop: function () { this._layoutManager.dropTargetIndicator.hide(); - + let abortedDrop = this._dragListener._bAborting; /* * Valid drop area found */ - if (this._area !== null) { + if (!abortedDrop && this._area !== null) { this._area.contentItem._$onDrop(this._contentItem, this._area); /** * No valid drop area available at present, but one has been found before. * Use it */ - } else if (this._lastValidArea !== null) { + } else if (!abortedDrop && this._lastValidArea !== null) { this._lastValidArea.contentItem._$onDrop(this._contentItem, this._lastValidArea); /** @@ -2197,7 +2216,7 @@ * content item to its original position if a original parent is provided. * (Which is not the case if the drag had been initiated by createDragSource) */ - } else if (this._originalParent) { + } else if (!abortedDrop && this._originalParent) { this._originalParent.addChild(this._contentItem); /** @@ -2212,7 +2231,7 @@ restoreScrollTops(this._contentItem.element) this.element.remove(); - this._layoutManager.emit('itemDropped', this._contentItem); + !abortedDrop && this._layoutManager.emit('itemDropped', this._contentItem); }, /** @@ -2963,7 +2982,7 @@ if (this.contentItem.parent.isMaximised === true) { this.contentItem.parent.toggleMaximise(); } - new lm.controls.DragProxy( + let proxy = new lm.controls.DragProxy( x, y, this._dragListener, @@ -2971,6 +2990,7 @@ this.contentItem, this.header.parent ); + this._layoutManager.emit('dragStart', proxy); }, /** diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 0d6a77f71..411fc6d11 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,3 +1,4 @@ +import { extend } from "lodash"; import { action } from "mobx"; import { DateField } from "../../fields/DateField"; import { Doc, Field, Opt } from "../../fields/Doc"; @@ -56,12 +57,7 @@ export function SetupDrag( if (e.shiftKey) { e.persist(); const dragDoc = await docFunc(); - dragDoc && DragManager.StartWindowDrag?.({ - pageX: e.pageX, - pageY: e.pageY, - preventDefault: emptyFunction, - button: 0 - }, [dragDoc]); + dragDoc && DragManager.StartWindowDrag?.(e, [dragDoc]); } else { document.addEventListener("pointermove", onRowMove); document.addEventListener("pointerup", onRowUp); @@ -74,7 +70,8 @@ export function SetupDrag( export namespace DragManager { let dragDiv: HTMLDivElement; let dragLabel: HTMLDivElement; - export let StartWindowDrag: Opt<((e: any, dragDocs: Doc[]) => void)> = undefined; + export let StartWindowDrag: Opt<((e: { pageX: number, pageY: number }, dragDocs: Doc[], finishDrag?: (aborted: boolean) => void) => void)>; + export let CompleteWindowDrag: Opt<(aborted: boolean) => void>; export function Root() { const root = document.getElementById("root"); @@ -460,17 +457,13 @@ export namespace DragManager { } if (((e.target as any)?.className === "lm_tabs" || e?.shiftKey) && dragData.draggedDocuments.length === 1) { dragData.dropAction = dragData.userDropAction || "same"; - if (dragData.dropAction === "move" || dragData.dropAction === "same") { - dragData.removeDocument?.(dragData.draggedDocuments[0]); - } AbortDrag(); await finishDrag?.(new DragCompleteEvent(true, dragData)); - DragManager.StartWindowDrag?.({ - pageX: e.pageX, - pageY: e.pageY, - preventDefault: emptyFunction, - button: 0 - }, dragData.droppedDocuments); + DragManager.StartWindowDrag?.(e, dragData.droppedDocuments, (aborted) => { + if (!aborted && (dragData.dropAction === "move" || dragData.dropAction === "same")) { + dragData.removeDocument?.(dragData.draggedDocuments[0]); + } + }); } const target = document.elementFromPoint(e.x, e.y); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 8cd646935..d7ead713a 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -151,12 +151,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P } onMaximizeDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, () => { - DragManager.StartWindowDrag?.({ - pageX: e.pageX, - pageY: e.pageY, - preventDefault: emptyFunction, - button: 0 - }, [SelectionManager.Views().slice(-1)[0].rootDoc]); + DragManager.StartWindowDrag?.(e, [SelectionManager.Views().slice(-1)[0].rootDoc]); return true; }, emptyFunction, this.onMaximizeClick, false, false); } diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 1a4080d81..4a327a842 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -114,6 +114,7 @@ export class KeyManager { DocumentLinksButton.StartLinkView = undefined; InkStrokeProperties.Instance._controlButton = false; CurrentUserUtils.SelectedTool = InkTool.None; + DragManager.CompleteWindowDrag?.(true); var doDeselect = true; if (SnappingManager.GetIsDragging()) { DragManager.AbortDrag(); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 9e8374605..6931d9896 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -11,6 +11,7 @@ import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { inheritParentAcls } from '../../../fields/util'; +import { emptyFunction } from '../../../Utils'; import { DocServer } from "../../DocServer"; import { Docs } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; @@ -46,7 +47,7 @@ export class CollectionDockingView extends CollectionSubView() { private _reactionDisposer?: IReactionDisposer; private _lightboxReactionDisposer?: IReactionDisposer; private _containerRef = React.createRef(); - private _flush: UndoManager.Batch | undefined; + public _flush: UndoManager.Batch | undefined; private _ignoreStateChange = ""; public tabMap: Set = new Set(); public get initialized() { return this._goldenLayout !== null; } @@ -62,15 +63,37 @@ export class CollectionDockingView extends CollectionSubView() { DragManager.StartWindowDrag = this.StartOtherDrag; } - public StartOtherDrag = (e: any, dragDocs: Doc[]) => { - !this._flush && (this._flush = UndoManager.StartBatch("golden layout drag")); + /** + * Switches from dragging a document around a freeform canvas to dragging it as a tab to be docked. + * + * @param e fake mouse down event position data containing pageX and pageY coordinates + * @param dragDocs the documents to be dragged + * @param batch optionally an undo batch that has been started to use instead of starting a new batch + */ + public StartOtherDrag = (e: { pageX: number, pageY: number }, dragDocs: Doc[], finishDrag?: (aborted: boolean) => void) => { + this._flush = this._flush ?? UndoManager.StartBatch("golden layout drag"); const config = dragDocs.length === 1 ? CollectionDockingView.makeDocumentConfig(dragDocs[0]) : - { type: 'row', content: dragDocs.map((doc, i) => CollectionDockingView.makeDocumentConfig(doc)) }; + { type: 'row', content: dragDocs.map(doc => CollectionDockingView.makeDocumentConfig(doc)) }; const dragSource = this._goldenLayout.createDragSource(document.createElement("div"), config); - //dragSource._dragListener.on("dragStop", dragSource.destroy); - dragSource._dragListener.onMouseDown(e); + this.tabDragStart(dragSource, finishDrag); + dragSource._dragListener.onMouseDown({ pageX: e.pageX, pageY: e.pageY, preventDefault: emptyFunction, button: 0 }); } + tabItemDropped = () => DragManager.CompleteWindowDrag?.(false); + tabDragStart = (proxy: any, finishDrag?: (aborted: boolean) => void) => { + DragManager.CompleteWindowDrag = (aborted: boolean) => { + if (aborted) { + proxy._dragListener.AbortDrag(); + if (this._flush) { + this._flush.cancel(); // cancel the undo change being logged + this._flush = undefined; + this.setupGoldenLayout(); // restore golden layout to where it was before the drag (this is a no-op when using StartOtherDrag because the proxy dragged item was never in the golden layout) + } + DragManager.CompleteWindowDrag = undefined; + } + finishDrag?.(aborted); + } + } @undoBatch public CloseFullScreen = () => { this._goldenLayout._maximisedItem?.toggleMaximise(); @@ -106,7 +129,6 @@ export class CollectionDockingView extends CollectionSubView() { docconfig.callDownwards('_$init'); instance._goldenLayout._$maximiseItem(docconfig); instance._goldenLayout.emit('stateChanged'); - instance._ignoreStateChange = JSON.stringify(instance._goldenLayout.toConfig()); instance.stateChanged(); return true; } @@ -255,7 +277,6 @@ export class CollectionDockingView extends CollectionSubView() { layoutChanged() { this._goldenLayout.root.callDownwards('setSize', [this._goldenLayout.width, this._goldenLayout.height]); this._goldenLayout.emit('stateChanged'); - this._ignoreStateChange = JSON.stringify(this._goldenLayout.toConfig()); this.stateChanged(); return true; } @@ -294,6 +315,9 @@ export class CollectionDockingView extends CollectionSubView() { } } this._goldenLayout.init(); + this._goldenLayout.root.layoutManager.on('itemDropped', this.tabItemDropped); + this._goldenLayout.root.layoutManager.on('dragStart', this.tabDragStart) + this._goldenLayout.root.layoutManager.on('activeContentItemChanged', this.stateChanged); } } @@ -335,13 +359,12 @@ export class CollectionDockingView extends CollectionSubView() { @action onPointerUp = (e: MouseEvent): void => { window.removeEventListener("pointerup", this.onPointerUp); - if (this._flush) { - setTimeout(() => { - CollectionDockingView.Instance._ignoreStateChange = JSON.stringify(CollectionDockingView.Instance._goldenLayout.toConfig()); - this.stateChanged(); - this._flush?.end(); - this._flush = undefined; - }, 10); + const flush = this._flush; + this._flush = undefined; + if (flush) { + DragManager.CompleteWindowDrag = undefined; + if (!this.stateChanged()) flush.cancel(); + else flush.end(); } } @@ -352,9 +375,12 @@ export class CollectionDockingView extends CollectionSubView() { hitFlyout = (par.className === "dockingViewButtonSelector"); } if (!hitFlyout) { + const htmlTarget = e.target as HTMLElement; window.addEventListener("mouseup", this.onPointerUp); - if (!(e.target as HTMLElement).closest("*.lm_content") && ((e.target as HTMLElement).closest("*.lm_tab") || (e.target as HTMLElement).closest("*.lm_stack"))) { - this._flush = UndoManager.StartBatch("golden layout edit"); + if (!htmlTarget.closest("*.lm_content") && (htmlTarget.closest("*.lm_tab") || htmlTarget.closest("*.lm_stack"))) { + if (htmlTarget.className !== "lm_close_tab") { + this._flush = UndoManager.StartBatch("golden layout edit"); + } } } if (!e.nativeEvent.cancelBubble && !InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE) && @@ -388,38 +414,43 @@ export class CollectionDockingView extends CollectionSubView() { @action stateChanged = () => { + this._ignoreStateChange = JSON.stringify(this._goldenLayout.toConfig()); const json = JSON.stringify(this._goldenLayout.toConfig()); const matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g); const docids = matches?.map(m => m.replace("\"documentId\":\"", "").replace("\"", "")); const docs = !docids ? [] : docids.map(id => DocServer.GetCachedRefField(id)).filter(f => f).map(f => f as Doc); - - this.props.Document.dockingConfig = json; - setTimeout(async () => { - const sublists = await DocListCastAsync(this.props.Document[this.props.fieldKey]); - const tabs = sublists && Cast(sublists[0], Doc, null); - // const other = sublists && Cast(sublists[1], Doc, null); - const tabdocs = await DocListCastAsync(tabs?.data); - // const otherdocs = await DocListCastAsync(other?.data); - if (tabs) { - tabs.data = new List(docs); - // DocListCast(tabs.aliases).forEach(tab => tab !== tabs && (tab.data = new List(docs))); - } - // const otherSet = new Set(); - // otherdocs?.filter(doc => !docs.includes(doc)).forEach(doc => otherSet.add(doc)); - // tabdocs?.filter(doc => !docs.includes(doc) && doc.type !== DocumentType.KVP).forEach(doc => otherSet.add(doc)); - // const vals = Array.from(otherSet.values()).filter(val => val instanceof Doc).map(d => d).filter(d => d.type !== DocumentType.KVP); - // this.props.Document[DataSym][this.props.fieldKey + "-all"] = new List([...docs, ...vals]); - // if (other) { - // other.data = new List(vals); - // // DocListCast(other.aliases).forEach(tab => tab !== other && (tab.data = new List(vals))); - // } - }, 0); + const changesMade = this.props.Document.dockingConfig !== json; + if (changesMade && !this._flush) { + this.props.Document.dockingConfig = json; + setTimeout(async () => { + const sublists = await DocListCastAsync(this.props.Document[this.props.fieldKey]); + const tabs = sublists && Cast(sublists[0], Doc, null); + // const other = sublists && Cast(sublists[1], Doc, null); + const tabdocs = await DocListCastAsync(tabs?.data); + // const otherdocs = await DocListCastAsync(other?.data); + if (tabs) { + tabs.data = new List(docs); + // DocListCast(tabs.aliases).forEach(tab => tab !== tabs && (tab.data = new List(docs))); + } + // const otherSet = new Set(); + // otherdocs?.filter(doc => !docs.includes(doc)).forEach(doc => otherSet.add(doc)); + // tabdocs?.filter(doc => !docs.includes(doc) && doc.type !== DocumentType.KVP).forEach(doc => otherSet.add(doc)); + // const vals = Array.from(otherSet.values()).filter(val => val instanceof Doc).map(d => d).filter(d => d.type !== DocumentType.KVP); + // this.props.Document[DataSym][this.props.fieldKey + "-all"] = new List([...docs, ...vals]); + // if (other) { + // other.data = new List(vals); + // // DocListCast(other.aliases).forEach(tab => tab !== other && (tab.data = new List(vals))); + // } + }, 0); + } + return changesMade; } tabDestroyed = (tab: any) => { this.tabMap.delete(tab); tab._disposers && Object.values(tab._disposers).forEach((disposer: any) => disposer?.()); tab.reactComponents?.forEach((ele: any) => ReactDOM.unmountComponentAtNode(ele)); + this.stateChanged(); } tabCreated = (tab: any) => { tab.contentItem.element[0]?.firstChild?.firstChild?.InitTab?.(tab); // have to explicitly initialize tabs that reuse contents from previous tabs (ie, when dragging a tab around a new tab is created for the old content) diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 8b5022593..ad5c0efb3 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -190,7 +190,7 @@ export class TabDocView extends React.Component { Object.values(tab._disposers).forEach((disposer: any) => disposer?.()); Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", doc, undefined, true, true); SelectionManager.DeselectAll(); - tab.contentItem.remove(); + UndoManager.RunInBatch(() => tab.contentItem.remove(), "delete tab"); }); } } @@ -277,7 +277,6 @@ export class TabDocView extends React.Component { private onActiveContentItemChanged(contentItem: any) { if (!contentItem || (this.stack === contentItem.parent && ((contentItem?.tab === this.tab && !this._isActive) || (contentItem?.tab !== this.tab && this._isActive)))) { this._activated = this._isActive = !contentItem || contentItem?.tab === this.tab; - (CollectionDockingView.Instance as any)._goldenLayout?.isInitialised && CollectionDockingView.Instance.stateChanged(); !this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one. } } -- cgit v1.2.3-70-g09d2 From ef63a072a586f51e8fa51b4684987491287540b2 Mon Sep 17 00:00:00 2001 From: Naafiyan Ahmed Date: Thu, 7 Apr 2022 17:21:01 -0400 Subject: added grouping and write mode vs pen mode --- src/client/util/CurrentUserUtils.ts | 4 +- src/client/views/GestureOverlay.tsx | 5 +- .../views/collections/CollectionDockingView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 12 +-- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 4 +- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/MapBox/MapBox.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 2 +- src/client/views/nodes/button/FontIconBox.tsx | 112 ++++++++++----------- src/client/views/pdf/PDFViewer.tsx | 2 +- src/fields/InkField.ts | 3 +- webpack.config.js | 2 +- 14 files changed, 77 insertions(+), 79 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 6cab8c100..f08f13bbc 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1010,8 +1010,8 @@ export class CurrentUserUtils { static inkTools(doc: Doc) { const tools: Button[] = [ - { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen", click: 'setActiveInkTool("pen", _readOnly_)' }, - { title: "Mode", toolTip: "Mode (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen", click: 'setActiveInkTool("write", _readOnly_)' }, + { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", click: 'setActiveInkTool("pen", _readOnly_)' }, + { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", click: 'setActiveInkTool("write", _readOnly_)' }, { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", click: 'setActiveInkTool("eraser", _readOnly_)' }, // { title: "Highlighter", toolTip: "Highlighter (Ctrl+H)", btnType: ButtonType.ToggleButton, icon: "highlighter", click: 'setActiveInkTool("highlighter")' }, { title: "Circle", toolTip: "Circle (Ctrl+Shift+C)", btnType: ButtonType.ToggleButton, icon: "circle", click: 'setActiveInkTool("circle", _readOnly_)' }, diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 87b006a93..53b360e60 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -491,7 +491,10 @@ export class GestureOverlay extends Touchable { @action onPointerDown = (e: React.PointerEvent) => { - if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { + if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { + CurrentUserUtils.SelectedTool = InkTool.Write; + } this._points.push({ X: e.clientX, Y: e.clientY }); setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction); // if (CurrentUserUtils.SelectedTool === InkTool.Highlighter) SetActiveInkColor("rgba(245, 230, 95, 0.75)"); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 9e8374605..c9f55a7bd 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -358,7 +358,7 @@ export class CollectionDockingView extends CollectionSubView() { } } if (!e.nativeEvent.cancelBubble && !InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE) && - ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { e.stopPropagation(); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index a694ca2b3..40164313c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -468,6 +468,8 @@ export class CollectionFreeFormView extends CollectionSubView e.preventDefault()} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7092b335c..2e822bb6a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -517,7 +517,7 @@ export class DocumentViewInternal extends DocComponent { // continue if the event hasn't been canceled AND we are using a mouse or this has an onClick or onDragStart function (meaning it is a button document) - if (!(InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool))) { + if (!(InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool))) { if (!InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { e.stopPropagation(); if (SelectionManager.IsSelected(this.props.DocumentView(), true) && this.props.Document._viewType !== CollectionViewType.Docking) e.preventDefault(); // goldenlayout needs to be able to move its tabs, so can't preventDefault for it @@ -550,7 +550,7 @@ export class DocumentViewInternal extends DocComponent { if (e.cancelBubble) return; - if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool))) return; + if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool))) return; if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 0a4168698..a8da22b61 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -322,7 +322,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent; } marqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index aa2130af5..9bf7c2e8c 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -471,7 +471,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { - if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 33fdc4935..a5b8967c4 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -549,7 +549,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent { - if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 7ff47107e..54c49ecad 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -529,7 +529,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { - if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index fc0cc87ca..7f3a667a9 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -13,6 +13,7 @@ import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../../fields import { WebField } from '../../../../fields/URLField'; import { aggregateBounds, Utils } from '../../../../Utils'; import { DocumentType } from '../../../documents/DocumentTypes'; +import { CurrentUserUtils } from '../../../util/CurrentUserUtils'; import { DocumentManager } from '../../../util/DocumentManager'; import { ScriptingGlobals } from "../../../util/ScriptingGlobals"; import { SelectionManager } from '../../../util/SelectionManager'; @@ -717,64 +718,56 @@ ScriptingGlobals.add(function setActiveInkTool(tool: string, checkResult?: boole // easy way without backing up to the server // - CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => { - const selected = ffView.unprocessedDocs; - ffView._marqueeViewRef.current?.getCollection(ffView.unprocessedDocs, undefined, [], true); - // loop through selected an get the bound - const bounds: { x: number, y: number, width?: number, height?: number }[] = [] - - selected.map(action(d => { - const x = NumCast(d.x); - const y = NumCast(d.y); - const width = d[WidthSym](); - const height = d[HeightSym](); - bounds.push({x, y, width, height}); - })) - - const aggregBounds = aggregateBounds(bounds, 0, 0); - const marqViewRef = ffView._marqueeViewRef.current; - - // set the vals for bounds in marqueeView - if (marqViewRef) { - marqViewRef._downX = aggregBounds.x; - marqViewRef._downY = aggregBounds.y; - marqViewRef._lastX = aggregBounds.r; - marqViewRef._lastY = aggregBounds.b; - } - - selected.map(action(d => { - const dx = NumCast(d.x); - const dy = NumCast(d.y); - delete d.x; - delete d.y; - delete d.activeFrame; - delete d._timecodeToShow; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection - delete d._timecodeToHide; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection - // TODO: nda - actually calc the bounds - // get the bounds - // d.x = dx - aggregBounds.x; - // d.y = dy - aggregBounds.y; + if (CurrentUserUtils.SelectedTool === InkTool.Write) { + CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => { + const selected = ffView.unprocessedDocs; + // loop through selected an get the bound + const bounds: { x: number, y: number, width?: number, height?: number }[] = [] - // d.x = dx - aggregBounds.x ; - // d.y = dy; - if (marqViewRef?.Bounds) { - d.x = dx - marqViewRef.Bounds.left - marqViewRef.Bounds?.width / 2; - d.y = dy - marqViewRef.Bounds.top - marqViewRef.Bounds.height / 2; - } - console.log(d[DataSym], d.x, d.y) - return d; - })); - ffView.props.removeDocument?.(selected); - // TODO: nda - this is the code to actually get a new grouped collection - // const newCollection = ffView._marqueeViewRef.current?.getCollection(ffView.unprocessedDocs, undefined, [], true); - const newCollection = marqViewRef?.getCollection(selected, undefined, [], true); - console.log("newcoll:", newCollection?.[DataSym]); - - // nda - bug: when deleting a stroke before leaving writing mode, delete the stroke from unprocessed ink docs - newCollection && ffView.props.addDocument?.(newCollection); - ffView.unprocessedDocs = []; - }); - + selected.map(action(d => { + const x = NumCast(d.x); + const y = NumCast(d.y); + const width = d[WidthSym](); + const height = d[HeightSym](); + bounds.push({x, y, width, height}); + })) + + const aggregBounds = aggregateBounds(bounds, 0, 0); + const marqViewRef = ffView._marqueeViewRef.current; + + // set the vals for bounds in marqueeView + if (marqViewRef) { + marqViewRef._downX = aggregBounds.x; + marqViewRef._downY = aggregBounds.y; + marqViewRef._lastX = aggregBounds.r; + marqViewRef._lastY = aggregBounds.b; + } + + selected.map(action(d => { + const dx = NumCast(d.x); + const dy = NumCast(d.y); + delete d.x; + delete d.y; + delete d.activeFrame; + delete d._timecodeToShow; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection + delete d._timecodeToHide; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection + // TODO: nda - actually calc the bounds + // calculate pos based on bounds + if (marqViewRef?.Bounds) { + d.x = dx - marqViewRef.Bounds.left - marqViewRef.Bounds.width / 2; + d.y = dy - marqViewRef.Bounds.top - marqViewRef.Bounds.height / 2; + } + return d; + })); + ffView.props.removeDocument?.(selected); + // TODO: nda - this is the code to actually get a new grouped collection + const newCollection = marqViewRef?.getCollection(selected, undefined, [], true); + + // nda - bug: when deleting a stroke before leaving writing mode, delete the stroke from unprocessed ink docs + newCollection && ffView.props.addDocument?.(newCollection); + ffView.unprocessedDocs = []; + }); + } CollectionFreeFormView.collectionsWithUnprocessedInk.clear(); if (checkResult) { @@ -793,8 +786,9 @@ ScriptingGlobals.add(function setActiveInkTool(tool: string, checkResult?: boole if (Doc.UserDoc().activeInkTool === tool && !GestureOverlay.Instance.InkShape) { Doc.UserDoc().activeInkTool = InkTool.None; } else if (tool == "write") { - console.log("write mode selected - create groupDoc here!") - // + console.log("write mode selected - create groupDoc here!", tool) + Doc.UserDoc().activeInkTool = tool; + GestureOverlay.Instance.InkShape = ""; } else { Doc.UserDoc().activeInkTool = tool; GestureOverlay.Instance.InkShape = ""; diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 1856c5353..37fbd7a1d 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -371,7 +371,7 @@ export class PDFViewer extends React.Component { if ((e.button !== 0 || e.altKey) && this.props.isContentActive(true)) { this._setPreviewCursor?.(e.clientX, e.clientY, true, false); } - if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { this.props.select(false); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; diff --git a/src/fields/InkField.ts b/src/fields/InkField.ts index 31024e805..c34e8f93d 100644 --- a/src/fields/InkField.ts +++ b/src/fields/InkField.ts @@ -11,7 +11,8 @@ export enum InkTool { Pen = "pen", Highlighter = "highlighter", Eraser = "eraser", - Stamp = "stamp" + Stamp = "stamp", + Write = "write" } diff --git a/webpack.config.js b/webpack.config.js index 3fd00bcf3..5a954db19 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -49,7 +49,7 @@ module.exports = { repl: ["./src/debug/Repl.tsx", 'webpack-hot-middleware/client?reload=true'], test: ["./src/debug/Test.tsx", 'webpack-hot-middleware/client?reload=true'], inkControls: ["./src/mobile/InkControls.tsx", 'webpack-hot-middleware/client?reload=true'], - mobileInterface: ["./src/mobile/MobileMain.tsx", 'webpack-hot-middleware/client?reload=true'], + mobileInterface: ["./src/client/views/Main.tsx", 'webpack-hot-middleware/client?reload=true'], }, devtool: "source-map", output: { -- cgit v1.2.3-70-g09d2 From fd58a5f8598815ab1ab3893e60973654a59a52c1 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 12 Apr 2022 10:54:28 -0400 Subject: cleaned up errors/warnings. fixed dragging to turn off pointer events on whatever's being dragged. --- src/client/util/DocumentManager.ts | 10 ++++++---- src/client/util/DragManager.ts | 2 +- src/client/views/StyleProvider.tsx | 4 +++- src/client/views/collections/CollectionDockingView.tsx | 4 ++-- .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 4 ++-- src/client/views/nodes/LabelBox.tsx | 7 +------ src/client/views/nodes/PDFBox.tsx | 6 +++--- src/client/views/nodes/VideoBox.tsx | 2 +- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 2 +- 10 files changed, 21 insertions(+), 22 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 6076de055..1d603e18f 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -169,10 +169,12 @@ export class DocumentManager { const getFirstDocView = LightboxView.LightboxDoc ? DocumentManager.Instance.getLightboxDocumentView : DocumentManager.Instance.getFirstDocumentView; const docView = getFirstDocView(targetDoc, originatingDoc); const wasHidden = targetDoc.hidden; // - if (wasHidden) runInAction(() => { - targetDoc.hidden = false; - docView?.props.bringToFront(targetDoc); - }); // if the target is hidden, un-hide it here. + if (wasHidden) { + runInAction(() => { + targetDoc.hidden = false; + docView?.props.bringToFront(targetDoc); + }); // if the target is hidden, un-hide it here. + } const focusAndFinish = (didFocus: boolean) => { if (originatingDoc?.isPushpin) { if (!didFocus && !wasHidden) { // don't toggle the hidden state if the doc was already un-hidden as part of this document traversal diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 94a09eac4..13e5940d6 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -405,7 +405,7 @@ export namespace DragManager { Array.from(pdfBox).filter(pb => pb.width && pb.height).map((pb, i) => pb.getContext('2d')!.drawImage(pdfBoxSrc[i], 0, 0)); } [dragElement, ...Array.from(dragElement.getElementsByTagName('*'))].forEach(ele => - ele.hasAttribute("style") && ((ele as any).style.pointerEvents = "none")); + (ele as any).style && ((ele as any).style.pointerEvents = "none")); dragDiv.appendChild(dragElement); if (dragElement !== ele) { diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 2ce78f64f..9803f9782 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -149,7 +149,9 @@ export function DefaultStyleProvider(doc: Opt, props: Opt 0 ? Doc.UserDoc().activeCollectionNestedBackground : - Doc.UserDoc().activeCollectionBackground ?? (darkScheme() ? Colors.BLACK : Colors.WHITE)) + Doc.UserDoc().activeCollectionBackground ?? (darkScheme() ? + Colors.BLACK : + "linear-gradient(#065fff, #85c1f9)")) )); break; //if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "rgb(62,62,62)"; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 6931d9896..e95371aaa 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -92,7 +92,7 @@ export class CollectionDockingView extends CollectionSubView() { DragManager.CompleteWindowDrag = undefined; } finishDrag?.(aborted); - } + }; } @undoBatch public CloseFullScreen = () => { @@ -316,7 +316,7 @@ export class CollectionDockingView extends CollectionSubView() { } this._goldenLayout.init(); this._goldenLayout.root.layoutManager.on('itemDropped', this.tabItemDropped); - this._goldenLayout.root.layoutManager.on('dragStart', this.tabDragStart) + this._goldenLayout.root.layoutManager.on('dragStart', this.tabDragStart); this._goldenLayout.root.layoutManager.on('activeContentItemChanged', this.stateChanged); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 04beed541..9b0acffdf 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1417,7 +1417,7 @@ export class CollectionFreeFormView extends CollectionSubView { this.props.docViewPath().lastElement().ContentDiv!.style.width = (this.layoutDoc[WidthSym]()).toString(); this.props.docViewPath().lastElement().ContentDiv!.style.height = (this.layoutDoc[HeightSym]()).toString(); - var htmlString = this._mainCont && new XMLSerializer().serializeToString(this.props.docViewPath().lastElement().ContentDiv!); + const htmlString = this._mainCont && new XMLSerializer().serializeToString(this.props.docViewPath().lastElement().ContentDiv!); this.props.docViewPath().lastElement().ContentDiv!.style.width = ""; this.props.docViewPath().lastElement().ContentDiv!.style.height = ""; const nativeWidth = this.layoutDoc[WidthSym](); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 7fb2c235a..3e35039e3 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -168,8 +168,8 @@ export class CollectionFreeFormDocumentView extends DocComponent m + ":").join(" ") + ")") render() { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 3f1771e68..c73823a2b 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -63,7 +63,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { - const title = StrCast(this.dataDoc.title) + const title = StrCast(this.dataDoc.title); if (!this.props.dontRegisterView && // (this.props.Document.isTemplateForField === "text" || !this.props.Document.isTemplateForField) && // only update the title if the data document's data field is changing (title.startsWith("-") || title.startsWith("@")) && this._editorView && !this.dataDoc["title-custom"] && (Doc.LayoutFieldKey(this.rootDoc) === this.fieldKey || this.fieldKey === "text")) { -- cgit v1.2.3-70-g09d2 From 5f297a17b38bdcd4d3928137daacf14fe2fbec9f Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 25 Apr 2022 21:45:20 -0400 Subject: put snapshot dash in novice mode. fixed undo for snapshot/new dashboard. changed titling of snapshots to use {#}. no current UI for cloning dashboards. --- src/Utils.ts | 6 +++++ .../views/collections/CollectionDockingView.tsx | 7 +++--- src/client/views/topbar/TopBar.tsx | 26 +++++++++++++--------- src/fields/Doc.ts | 7 ++++-- 4 files changed, 30 insertions(+), 16 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index d1d400de7..38eb51529 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -399,6 +399,12 @@ export function timenow() { return now.toLocaleDateString() + ' ' + h + ':' + m + ' ' + ampm; } +export function incrementTitleCopy(title: string) { + const numstr = title.match(/.*(\{([0-9]*)\})+/); + const copyNumStr = `{${1 + (numstr ? (+numstr[2]) : 0)}}`; + return (numstr ? title.replace(numstr[1], "") : title) + copyNumStr; +} + export function formatTime(time: number) { time = Math.round(time); const hours = Math.floor(time / 60 / 60); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index e95371aaa..64a5f38d4 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -11,7 +11,7 @@ import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { inheritParentAcls } from '../../../fields/util'; -import { emptyFunction } from '../../../Utils'; +import { emptyFunction, incrementTitleCopy } from '../../../Utils'; import { DocServer } from "../../DocServer"; import { Docs } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; @@ -390,7 +390,6 @@ export class CollectionDockingView extends CollectionSubView() { } public static async Copy(doc: Doc, clone = false) { - clone = !Doc.UserDoc().noviceMode; let json = StrCast(doc.dockingConfig); if (clone) { const cloned = (await Doc.MakeClone(doc)); @@ -403,13 +402,13 @@ export class CollectionDockingView extends CollectionSubView() { const origtabs = origtabids.map(id => DocServer.GetCachedRefField(id)).filter(f => f).map(f => f as Doc); const newtabs = origtabs.map(origtab => { const origtabdocs = DocListCast(origtab.data); - const newtab = origtabdocs.length ? Doc.MakeCopy(origtab, true) : Doc.MakeAlias(origtab); + const newtab = origtabdocs.length ? Doc.MakeCopy(origtab, true, undefined, true) : Doc.MakeAlias(origtab); const newtabdocs = origtabdocs.map(origtabdoc => Doc.MakeAlias(origtabdoc)); newtabdocs.length && (Doc.GetProto(newtab).data = new List(newtabdocs)); json = json.replace(origtab[Id], newtab[Id]); return newtab; }); - return Docs.Create.DockDocument(newtabs, json, { title: "Snapshot: " + doc.title }); + return Docs.Create.DockDocument(newtabs, json, { title: incrementTitleCopy(StrCast(doc.title)) }); } @action diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index d5254e315..0af7de6af 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -7,7 +7,7 @@ import { StrCast } from '../../../fields/Types'; import { Utils } from '../../../Utils'; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; import { SettingsManager } from "../../util/SettingsManager"; -import { undoBatch } from "../../util/UndoManager"; +import { undoBatch, UndoManager } from "../../util/UndoManager"; import { Borders, Colors } from "../global/globalEnums"; import "./TopBar.scss"; @@ -33,30 +33,36 @@ export class TopBar extends React.Component {
- CurrentUserUtils.openDashboard(Doc.UserDoc(), myDashboards[Number(e.target.value)]))} value={myDashboards.indexOf(CurrentUserUtils.ActiveDashboard)} style={{ color: Colors.WHITE }}> {myDashboards.map((dash, i) => )}
-
CurrentUserUtils.createNewDashboard(Doc.UserDoc()))} - > - {"New"} +
{ + const batch = UndoManager.StartBatch("new dash"); + await CurrentUserUtils.createNewDashboard(Doc.UserDoc()); + batch.end(); + }}> + {"New"}
- {Doc.UserDoc().noviceMode ? (null) :
CurrentUserUtils.snapshotDashboard(Doc.UserDoc()))} - > - {"Snapshot"} + {
{ + const batch = UndoManager.StartBatch("snapshot"); + await CurrentUserUtils.snapshotDashboard(Doc.UserDoc()); + batch.end(); + }}> + {"Snapshot"}
}
window.open( "https://brown-dash.github.io/Dash-Documentation/", "_blank")}> - {"Help"} + {"Help"}
SettingsManager.Instance.open()}> - {"Settings"} + {"Settings"}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 63af8401c..50e5fcbc4 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -11,7 +11,7 @@ import { scriptingGlobal, ScriptingGlobals } from "../client/util/ScriptingGloba import { SelectionManager } from "../client/util/SelectionManager"; import { afterDocDeserialize, autoObject, Deserializable, SerializationHelper } from "../client/util/SerializationHelper"; import { UndoManager } from "../client/util/UndoManager"; -import { DashColor, intersectRect, Utils } from "../Utils"; +import { DashColor, incrementTitleCopy, intersectRect, Utils } from "../Utils"; import { DateField } from "./DateField"; import { Copy, HandleUpdate, Id, OnUpdate, Parent, Self, SelfProxy, ToScriptString, ToString, Update } from "./FieldSymbols"; import { List } from "./List"; @@ -770,7 +770,7 @@ export namespace Doc { return overwrite; } - export function MakeCopy(doc: Doc, copyProto: boolean = false, copyProtoId?: string): Doc { + export function MakeCopy(doc: Doc, copyProto: boolean = false, copyProtoId?: string, retitle = false): Doc { const copy = new Doc(copyProtoId, true); const exclude = Cast(doc.cloneFieldFilter, listSpec("string"), []); Object.keys(doc).forEach(key => { @@ -806,6 +806,9 @@ export namespace Doc { } copy.context = undefined; Doc.UserDoc().defaultAclPrivate && (copy["acl-Public"] = "Not Shared"); + if (retitle) { + copy.title = incrementTitleCopy(StrCast(copy.title)); + } return copy; } -- cgit v1.2.3-70-g09d2 From 09c7ee4120f48e212f9b64fd3e307c8ce49e0cfd Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 16 May 2022 19:33:08 -0400 Subject: fixed snapshot to set 'context' of new aliases. --- src/client/views/collections/CollectionDockingView.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 64a5f38d4..30f60bba6 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -404,7 +404,10 @@ export class CollectionDockingView extends CollectionSubView() { const origtabdocs = DocListCast(origtab.data); const newtab = origtabdocs.length ? Doc.MakeCopy(origtab, true, undefined, true) : Doc.MakeAlias(origtab); const newtabdocs = origtabdocs.map(origtabdoc => Doc.MakeAlias(origtabdoc)); - newtabdocs.length && (Doc.GetProto(newtab).data = new List(newtabdocs)); + if (newtabdocs.length) { + Doc.GetProto(newtab).data = new List(newtabdocs); + newtabdocs.forEach(ntab => ntab.context = newtab); + } json = json.replace(origtab[Id], newtab[Id]); return newtab; }); -- cgit v1.2.3-70-g09d2 From d50b851d8e92797d214fc35cf243bfb29e970b36 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 23 May 2022 21:58:26 -0400 Subject: simplified dashboards by getting rid of confusing on-screen/off-screen tabs. Now off screen tabs appear in the header bar which is not currently specific to a dashboard. --- src/client/documents/Documents.ts | 4 +- src/client/util/CurrentUserUtils.ts | 33 +-------------- src/client/views/MainView.tsx | 4 +- .../views/collections/CollectionDockingView.tsx | 48 +++++++++++++++++----- src/client/views/collections/TabDocView.tsx | 3 +- 5 files changed, 43 insertions(+), 49 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 6fa467368..c3b6953b5 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -905,9 +905,7 @@ export namespace Docs { } export function DockDocument(documents: Array, config: string, options: DocumentOptions, id?: string) { - const tabs = TreeDocument(documents, { title: "On-Screen Tabs", childDontRegisterViews: true, freezeChildren: "remove|add", treeViewExpandedViewLock: true, treeViewExpandedView: "data", _fitWidth: true, system: true, isFolder: true }); - const all = TreeDocument([], { title: "Off-Screen Tabs", childDontRegisterViews: true, freezeChildren: "add", treeViewExpandedViewLock: true, treeViewExpandedView: "data", system: true, isFolder: true }); - return InstanceFromProto(Prototypes.get(DocumentType.COL), new List([tabs, all]), { freezeChildren: "remove|add", ...options, _viewType: CollectionViewType.Docking, dockingConfig: config }, id); + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { freezeChildren: "remove|add", ...options, _viewType: CollectionViewType.Docking, dockingConfig: config }, id); } export function DirectoryImportDocument(options: DocumentOptions = {}) { diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 1e42b9073..9212d8ed9 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1172,22 +1172,8 @@ export class CurrentUserUtils { freeformDoc.context = dashboardDoc; // switching the tabs from the datadoc to the regular doc - const dashboardTabs = dashboardDoc[DataSym].data; - dashboardDoc[DataSym].data = new List(); - dashboardDoc.data = dashboardTabs; - - // collating all docs on the dashboard to make a data-all field - const allDocs = new List(); - const allDocs2 = new List(); // Array.from, spread, splice all cause so stack or acl issues for some reason - DocListCast(dashboardTabs).forEach(doc => { - const tabDocs = DocListCast(doc.data); - allDocs.push(...tabDocs); - allDocs2.push(...tabDocs); - }); - dashboardDoc[DataSym]["data-all"] = allDocs; - dashboardDoc["data-all"] = allDocs2; - DocListCast(dashboardDoc.data).forEach(doc => doc.dashboard = dashboardDoc); - DocListCast(dashboardDoc.data)[1].data = ComputedField.MakeFunction(`dynamicOffScreenDocs(self.dashboard)`) as any; + const dashboardTabs = DocListCast(dashboardDoc[DataSym].data); + dashboardDoc.data = new List(dashboardTabs); userDoc.activePresentation = presentation; @@ -1258,21 +1244,6 @@ ScriptingGlobals.add(function addToDashboards(dashboard: Doc) { }, "adds Dashboard to set of Dashboards"); -/** - * Dynamically computes which docs should be rendered in the off-screen tabs tree of a dashboard. - */ -ScriptingGlobals.add(function dynamicOffScreenDocs(dashboard: Doc) { - if (dashboard[DataSym] instanceof Doc) { - const allDocs = DocListCast(dashboard["data-all"]); - const onScreenTab = DocListCast(dashboard.data)[0]; - const onScreenDocs = DocListCast(onScreenTab.data); - return new List(allDocs.reduce((result: Doc[], doc) => { - !onScreenDocs.includes(doc) && !onScreenDocs.includes(doc.aliasOf as Doc) && (result.push(doc)); - return result; - }, [])); - } - return []; -}); ScriptingGlobals.add(function selectedDocumentType(docType?: DocumentType, colType?: CollectionViewType, checkParent?: boolean) { let selected = SelectionManager.Docs().length ? SelectionManager.Docs()[0] : undefined; if (selected && checkParent) { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 69e394790..f3dc2cf85 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -92,7 +92,7 @@ export class MainView extends React.Component { @computed private get headerBarDoc() { return this.userDoc ? CurrentUserUtils.MyHeaderBarDoc : CurrentUserUtils.MyHeaderBarDoc; } @computed public get mainFreeform(): Opt { return (docs => (docs?.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); } - headerBarDocWidth = () => this._dashUIWidth; + headerBarDocWidth = () => this.mainDocViewWidth(); headerBarDocHeight = () => CurrentUserUtils.headerBarHeight ?? 0; topMenuHeight = () => 35; topMenuWidth = returnZero; // value is ignored ... @@ -102,7 +102,7 @@ export class MainView extends React.Component { leftMenuFlyoutHeight = () => this._dashUIHeight; propertiesWidth = () => Math.max(0, Math.min(this._dashUIWidth - 50, CurrentUserUtils.propertiesWidth || 0)); propertiesHeight = () => this._dashUIHeight; - mainDocViewWidth = () => this._dashUIWidth - this.propertiesWidth() - this.leftMenuWidth(); + mainDocViewWidth = () => this._dashUIWidth - this.propertiesWidth() - this.leftMenuWidth() - this.leftMenuFlyoutWidth(); mainDocViewHeight = () => this._dashUIHeight - this.headerBarDocHeight(); componentDidMount() { diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 30f60bba6..1d65256a6 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -81,6 +81,8 @@ export class CollectionDockingView extends CollectionSubView() { tabItemDropped = () => DragManager.CompleteWindowDrag?.(false); tabDragStart = (proxy: any, finishDrag?: (aborted: boolean) => void) => { + const dashDoc = proxy?._contentItem?.tab?.DashDoc as Doc; + dashDoc && (DragManager.DocDragData = new DragManager.DocumentDragData([proxy._contentItem.tab.DashDoc])); DragManager.CompleteWindowDrag = (aborted: boolean) => { if (aborted) { proxy._dragListener.AbortDrag(); @@ -90,6 +92,8 @@ export class CollectionDockingView extends CollectionSubView() { this.setupGoldenLayout(); // restore golden layout to where it was before the drag (this is a no-op when using StartOtherDrag because the proxy dragged item was never in the golden layout) } DragManager.CompleteWindowDrag = undefined; + } else { + DragManager.DocDragData?.droppedDocuments.forEach(doc => this.addToTabDocList(doc)); } finishDrag?.(aborted); }; @@ -100,12 +104,43 @@ export class CollectionDockingView extends CollectionSubView() { this.stateChanged(); } + addToTabDocList = (document: Doc) => { + const instance = CollectionDockingView.Instance; + if (instance) { + const docList = DocListCast(instance.props.Document[DataSym].data); + // adds the doc of the newly created tab to the data-all field if it doesn't already include that doc or one of its aliases + !docList.includes(document) && !docList.includes(document.aliasOf as Doc) && Doc.AddDocToList(instance.props.Document[DataSym], "data", document); + // adds an alias of the doc to the data-all field of the layoutdocs of the aliases + DocListCast(instance.props.Document.aliases).forEach(alias => { + const aliasDocList = DocListCast(alias.data); + // if aliasDocList contains the alias, don't do anything + // otherwise add the original or an alias depending on whether the doc you're looking at is the current doc or a different alias + !DocListCast(document.aliases).some(a => aliasDocList.includes(a)) && Doc.AddDocToList(alias, "data", document);//alias !== instance.props.Document ? Doc.MakeAlias(document) : document); + }); + } + } + removeFromTabDocList = (document: Doc) => { + const instance = CollectionDockingView.Instance; + if (instance) { + // adds the doc of the newly created tab to the data-all field if it doesn't already include that doc or one of its aliases + Doc.RemoveDocFromList(instance.props.Document[DataSym], "data", document); + // adds an alias of the doc to the data-all field of the layoutdocs of the aliases + DocListCast(instance.props.Document.aliases).forEach(alias => { + // if aliasDocList contains the alias, don't do anything + // otherwise add the original or an alias depending on whether the doc you're looking at is the current doc or a different alias + Doc.RemoveDocFromList(alias, "data", document);//alias !== instance.props.Document ? Doc.MakeAlias(document) : document); + }); + document.type !== DocumentType.KVP && Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", document); + } + } + @undoBatch public static CloseSplit(document: Opt, panelName?: string): boolean { const tab = Array.from(CollectionDockingView.Instance.tabMap.keys()).find((tab) => panelName ? tab.contentItem.config.props.panelName === panelName : tab.DashDoc === document); if (tab) { const j = tab.header.parent.contentItems.indexOf(tab.contentItem); if (j !== -1) { + CollectionDockingView.Instance.removeFromTabDocList(tab.dashDoc as Doc); tab.header.parent.contentItems[j].remove(); return CollectionDockingView.Instance.layoutChanged(); } @@ -185,16 +220,7 @@ export class CollectionDockingView extends CollectionSubView() { const instance = CollectionDockingView.Instance; if (!instance) return false; else { - const docList = DocListCast(instance.props.Document[DataSym]["data-all"]); - // adds the doc of the newly created tab to the data-all field if it doesn't already include that doc or one of its aliases - !docList.includes(document) && !docList.includes(document.aliasOf as Doc) && Doc.AddDocToList(instance.props.Document[DataSym], "data-all", document); - // adds an alias of the doc to the data-all field of the layoutdocs of the aliases - DocListCast(instance.props.Document[DataSym].aliases).forEach(alias => { - const aliasDocList = DocListCast(alias["data-all"]); - // if aliasDocList contains the alias, don't do anything - // otherwise add the original or an alias depending on whether the doc you're looking at is the current doc or a different alias - !DocListCast(document.aliases).some(a => aliasDocList.includes(a)) && Doc.AddDocToList(alias, "data-all", document);//alias !== instance.props.Document ? Doc.MakeAlias(document) : document); - }); + instance.addToTabDocList(document); } const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName); @@ -477,7 +503,7 @@ export class CollectionDockingView extends CollectionSubView() { //if (confirm('really close this?')) { if (!stack.parent.parent.isRoot || stack.parent.contentItems.length > 1) { stack.remove(); - stack.contentItems.forEach((contentItem: any) => Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", contentItem.tab.DashDoc, undefined, true, true)); + stack.contentItems.forEach((contentItem: any) => CollectionDockingView.Instance.removeFromTabDocList(contentItem.tab.DashDoc)); } else { alert('cant delete the last stack'); } diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 0070d0b9d..88d14fdfe 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -180,8 +180,7 @@ export class TabDocView extends React.Component { tab.closeElement.off('click') //unbind the current click handler .click(function () { Object.values(tab._disposers).forEach((disposer: any) => disposer?.()); - Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", doc); - Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", doc, undefined, true, true); + CollectionDockingView.Instance?.removeFromTabDocList(doc); SelectionManager.DeselectAll(); UndoManager.RunInBatch(() => tab.contentItem.remove(), "delete tab"); }); -- cgit v1.2.3-70-g09d2 From 76d737a05093e4132f2ab56630c4003879747ef9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 26 May 2022 15:36:32 -0400 Subject: removed setting 'data' field of docking views on aliases. assigned acl's to delegates to match prototype. changed how documents are created to make sure acl's are set first so that, when sharing, remote clients will get the ACLs first and not render documents transiently when they don't have permissions. turned off inheriting ACL's from outer collection --- src/client/documents/Documents.ts | 15 +++++++++------ src/client/util/CurrentUserUtils.ts | 3 --- src/client/views/collections/CollectionDockingView.tsx | 17 ++--------------- src/client/views/global/globalCssVariables.scss | 2 +- src/fields/Doc.ts | 1 + src/fields/util.ts | 3 ++- 6 files changed, 15 insertions(+), 26 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index ed37c48dc..8d29bcebe 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -639,13 +639,14 @@ export namespace Docs { const viewKeys = ["x", "y", "system"]; // keys that should be addded to the view document even though they don't begin with an "_" const { omit: dataProps, extract: viewProps } = OmitKeys(options, viewKeys, "^_"); + dataProps["acl-Override"] = "None"; + dataProps["acl-Public"] = options["acl-Public"] ? options["acl-Public"] : Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; + dataProps.system = viewProps.system; dataProps.isPrototype = true; dataProps.author = Doc.CurrentUserEmail; dataProps.creationDate = new DateField; dataProps[`${fieldKey}-lastModified`] = new DateField; - dataProps["acl-Override"] = "None"; - dataProps["acl-Public"] = options["acl-Public"] ? options["acl-Public"] : Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; dataProps[fieldKey] = data; @@ -654,10 +655,12 @@ export namespace Docs { dataProps[fieldKey + "-annotations"] = new List(); const dataDoc = Doc.assign(Doc.MakeDelegate(proto, protoId), dataProps, undefined, true); - viewProps.author = Doc.CurrentUserEmail; - viewProps["acl-Override"] = "None"; - viewProps["acl-Public"] = options["_acl-Public"] ? options["_acl-Public"] : Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; - const viewDoc = Doc.assign(Doc.MakeDelegate(dataDoc, delegId), viewProps, true, true); + const viewFirstProps: { [id: string]: any } = {}; + viewFirstProps["acl-Public"] = options["_acl-Public"] ? options["_acl-Public"] : Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; + viewFirstProps["acl-Override"] = "None"; + viewFirstProps.author = Doc.CurrentUserEmail; + const viewDoc = Doc.assign(Doc.MakeDelegate(dataDoc, delegId), viewFirstProps, true, true); + Doc.assign(viewDoc, viewProps, true, true); ![DocumentType.LINK, DocumentType.MARKER, DocumentType.LABEL].includes(viewDoc.type as any) && DocUtils.MakeLinkToActiveAudio(() => viewDoc); !Doc.IsSystem(dataDoc) && ![DocumentType.MARKER, DocumentType.KVP, DocumentType.LINK, DocumentType.LINKANCHOR].includes(proto.type as any) && diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 436237d6c..083530ce7 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1236,9 +1236,6 @@ ScriptingGlobals.add(async function removeDashboard(dashboard: Doc) { "Remove Dashboard from Dashboards"); ScriptingGlobals.add(function addToDashboards(dashboard: Doc) { const dashboardAlias = Doc.MakeAlias(dashboard); - dashboardAlias.data = new List(DocListCast(dashboard.data).map(tabFolder => Doc.MakeAlias(tabFolder))); - DocListCast(dashboardAlias.data).forEach(doc => doc.dashboard = dashboardAlias); - DocListCast(dashboardAlias.data)[1].data = ComputedField.MakeFunction(`dynamicOffScreenDocs(self.dashboard)`) as any; Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", dashboardAlias); CurrentUserUtils.openDashboard(Doc.UserDoc(), dashboardAlias); }, diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 1d65256a6..c60434d95 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -109,27 +109,14 @@ export class CollectionDockingView extends CollectionSubView() { if (instance) { const docList = DocListCast(instance.props.Document[DataSym].data); // adds the doc of the newly created tab to the data-all field if it doesn't already include that doc or one of its aliases - !docList.includes(document) && !docList.includes(document.aliasOf as Doc) && Doc.AddDocToList(instance.props.Document[DataSym], "data", document); - // adds an alias of the doc to the data-all field of the layoutdocs of the aliases - DocListCast(instance.props.Document.aliases).forEach(alias => { - const aliasDocList = DocListCast(alias.data); - // if aliasDocList contains the alias, don't do anything - // otherwise add the original or an alias depending on whether the doc you're looking at is the current doc or a different alias - !DocListCast(document.aliases).some(a => aliasDocList.includes(a)) && Doc.AddDocToList(alias, "data", document);//alias !== instance.props.Document ? Doc.MakeAlias(document) : document); - }); + !docList.includes(document) && !docList.includes(document.aliasOf as Doc) && Doc.AddDocToList(instance.props.Document, "data", document); } } removeFromTabDocList = (document: Doc) => { const instance = CollectionDockingView.Instance; if (instance) { // adds the doc of the newly created tab to the data-all field if it doesn't already include that doc or one of its aliases - Doc.RemoveDocFromList(instance.props.Document[DataSym], "data", document); - // adds an alias of the doc to the data-all field of the layoutdocs of the aliases - DocListCast(instance.props.Document.aliases).forEach(alias => { - // if aliasDocList contains the alias, don't do anything - // otherwise add the original or an alias depending on whether the doc you're looking at is the current doc or a different alias - Doc.RemoveDocFromList(alias, "data", document);//alias !== instance.props.Document ? Doc.MakeAlias(document) : document); - }); + Doc.RemoveDocFromList(instance.props.Document, "data", document); document.type !== DocumentType.KVP && Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", document); } } diff --git a/src/client/views/global/globalCssVariables.scss b/src/client/views/global/globalCssVariables.scss index 520ac9357..a14634bdc 100644 --- a/src/client/views/global/globalCssVariables.scss +++ b/src/client/views/global/globalCssVariables.scss @@ -10,7 +10,7 @@ $black: #000000; $light-blue: #bdddf5; $light-blue-transparent: #bdddf590; $medium-blue: #4476f7; -$medium-blue-alt: #4476f73d; +$medium-blue-alt: #0047ff54; $pink: #e0217d; $yellow: #f5d747; diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 194b3ba27..b0a45091e 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -821,6 +821,7 @@ export namespace Doc { delegate[Initializing] = true; delegate.proto = doc; delegate.author = Doc.CurrentUserEmail; + Object.keys(doc).filter(key => key.startsWith("acl")).forEach(key => delegate[key] = doc[key]); if (!Doc.IsSystem(doc)) Doc.AddDocToList(doc[DataSym], "aliases", delegate); title && (delegate.title = title); delegate[Initializing] = false; diff --git a/src/fields/util.ts b/src/fields/util.ts index ef5ac79b8..d1e565774 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -138,6 +138,7 @@ export function denormalizeEmail(email: string) { * Copies parent's acl fields to the child */ export function inheritParentAcls(parent: Doc, child: Doc) { + return; const dataDoc = parent[DataSym]; for (const key of Object.keys(dataDoc)) { // if the default acl mode is private, then don't inherit the acl-Public permission, but set it to private. @@ -177,7 +178,7 @@ const getEffectiveAclCache = computedFn(function (target: any, user?: string) { export function GetEffectiveAcl(target: any, user?: string): symbol { if (!target) return AclPrivate; if (target[UpdatingFromServer]) return AclAdmin; - // authored documents are private until an ACL is set. this also fixes notes that flicker on and off when a remote types to create a private note into a shared collection. + // authored documents are private until an ACL is set. if (!target[AclSym] && target.author && target.author !== Doc.CurrentUserEmail) return AclPrivate; return getEffectiveAclCache(target, user);// all changes received from the server must be processed as Admin. return this directly so that the acls aren't cached (UpdatingFromServer is not observable) } -- cgit v1.2.3-70-g09d2 From ddd38f923180efd0dc4f53a1c3caad4a1f9ed26f Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 26 May 2022 17:40:54 -0400 Subject: removed more code relating to old version of dashboards with on and off screen tab lists. fixed schema headers to not iconify when typing Enter in header field name. --- .../views/collections/CollectionDockingView.tsx | 47 +--------------------- src/client/views/collections/TabDocView.tsx | 1 - .../collectionSchema/CollectionSchemaHeaders.tsx | 5 ++- 3 files changed, 6 insertions(+), 47 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index c60434d95..509da18cb 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -92,8 +92,6 @@ export class CollectionDockingView extends CollectionSubView() { this.setupGoldenLayout(); // restore golden layout to where it was before the drag (this is a no-op when using StartOtherDrag because the proxy dragged item was never in the golden layout) } DragManager.CompleteWindowDrag = undefined; - } else { - DragManager.DocDragData?.droppedDocuments.forEach(doc => this.addToTabDocList(doc)); } finishDrag?.(aborted); }; @@ -104,30 +102,12 @@ export class CollectionDockingView extends CollectionSubView() { this.stateChanged(); } - addToTabDocList = (document: Doc) => { - const instance = CollectionDockingView.Instance; - if (instance) { - const docList = DocListCast(instance.props.Document[DataSym].data); - // adds the doc of the newly created tab to the data-all field if it doesn't already include that doc or one of its aliases - !docList.includes(document) && !docList.includes(document.aliasOf as Doc) && Doc.AddDocToList(instance.props.Document, "data", document); - } - } - removeFromTabDocList = (document: Doc) => { - const instance = CollectionDockingView.Instance; - if (instance) { - // adds the doc of the newly created tab to the data-all field if it doesn't already include that doc or one of its aliases - Doc.RemoveDocFromList(instance.props.Document, "data", document); - document.type !== DocumentType.KVP && Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", document); - } - } - @undoBatch public static CloseSplit(document: Opt, panelName?: string): boolean { const tab = Array.from(CollectionDockingView.Instance.tabMap.keys()).find((tab) => panelName ? tab.contentItem.config.props.panelName === panelName : tab.DashDoc === document); if (tab) { const j = tab.header.parent.contentItems.indexOf(tab.contentItem); if (j !== -1) { - CollectionDockingView.Instance.removeFromTabDocList(tab.dashDoc as Doc); tab.header.parent.contentItems[j].remove(); return CollectionDockingView.Instance.layoutChanged(); } @@ -206,9 +186,6 @@ export class CollectionDockingView extends CollectionSubView() { } const instance = CollectionDockingView.Instance; if (!instance) return false; - else { - instance.addToTabDocList(document); - } const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName); if (!pullSide && stack) { @@ -434,29 +411,10 @@ export class CollectionDockingView extends CollectionSubView() { const matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g); const docids = matches?.map(m => m.replace("\"documentId\":\"", "").replace("\"", "")); const docs = !docids ? [] : docids.map(id => DocServer.GetCachedRefField(id)).filter(f => f).map(f => f as Doc); - const changesMade = this.props.Document.dockingConfig !== json; + const changesMade = this.props.Document.dockcingConfig !== json; if (changesMade && !this._flush) { this.props.Document.dockingConfig = json; - setTimeout(async () => { - const sublists = await DocListCastAsync(this.props.Document[this.props.fieldKey]); - const tabs = sublists && Cast(sublists[0], Doc, null); - // const other = sublists && Cast(sublists[1], Doc, null); - const tabdocs = await DocListCastAsync(tabs?.data); - // const otherdocs = await DocListCastAsync(other?.data); - if (tabs) { - tabs.data = new List(docs); - // DocListCast(tabs.aliases).forEach(tab => tab !== tabs && (tab.data = new List(docs))); - } - // const otherSet = new Set(); - // otherdocs?.filter(doc => !docs.includes(doc)).forEach(doc => otherSet.add(doc)); - // tabdocs?.filter(doc => !docs.includes(doc) && doc.type !== DocumentType.KVP).forEach(doc => otherSet.add(doc)); - // const vals = Array.from(otherSet.values()).filter(val => val instanceof Doc).map(d => d).filter(d => d.type !== DocumentType.KVP); - // this.props.Document[DataSym][this.props.fieldKey + "-all"] = new List([...docs, ...vals]); - // if (other) { - // other.data = new List(vals); - // // DocListCast(other.aliases).forEach(tab => tab !== other && (tab.data = new List(vals))); - // } - }, 0); + this.props.Document.data = new List(docs); } return changesMade; } @@ -490,7 +448,6 @@ export class CollectionDockingView extends CollectionSubView() { //if (confirm('really close this?')) { if (!stack.parent.parent.isRoot || stack.parent.contentItems.length > 1) { stack.remove(); - stack.contentItems.forEach((contentItem: any) => CollectionDockingView.Instance.removeFromTabDocList(contentItem.tab.DashDoc)); } else { alert('cant delete the last stack'); } diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index a2ba504dc..2b78b20ea 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -180,7 +180,6 @@ export class TabDocView extends React.Component { tab.closeElement.off('click') //unbind the current click handler .click(function () { Object.values(tab._disposers).forEach((disposer: any) => disposer?.()); - CollectionDockingView.Instance?.removeFromTabDocList(doc); SelectionManager.DeselectAll(); UndoManager.RunInBatch(() => tab.contentItem.remove(), "delete tab"); }); diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx index dc35b5749..0875c80b3 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx @@ -278,6 +278,7 @@ export class KeysDropdown extends React.Component { @undoBatch onKeyDown = (e: React.KeyboardEvent): void => { if (e.key === "Enter") { + e.stopPropagation(); if (this._searchTerm.includes(":")) { const colpos = this._searchTerm.indexOf(":"); const temp = this._searchTerm.slice(colpos + 1, this._searchTerm.length); @@ -490,7 +491,9 @@ export class KeysDropdown extends React.Component {
this.onChange(e.target.value)} onClick={(e) => { e.stopPropagation(); this._inputRef.current?.focus(); }} onFocus={this.onFocus} > -- cgit v1.2.3-70-g09d2 From b0408fa264fc8a017c87a17325600d8e458fe711 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 6 Jun 2022 01:32:36 -0400 Subject: fixed up overlayDocs a bit so that they can be removed. made audioBox's appear in overlay when clicked from toolbar. add links to audio when navigating to doc in lightbox. --- src/client/util/CurrentUserUtils.ts | 4 ++-- src/client/views/LightboxView.tsx | 2 ++ src/client/views/OverlayView.tsx | 10 +++++++--- src/client/views/collections/CollectionDockingView.tsx | 2 ++ src/client/views/nodes/AudioBox.tsx | 9 ++++++++- 5 files changed, 21 insertions(+), 6 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index cad86c0a6..51bfdbbd2 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -276,7 +276,7 @@ export class CurrentUserUtils { (doc.emptyWall as Doc).videoWall = true; } if (doc.emptyAudio === undefined) { - doc.emptyAudio = Docs.Create.AudioDocument(nullAudio, { ...standardOps(), title: "audio recording", _width: 200, _height: 100, }); + doc.emptyAudio = Docs.Create.AudioDocument(nullAudio, { ...standardOps(), title: "audio recording", x: 200, y: 200, _width: 200, _height: 100, }); } if (doc.emptyNote === undefined) { doc.emptyNote = Docs.Create.TextDocument("", { ...standardOps(), title: "text note", _width: 200, _autoHeight: true }); @@ -301,7 +301,7 @@ export class CurrentUserUtils { { toolTip: "Tap to create a comparison box in a new pane, drag for a comparison box", title: "Compare", icon: "columns", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyComparison as Doc, noviceMode: true }, { toolTip: "Tap to create a screen grabber in a new pane, drag for a screen grabber", title: "Grab", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScreenshot as Doc }, { toolTip: "Tap to create a videoWall", title: "Wall", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyWall as Doc }, - { toolTip: "Tap to create an audio recorder in a new pane, drag for an audio recorder", title: "Audio", icon: "microphone", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyAudio as Doc, noviceMode: true }, + { toolTip: "Tap to create an audio recorder in a overlay pane, drag for an audio recorder", title: "Audio", icon: "microphone", click: 'openInOverlay(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyAudio as Doc, noviceMode: true }, { toolTip: "Tap to create a button in a new pane, drag for a button", title: "Button", icon: "bolt", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyButton as Doc }, // { toolTip: "Tap to create a presentation in a new pane, drag for a presentation", title: "Trails", icon: "pres-trail", click: 'openOnRight(Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory))', drag: `Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory)`, dragFactory: doc.emptyPresentation as Doc, noviceMode: true }, { toolTip: "Tap to create a scripting box in a new pane, drag for a scripting box", title: "Script", icon: "terminal", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScript as Doc }, diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index 2543111b0..f67f37bfb 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -126,6 +126,8 @@ export class LightboxView extends React.Component { const target = LightboxView._docTarget = this._future?.pop(); const targetDocView = target && DocumentManager.Instance.getLightboxDocumentView(target); if (targetDocView && target) { + const l = DocUtils.MakeLinkToActiveAudio(() => targetDocView.ComponentView?.getAnchor?.() || target).lastElement(); + l && (Cast(l.anchor2, Doc, null).backgroundColor = "lightgreen"); targetDocView.focus(target, { originalTarget: target, willZoom: true, scale: 0.9 }); if (LightboxView._history?.lastElement().target !== target) LightboxView._history?.push({ doc, target }); } else { diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index 18b87e3d5..95e146df4 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -146,6 +146,10 @@ export class OverlayView extends React.Component { return remove; } + removeOverlayDoc = (doc: Doc | Doc[]) => { + (doc instanceof Doc ? [doc] : doc).forEach(doc => Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc)); + return true; + } @computed get overlayDocs() { return CurrentUserUtils.OverlayDocs?.map(d => { @@ -179,16 +183,16 @@ export class OverlayView extends React.Component { offsetx = NumCast(d.x) - e.clientX; offsety = NumCast(d.y) - e.clientY; }; - return
+ return
new Transform(-NumCast(d.x), -NumCast(d.y), 1)} renderDepth={1} isDocumentActive={returnFalse} isContentActive={returnTrue} diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 5c0d6b1c4..de2106e4a 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -475,4 +475,6 @@ ScriptingGlobals.add(function openInLightbox(doc: any) { LightboxView.AddDocTab( "opens up document in a lightbox", "(doc: any)"); ScriptingGlobals.add(function openOnRight(doc: any) { return CollectionDockingView.AddSplit(doc, "right"); }, "opens up document in tab on right side of the screen", "(doc: any)"); +ScriptingGlobals.add(function openInOverlay(doc: any) { return Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc); }, + "opens up document in screen overlay layer", "(doc: any)"); ScriptingGlobals.add(function useRightSplit(doc: any, shiftKey?: boolean) { CollectionDockingView.ReplaceTab(doc, "right", undefined, shiftKey); }); \ No newline at end of file diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 9b92762a2..787ad939d 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -350,7 +350,14 @@ export class AudioBox extends ViewBoxAnnotatableComponent Date: Wed, 8 Jun 2022 01:17:24 -0400 Subject: added ability to make thumbnails of dashboards. started to cleanup dockingView/goldenlayout undo event handling. cleaned up tab doc list in docking view. made titles editable again in treeview. fixed overlay view to work with image docs etc by setting top/left in css --- src/client/documents/Documents.ts | 6 +-- src/client/goldenLayout.js | 2 +- src/client/util/CurrentUserUtils.ts | 26 ++++++++--- src/client/views/DocumentButtonBar.tsx | 53 ++++++++++------------ src/client/views/MainView.tsx | 12 +---- src/client/views/OverlayView.scss | 2 + src/client/views/OverlayView.tsx | 2 +- .../views/collections/CollectionDockingView.tsx | 21 ++++++--- src/client/views/collections/TabDocView.tsx | 28 ++++-------- src/client/views/collections/TreeView.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 45 ++++++++++-------- src/client/views/nodes/WebBoxRenderer.js | 4 +- src/client/views/topbar/TopBar.tsx | 6 +-- 13 files changed, 108 insertions(+), 103 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 817478b2f..acc1e341a 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -671,9 +671,9 @@ export namespace Docs { return viewDoc; } - export function ImageDocument(url: string, options: DocumentOptions = {}) { - const imgField = new ImageField(url); - return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { title: basename(url), ...options }); + export function ImageDocument(url: string|ImageField, options: DocumentOptions = {}) { + const imgField = url instanceof ImageField ? url : new ImageField(url); + return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { title: basename(imgField.url.href), ...options }); } export function PresDocument(options: DocumentOptions = {}) { diff --git a/src/client/goldenLayout.js b/src/client/goldenLayout.js index 82b10608d..4735f216f 100644 --- a/src/client/goldenLayout.js +++ b/src/client/goldenLayout.js @@ -1431,7 +1431,7 @@ this.root.callDownwards('_$init'); if (config.maximisedItemId === '__glMaximised') { - this.root.getItemsById(config.maximisedItemId)[0].toggleMaximise(); + this.root.getItemsById(config.maximisedItemId)[0]?.toggleMaximise(); } }, diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 51bfdbbd2..885679b64 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -8,7 +8,7 @@ import { PrefetchProxy } from "../../fields/Proxy"; import { RichTextField } from "../../fields/RichTextField"; import { ComputedField, ScriptField } from "../../fields/ScriptField"; import { BoolCast, Cast, DateCast, NumCast, PromiseValue, StrCast } from "../../fields/Types"; -import { nullAudio } from "../../fields/URLField"; +import { ImageField, nullAudio } from "../../fields/URLField"; import { SharingPermissions } from "../../fields/util"; import { Utils } from "../../Utils"; import { DocServer } from "../DocServer"; @@ -22,11 +22,10 @@ import { TreeView } from "../views/collections/TreeView"; import { Colors } from "../views/global/globalEnums"; import { MainView } from "../views/MainView"; import { ButtonType, NumButtonType } from "../views/nodes/button/FontIconBox"; -import { LabelBox } from "../views/nodes/LabelBox"; import { CollectionFreeFormDocumentView } from "../views/nodes/CollectionFreeFormDocumentView"; import { OverlayView } from "../views/OverlayView"; import { DocumentManager } from "./DocumentManager"; -import { DragManager, dropActionType } from "./DragManager"; +import { DragManager } from "./DragManager"; import { makeTemplate, MakeTemplate } from "./DropConverter"; import { HistoryUtil } from "./History"; import { LinkManager } from "./LinkManager"; @@ -1185,9 +1184,24 @@ export class CurrentUserUtils { } public static async snapshotDashboard(userDoc: Doc) { - const copy = await CollectionDockingView.Copy(CurrentUserUtils.ActiveDashboard); - Doc.AddDocToList(Cast(userDoc.myDashboards, Doc, null), "data", copy); - CurrentUserUtils.openDashboard(userDoc, copy); + const docView = CollectionDockingView.Instance.props.DocumentView?.(); + const content = docView?.ContentDiv; + if (docView && content) { + const _width = Number(getComputedStyle(content).width.replace("px","")); + const _height = Number(getComputedStyle(content).height.replace("px","")); + CollectionFreeFormView.UpdateIcon( + docView.layoutDoc[Id] + "-icon" + (new Date()).getTime(), + content, + _width, _height, + _width, _height, 0, + (iconFile, _nativeWidth, _nativeHeight) => { + const img = Docs.Create.ImageDocument(new ImageField(iconFile), { title: docView.rootDoc.title+"-icon", _width, _height, _nativeWidth, _nativeHeight}); + const proto = Cast(img.proto, Doc, null)!; + proto["data-nativeWidth"] = _width; + proto["data-nativeHeight"] = _height; + docView.dataDoc.thumb = img; + }); + } } public static createNewDashboard = async (userDoc: Doc, id?: string) => { diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index c0645f0ab..103734b9b 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -213,34 +213,31 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV @undoBatch @action pinWithView = (targetDoc: Doc) => { - if (targetDoc) { - TabDocView.PinDoc(targetDoc); - setTimeout(() => { - const activeDoc = PresBox.Instance.childDocs[PresBox.Instance.childDocs.length - 1]; - const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(targetDoc.type as any) || targetDoc._viewType === CollectionViewType.Stacking; - const pannable: boolean = ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG); - if (scrollable) { - const scroll = targetDoc._scrollTop; - activeDoc.presPinView = true; - activeDoc.presPinViewScroll = scroll; - } else if ([DocumentType.AUDIO, DocumentType.VID].includes(targetDoc.type as any)) { - activeDoc.presPinView = true; - activeDoc.presStartTime = targetDoc._currentTimecode; - activeDoc.presEndTime = NumCast(targetDoc._currentTimecode) + 0.1; - } else if (pannable) { - const x = targetDoc._panX; - const y = targetDoc._panY; - const scale = targetDoc._viewScale; - activeDoc.presPinView = true; - activeDoc.presPinViewX = x; - activeDoc.presPinViewY = y; - activeDoc.presPinViewScale = scale; - } else if (targetDoc.type === DocumentType.COMPARISON) { - const width = targetDoc._clipWidth; - activeDoc.presPinClipWidth = width; - activeDoc.presPinView = true; - } - }); + const activeDoc = targetDoc && TabDocView.PinDoc(targetDoc); + if (activeDoc) { + const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(targetDoc.type as any) || targetDoc._viewType === CollectionViewType.Stacking; + const pannable: boolean = ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG); + if (scrollable) { + const scroll = targetDoc._scrollTop; + activeDoc.presPinView = true; + activeDoc.presPinViewScroll = scroll; + } else if ([DocumentType.AUDIO, DocumentType.VID].includes(targetDoc.type as any)) { + activeDoc.presPinView = true; + activeDoc.presStartTime = targetDoc._currentTimecode; + activeDoc.presEndTime = NumCast(targetDoc._currentTimecode) + 0.1; + } else if (pannable) { + const x = targetDoc._panX; + const y = targetDoc._panY; + const scale = targetDoc._viewScale; + activeDoc.presPinView = true; + activeDoc.presPinViewX = x; + activeDoc.presPinViewY = y; + activeDoc.presPinViewScale = scale; + } else if (targetDoc.type === DocumentType.COMPARISON) { + const width = targetDoc._clipWidth; + activeDoc.presPinClipWidth = width; + activeDoc.presPinView = true; + } } } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index cdf85c905..a30db66e4 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -226,17 +226,7 @@ export class MainView extends React.Component { if (received && !this.userDoc) { reaction(() => CurrentUserUtils.GuestTarget, target => target && CurrentUserUtils.createNewDashboard(Doc.UserDoc()), { fireImmediately: true }); } else { - if (received && CurrentUserUtils._urlState.sharing) { - reaction(() => CollectionDockingView.Instance && CollectionDockingView.Instance.initialized, - initialized => initialized && received && DocServer.GetRefField(received).then(docField => { - if (docField instanceof Doc && docField._viewType !== CollectionViewType.Docking) { - CollectionDockingView.AddSplit(docField, "right"); - } - }), - ); - } - const activeDash = PromiseValue(this.userDoc.activeDashboard); - activeDash.then(dash => { + PromiseValue(this.userDoc.activeDashboard).then(dash => { if (dash instanceof Doc) CurrentUserUtils.openDashboard(this.userDoc, dash); else CurrentUserUtils.createNewDashboard(this.userDoc); }); diff --git a/src/client/views/OverlayView.scss b/src/client/views/OverlayView.scss index 555f4298d..f22e68ff5 100644 --- a/src/client/views/OverlayView.scss +++ b/src/client/views/OverlayView.scss @@ -46,4 +46,6 @@ .overlayView-doc { z-index: 9002; //so that it appears above chroma position: absolute; + top: 0; + left: 0; } \ No newline at end of file diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index c3c103b50..f5e686473 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -200,7 +200,7 @@ export class OverlayView extends React.Component { ScreenToLocalTransform={this.docScreenToLocalXf(d)} renderDepth={1} isDocumentActive={returnTrue} - isContentActive={retu} + isContentActive={returnTrue} whenChildContentsActiveChanged={emptyFunction} focus={DocUtils.DefaultFocus} styleProvider={DefaultStyleProvider} diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index de2106e4a..5af72b7d1 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -26,6 +26,7 @@ import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView"; import { CollectionViewType } from './CollectionView'; import { TabDocView } from './TabDocView'; import React = require("react"); +import { SelectionManager } from '../../util/SelectionManager'; const _global = (window /* browser */ || global /* node */) as any; @observer @@ -50,9 +51,8 @@ export class CollectionDockingView extends CollectionSubView() { public _flush: UndoManager.Batch | undefined; private _ignoreStateChange = ""; public tabMap: Set = new Set(); - public get initialized() { return this._goldenLayout !== null; } public get HasFullScreen() { return this._goldenLayout._maximisedItem !== null; } - @observable private _goldenLayout: any = null; + private _goldenLayout: any = null; constructor(props: SubCollectionViewProps) { super(props); @@ -118,6 +118,7 @@ export class CollectionDockingView extends CollectionSubView() { @undoBatch public static OpenFullScreen(doc: Doc) { + SelectionManager.DeselectAll(); const instance = CollectionDockingView.Instance; if (doc._viewType === CollectionViewType.Docking && doc.layoutKey === "layout") { return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc); @@ -271,7 +272,7 @@ export class CollectionDockingView extends CollectionSubView() { return true; } - async setupGoldenLayout() { + setupGoldenLayout = async () => { const config = StrCast(this.props.Document.dockingConfig); if (config) { const matches = config.match(/\"documentId\":\"[a-z0-9-]+\"/g); @@ -291,7 +292,7 @@ export class CollectionDockingView extends CollectionSubView() { } this.tabMap.clear(); this._goldenLayout?.destroy(); - runInAction(() => this._goldenLayout = new GoldenLayout(JSON.parse(config))); + this._goldenLayout = new GoldenLayout(JSON.parse(config)); this._goldenLayout.on('tabCreated', this.tabCreated); this._goldenLayout.on('tabDestroyed', this.tabDestroyed); this._goldenLayout.on('stackCreated', this.stackCreated); @@ -322,7 +323,7 @@ export class CollectionDockingView extends CollectionSubView() { } this._ignoreStateChange = ""; }); - setTimeout(() => this.setupGoldenLayout(), 0); + setTimeout(this.setupGoldenLayout); //window.addEventListener('resize', this.onResize); // bcz: would rather add this event to the parent node, but resize events only come from Window } } @@ -413,19 +414,25 @@ export class CollectionDockingView extends CollectionSubView() { const docs = !docids ? [] : docids.map(id => DocServer.GetCachedRefField(id)).filter(f => f).map(f => f as Doc); const changesMade = this.props.Document.dockcingConfig !== json; if (changesMade && !this._flush) { - this.props.Document.dockingConfig = json; - this.props.Document.data = new List(docs); + UndoManager.RunInBatch(() => { + this.props.Document.dockingConfig = json; + this.props.Document.data = new List(docs); + }, "state changed"); } return changesMade; } tabDestroyed = (tab: any) => { + const dview = CollectionDockingView.Instance.props.Document; + const fieldKey = CollectionDockingView.Instance.props.fieldKey; + Doc.RemoveDocFromList(dview, fieldKey, tab.DashDoc); this.tabMap.delete(tab); tab._disposers && Object.values(tab._disposers).forEach((disposer: any) => disposer?.()); tab.reactComponents?.forEach((ele: any) => ReactDOM.unmountComponentAtNode(ele)); this.stateChanged(); } tabCreated = (tab: any) => { + this.tabMap.add(tab); tab.contentItem.element[0]?.firstChild?.firstChild?.InitTab?.(tab); // have to explicitly initialize tabs that reuse contents from previous tabs (ie, when dragging a tab around a new tab is created for the old content) } diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 0141724ea..75a8207dd 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -82,7 +82,6 @@ export class TabDocView extends React.Component { const iconWrap = document.createElement("div"); const closeWrap = document.createElement("div"); - titleEle.size = StrCast(doc.title).length + 3; titleEle.value = doc.title; titleEle.onkeydown = (e: KeyboardEvent) => { @@ -185,14 +184,13 @@ export class TabDocView extends React.Component { UndoManager.RunInBatch(() => tab.contentItem.remove(), "delete tab"); }); } - CollectionDockingView.Instance.tabMap.add(tab); } /** * Adds a document to the presentation view **/ @action - public static async PinDoc(doc: Doc, pinProps?: PinProps) { + public static PinDoc(doc: Doc, pinProps?: PinProps) { //add this new doc to props.Document // all docs will be added to the ActivePresentation as stored on CurrentUserUtils @@ -246,19 +244,14 @@ export class TabDocView extends React.Component { pinDoc.presMovement = PresMovement.None; } if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true; - const dview = CollectionDockingView.Instance.props.Document; - const fieldKey = CollectionDockingView.Instance.props.fieldKey; - const tabdocs = await DocListCastAsync(dview[fieldKey]); - runInAction(() => { - if (!pinProps?.hidePresBox && !tabdocs?.includes(curPres)) { - tabdocs?.push(curPres); // bcz: Argh! this is annoying. if multiple documents are pinned, this will get called multiple times before the presentation view is drawn. Thus it won't be in the tabdocs list and it will get created multple times. so need to explicilty add the presbox to the list of open tabs - CollectionDockingView.AddSplit(curPres, "right"); - } - PresBox.Instance?._selectedArray.clear(); - pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Update selected array - DocumentManager.Instance.jumpToDocument(doc, false, undefined, []); - batch.end(); - }); + if (!Array.from(CollectionDockingView.Instance.tabMap).map(d => d.DashDoc).includes(curPres)) { + CollectionDockingView.AddSplit(curPres, "right"); + setTimeout(() => DocumentManager.Instance.jumpToDocument(doc, false, undefined, []), 100); // keeps the pinned doc in view since the sidebar shifts things + } + PresBox.Instance?._selectedArray.clear(); + pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Update selected array + setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs + return pinDoc; } } @@ -282,7 +275,6 @@ export class TabDocView extends React.Component { componentWillUnmount() { this._tabReaction?.(); this._view && DocumentManager.Instance.RemoveView(this._view); - this.tab && CollectionDockingView.Instance.tabMap.delete(this.tab); this.props.glContainer.layoutManager.off("activeContentItemChanged", this.onActiveContentItemChanged); } @@ -430,9 +422,7 @@ export class TabDocView extends React.Component { }} ref={ref => { if (this._mainCont = ref) { if (this._lastTab) { - console.log("DUP tab") this._view && DocumentManager.Instance.RemoveView(this._view); - CollectionDockingView.Instance.tabMap.delete(this._lastTab); } this._lastTab = this.tab; (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document); diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index befd2020c..09f05f69a 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -609,10 +609,8 @@ export class TreeView extends React.Component { return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label })); } - // TODO: currently doc focus works, but can't seem to edit title - // onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick)); onChildClick = () => { - return this.props.onChildClick?.() ?? (ScriptField.MakeFunction(`DocFocusOrOpen(self)`)! || this._editTitleScript?.()); + return this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!); } onChildDoubleClick = () => (!this.props.treeView.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 77cf0fc84..5f927a2a9 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1489,7 +1489,7 @@ export class CollectionFreeFormView extends CollectionSubView { + static replaceCanvases(oldDiv: HTMLElement, newDiv: HTMLElement) { if (oldDiv.childNodes && newDiv) { for (let i = 0; i < oldDiv.childNodes.length; i++) { this.replaceCanvases(oldDiv.childNodes[i] as HTMLElement, newDiv.childNodes[i] as HTMLElement); @@ -1508,32 +1508,39 @@ export class CollectionFreeFormView extends CollectionSubView { - const docViewContent = this.props.docViewPath().lastElement().ContentDiv!; + updateIcon = () => CollectionFreeFormView.UpdateIcon( + this.layoutDoc[Id] + "-icon" + (new Date()).getTime(), + this.props.docViewPath().lastElement().ContentDiv!, + this.layoutDoc[WidthSym](), this.layoutDoc[HeightSym](), + this.props.PanelWidth(), this.props.PanelHeight(), 0, + (iconFile, nativeWidth, nativeHeight) => { + this.dataDoc.icon = new ImageField(iconFile); + this.dataDoc["icon-nativeWidth"] = nativeWidth; + this.dataDoc["icon-nativeHeight"] = nativeHeight; + }); + + public static UpdateIcon(filename:string, docViewContent:HTMLElement, width: number, height: number, + panelWidth:number, panelHeight: number, scrollTop:number, cb:(iconFile:string, nativeWidth:number, nativeHeight:number) => any) { const newDiv = docViewContent.cloneNode(true) as HTMLDivElement; - newDiv.style.width = (this.layoutDoc[WidthSym]()).toString(); - newDiv.style.height = (this.layoutDoc[HeightSym]()).toString(); + newDiv.style.width = width.toString(); + newDiv.style.height = height.toString(); this.replaceCanvases(docViewContent, newDiv); - const htmlString = this._mainCont && new XMLSerializer().serializeToString(newDiv); - const nativeWidth = this.layoutDoc[WidthSym](); - const nativeHeight = this.layoutDoc[HeightSym](); - + const htmlString = new XMLSerializer().serializeToString(newDiv); + const nativeWidth = width; + const nativeHeight = height; CreateImage( - "", + Utils.prepend(""), document.styleSheets, htmlString, nativeWidth, - nativeWidth * this.props.PanelHeight() / this.props.PanelWidth(), - NumCast(this.layoutDoc._scrollTop) + nativeWidth * panelHeight / panelWidth, + scrollTop ).then ((data_url: any) => { - VideoBox.convertDataUri(data_url, this.layoutDoc[Id] + "-icon" + (new Date()).getTime(), true, this.layoutDoc[Id] + "-icon").then( - returnedfilename => setTimeout(action(() => { - - this.dataDoc.icon = new ImageField(returnedfilename); - this.dataDoc["icon-nativeWidth"] = nativeWidth; - this.dataDoc["icon-nativeHeight"] = nativeHeight; - }), 500)); + VideoBox.convertDataUri(data_url, filename).then( + returnedfilename => setTimeout(() => { + cb(returnedfilename as string, nativeWidth, nativeHeight); + }, 500)); }) .catch(function (error: any) { console.error('oops, something went wrong!', error); diff --git a/src/client/views/nodes/WebBoxRenderer.js b/src/client/views/nodes/WebBoxRenderer.js index d9524dd6e..f3f1bcf5c 100644 --- a/src/client/views/nodes/WebBoxRenderer.js +++ b/src/client/views/nodes/WebBoxRenderer.js @@ -214,8 +214,8 @@ var ForeignHtmlRenderer = function (styleSheets) { .replace(/noscript/g, "div").replace(/
<\/div>/g, "") // when scripting isn't available (ie, rendering web pages here),
} placement="bottom"> @@ -57,12 +57,12 @@ export class TopBar extends React.Component { await CurrentUserUtils.snapshotDashboard(Doc.UserDoc()); batch.end(); }}> - {"Snapshot"} + Snapshot
Browsing mode for directly navigating to documents
} placement="bottom">
MainView.Instance._exploreMode = !MainView.Instance._exploreMode)}> - {"Explore"} + Explore
-- cgit v1.2.3-70-g09d2 From 7ab50d37d38a91d564cf3150be35a68d11bdcffe Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 8 Jun 2022 01:45:05 -0400 Subject: undo/redo fixes for docking views (maximizing, closing stacks). making maximised tabs persist across refreshes. --- src/client/views/collections/CollectionDockingView.tsx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 5af72b7d1..745565ff5 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -298,13 +298,6 @@ export class CollectionDockingView extends CollectionSubView() { this._goldenLayout.on('stackCreated', this.stackCreated); this._goldenLayout.registerComponent('DocumentFrameRenderer', TabDocView); this._goldenLayout.container = this._containerRef.current; - if (this._goldenLayout.config.maximisedItemId === '__glMaximised') { - try { - this._goldenLayout.config.root.getItemsById(this._goldenLayout.config.maximisedItemId)[0].toggleMaximise(); - } catch (e) { - this._goldenLayout.config.maximisedItemId = null; - } - } this._goldenLayout.init(); this._goldenLayout.root.layoutManager.on('itemDropped', this.tabItemDropped); this._goldenLayout.root.layoutManager.on('dragStart', this.tabDragStart); @@ -369,7 +362,7 @@ export class CollectionDockingView extends CollectionSubView() { const htmlTarget = e.target as HTMLElement; window.addEventListener("mouseup", this.onPointerUp); if (!htmlTarget.closest("*.lm_content") && (htmlTarget.closest("*.lm_tab") || htmlTarget.closest("*.lm_stack"))) { - if (htmlTarget.className !== "lm_close_tab") { + if (!htmlTarget.className.includes("lm_close") && !htmlTarget.className.includes("lm_maximise")) { this._flush = UndoManager.StartBatch("golden layout edit"); } } @@ -459,6 +452,9 @@ export class CollectionDockingView extends CollectionSubView() { alert('cant delete the last stack'); } })); + + stack.header?.controlsContainer.find('.lm_maximise') //get the close icon + .click(() => setTimeout(this.stateChanged)); stack.header?.controlsContainer.find('.lm_popout') //get the popout icon .off('click') //unbind the current click handler .click(action(() => { -- cgit v1.2.3-70-g09d2 From 5157f0c500b01a635c373cc661a2588ef7506d79 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 8 Jun 2022 12:44:36 -0400 Subject: added context menu back to tab's via the doc icon. made docicon draggable and clickable. removed collectiondockingviewmenu. --- src/client/goldenLayout.js | 5 ++- .../views/collections/CollectionDockingView.tsx | 3 +- .../collections/CollectionDockingViewMenu.scss | 34 --------------- .../collections/CollectionDockingViewMenu.tsx | 48 -------------------- src/client/views/collections/TabDocView.tsx | 51 +++++++++++----------- 5 files changed, 31 insertions(+), 110 deletions(-) delete mode 100644 src/client/views/collections/CollectionDockingViewMenu.scss delete mode 100644 src/client/views/collections/CollectionDockingViewMenu.tsx (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/goldenLayout.js b/src/client/goldenLayout.js index 4735f216f..012ee163c 100644 --- a/src/client/goldenLayout.js +++ b/src/client/goldenLayout.js @@ -458,8 +458,9 @@ if (this._bDragging === true) { this._bDragging = false; this.emit('dragStop', oEvent, this._nOriginalX + this._nX); - } else if (oEvent.target) { // make title receive pointer events to allow setting insertion position or selecting texst range - if (oEvent.target.className.includes("lm_title_wrap")) { + } else { // make title receive pointer events to allow setting insertion position or selecting texst range + const classname = typeof oEvent.target?.className === "string" ? oEvent.target.className : ""; + if (classname.includes("lm_title_wrap")) { oEvent.target.children[0].style.pointerEvents = "all"; oEvent.target.children[0].focus(); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 745565ff5..476ffaf81 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -362,7 +362,8 @@ export class CollectionDockingView extends CollectionSubView() { const htmlTarget = e.target as HTMLElement; window.addEventListener("mouseup", this.onPointerUp); if (!htmlTarget.closest("*.lm_content") && (htmlTarget.closest("*.lm_tab") || htmlTarget.closest("*.lm_stack"))) { - if (!htmlTarget.className.includes("lm_close") && !htmlTarget.className.includes("lm_maximise")) { + const className = typeof htmlTarget.className === "string" ? htmlTarget.className : ""; + if (!className.includes("lm_close") && !className.includes("lm_maximise")) { this._flush = UndoManager.StartBatch("golden layout edit"); } } diff --git a/src/client/views/collections/CollectionDockingViewMenu.scss b/src/client/views/collections/CollectionDockingViewMenu.scss deleted file mode 100644 index 4157f0f7e..000000000 --- a/src/client/views/collections/CollectionDockingViewMenu.scss +++ /dev/null @@ -1,34 +0,0 @@ - -.dockingViewButtonSelector { - div { - overflow: visible !important; - } - - display: inline-block; - width:100%; - height:100%; -} -.dockingViewButtonSelector-flyout { - position: relative; - z-index: 9999; - background-color: #eeeeee; - box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); - color: black; - - padding: 10px; - border-radius: 3px; - display: inline-block; - height: 100%; - width: 100%; - border-radius: 3px; - - hr { - height: 1px; - margin: 0px; - background-color: gray; - border-top: 0px; - border-bottom: 0px; - border-right: 0px; - border-left: 0px; - } -} \ No newline at end of file diff --git a/src/client/views/collections/CollectionDockingViewMenu.tsx b/src/client/views/collections/CollectionDockingViewMenu.tsx deleted file mode 100644 index 1cab293a8..000000000 --- a/src/client/views/collections/CollectionDockingViewMenu.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Tooltip } from "@material-ui/core"; -import { action, computed, observable } from "mobx"; -import { observer } from "mobx-react"; -import * as React from "react"; -import { DocumentButtonBar } from "../DocumentButtonBar"; -import { DocumentView } from "../nodes/DocumentView"; -const higflyout = require("@hig/flyout"); -export const { anchorPoints } = higflyout; -export const Flyout = higflyout.default; - -@observer -export class CollectionDockingViewMenu extends React.Component<{ views: () => DocumentView[], Stack: any }> { - customStylesheet(styles: any) { - return { - ...styles, - panel: { - ...styles.panel, - minWidth: "100px" - }, - }; - } - _ref = React.createRef(); - - @computed get flyout() { - return ( -
- -
- ); - } - - @observable _tooltipOpen: boolean = false; - render() { - return this._tooltipOpen = false)} title={<>
Tap for toolbar, drag to create alias in another pane
} placement="bottom"> - !this._ref.current?.getBoundingClientRect().width && (this._tooltipOpen = true))} - onPointerDown={action(e => { - this.props.views()[0]?.select(false); - this._tooltipOpen = false; - })} > - - - - -
; - } -} diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 75a8207dd..91c6975ea 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -4,15 +4,15 @@ import { Tooltip } from '@material-ui/core'; import 'golden-layout/src/css/goldenlayout-base.css'; import 'golden-layout/src/css/goldenlayout-dark-theme.css'; import { clamp } from 'lodash'; -import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; +import { action, computed, IReactionDisposer, observable, reaction } from "mobx"; import { observer } from "mobx-react"; import * as ReactDOM from 'react-dom'; -import { DataSym, Doc, DocListCast, DocListCastAsync, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; +import { DataSym, Doc, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { FieldId } from "../../../fields/RefField"; import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types"; -import { emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, Utils } from "../../../Utils"; +import { emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from "../../../Utils"; import { DocServer } from "../../DocServer"; import { DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; @@ -27,10 +27,10 @@ import { Colors, Shadows } from '../global/globalEnums'; import { LightboxView } from '../LightboxView'; import { MainView } from '../MainView'; import { DocFocusOptions, DocumentView, DocumentViewProps } from "../nodes/DocumentView"; +import { DashFieldView } from '../nodes/formattedText/DashFieldView'; import { PinProps, PresBox, PresMovement } from '../nodes/trails'; import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; import { CollectionDockingView } from './CollectionDockingView'; -import { CollectionDockingViewMenu } from './CollectionDockingViewMenu'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { CollectionView, CollectionViewType } from './CollectionView'; import "./TabDocView.scss"; @@ -92,14 +92,28 @@ export class TabDocView extends React.Component { Doc.GetProto(doc).title = e.currentTarget.value; })); - const dragBtnDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, e => !e.defaultPrevented && DragManager.StartDocumentDrag([iconWrap], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY), returnFalse, emptyFunction); - }; - - if (tab.element[0].children[1].children.length === 1) { - iconWrap.className = "lm_iconWrap"; - iconWrap.id = "lm_iconWrap"; + iconWrap.className = "lm_iconWrap lm_moreInfo"; + const dragBtnDown = (e: React.PointerEvent) => { + setupMoveUpEvents(this, e, e => !e.defaultPrevented && DragManager.StartDocumentDrag([iconWrap], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY), returnFalse, action(e => { + if (this.view) { + SelectionManager.SelectView(this.view, false); + let child = this.view.ContentDiv!.children[0]; + while (child.children.length) { + const next = Array.from(child.children).find(c => c.className?.toString().includes("SVGAnimatedString") || typeof (c.className) === "string"); + if (next?.className?.toString().includes(DocumentView.ROOT_DIV)) break; + if (next?.className?.toString().includes(DashFieldView.name)) break; + if (next) child = next; + else break; + } + simulateMouseClick(child, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30); + } + else { this._activated = true; + setTimeout(() =>this.view && SelectionManager.SelectView(this.view, false)); + } + })); + }; + closeWrap.className = "lm_iconWrap"; closeWrap.id = "lm_closeWrap"; closeWrap.onclick = (e: MouseEvent) => { @@ -111,6 +125,7 @@ export class TabDocView extends React.Component { const closeIcon = ; ReactDOM.render(docIcon, iconWrap); ReactDOM.render(closeIcon, closeWrap); + tab.reactComponents = [iconWrap, closeWrap]; // tab.element[0].append(closeWrap); tab.element[0].prepend(iconWrap); tab._disposers.layerDisposer = reaction(() => ({ layer: tab.DashDoc.activeLayer, color: this.tabColor }), @@ -122,7 +137,6 @@ export class TabDocView extends React.Component { titleEle.style.backgroundColor = "transparent"; iconWrap.style.color = textColor; closeWrap.style.color = textColor; - moreInfoDrag.style.backgroundColor = textColor; tab.element[0].style.background = !layer ? color : "dimgrey"; }, { fireImmediately: true }); } @@ -155,19 +169,6 @@ export class TabDocView extends React.Component { // toggle.style.textTransform = selected ? "uppercase" : ""; })); - //attach the selection doc buttons menu to the drag handle - const stack: HTMLDivElement = tab.contentItem.parent; - const header: HTMLDivElement = tab; - stack.onscroll = action((e: any) => { - console.log('scrolling...'); - }); - const moreInfoDrag = document.createElement("div"); - moreInfoDrag.className = "lm_iconWrap"; - tab._disposers.buttonDisposer = reaction(() => this.view, view => - view && [ReactDOM.render( [view]} Stack={stack} />, moreInfoDrag), tab._disposers.buttonDisposer?.()], - { fireImmediately: true }); - // tab.reactComponents = [moreInfoDrag]; - // tab.element[0].children[3].before(moreInfoDrag); // highlight the tab when the tab document is brushed in any part of the UI tab._disposers.reactionDisposer = reaction(() => ({ title: doc.title, degree: Doc.IsBrushedDegree(doc) }), ({ title, degree }) => { -- cgit v1.2.3-70-g09d2 From 94975954fbd1ce9b68f6545b16a4eabe4b41cca0 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 8 Jun 2022 14:30:18 -0400 Subject: fixed bug with adding to pres when in miniview mode. --- .../views/collections/CollectionDockingView.tsx | 69 ++++++++++------------ src/client/views/collections/TabDocView.tsx | 3 + src/client/views/nodes/trails/PresBox.tsx | 4 +- 3 files changed, 37 insertions(+), 39 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 476ffaf81..a790a0475 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -172,12 +172,6 @@ export class CollectionDockingView extends CollectionSubView() { @undoBatch @action public static AddSplit(document: Doc, pullSide: string, stack?: any, panelName?: string) { - if (document.type === DocumentType.PRES) { - const docs = Cast(Cast(Doc.UserDoc().myOverlayDocs, Doc, null).data, listSpec(Doc), []); - if (docs.includes(document)) { - docs.splice(docs.indexOf(document), 1); - } - } if (document._viewType === CollectionViewType.Docking) return CurrentUserUtils.openDashboard(Doc.UserDoc(), document); const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document); @@ -186,6 +180,7 @@ export class CollectionDockingView extends CollectionSubView() { return true; } const instance = CollectionDockingView.Instance; + const glayRoot = instance._goldenLayout.root; if (!instance) return false; const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName); @@ -194,29 +189,29 @@ export class CollectionDockingView extends CollectionSubView() { stack.setActiveContentItem(stack.contentItems[stack.contentItems.length - 1]); } else { const newItemStackConfig = { type: 'stack', content: [docContentConfig] }; - const newContentItem = instance._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout); - if (instance._goldenLayout.root.contentItems.length === 0) { // if no rows / columns - instance._goldenLayout.root.addChild(newContentItem); - } else if (instance._goldenLayout.root.contentItems[0].isStack) { - instance._goldenLayout.root.contentItems[0].addChild(docContentConfig); + const newContentItem = glayRoot.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout); + if (glayRoot.contentItems.length === 0) { // if no rows / columns + glayRoot.addChild(newContentItem); + } else if (glayRoot.contentItems[0].isStack) { + glayRoot.contentItems[0].addChild(docContentConfig); } else if ( - instance._goldenLayout.root.contentItems.length === 1 && - instance._goldenLayout.root.contentItems[0].contentItems.length === 1 && - instance._goldenLayout.root.contentItems[0].contentItems[0].contentItems.length === 0) { - instance._goldenLayout.root.contentItems[0].contentItems[0].addChild(docContentConfig); + glayRoot.contentItems.length === 1 && + glayRoot.contentItems[0].contentItems.length === 1 && + glayRoot.contentItems[0].contentItems[0].contentItems.length === 0) { + glayRoot.contentItems[0].contentItems[0].addChild(docContentConfig); } else if (instance._goldenLayout.root.contentItems[0].isRow) { // if row switch (pullSide) { default: - case "right": instance._goldenLayout.root.contentItems[0].addChild(newContentItem); break; - case "left": instance._goldenLayout.root.contentItems[0].addChild(newContentItem, 0); break; + case "right": glayRoot.contentItems[0].addChild(newContentItem); break; + case "left": glayRoot.contentItems[0].addChild(newContentItem, 0); break; case "top": case "bottom": // if not going in a row layout, must add already existing content into column - const rowlayout = instance._goldenLayout.root.contentItems[0]; + const rowlayout = glayRoot.contentItems[0]; const newColumn = rowlayout.layoutManager.createContentItem({ type: "column" }, instance._goldenLayout); - CollectionDockingView.Instance._goldenLayout.saveScrollTops(rowlayout.element); + instance._goldenLayout.saveScrollTops(rowlayout.element); rowlayout.parent.replaceChild(rowlayout, newColumn); if (pullSide === "top") { newColumn.addChild(rowlayout, undefined, true); @@ -225,23 +220,23 @@ export class CollectionDockingView extends CollectionSubView() { newColumn.addChild(newContentItem, undefined, true); newColumn.addChild(rowlayout, 0, true); } - CollectionDockingView.Instance._goldenLayout.restoreScrollTops(rowlayout.element); + instance._goldenLayout.restoreScrollTops(rowlayout.element); rowlayout.config.height = 50; newContentItem.config.height = 50; } } else {// if (instance._goldenLayout.root.contentItems[0].isColumn) { // if column switch (pullSide) { - case "top": instance._goldenLayout.root.contentItems[0].addChild(newContentItem, 0); break; - case "bottom": instance._goldenLayout.root.contentItems[0].addChild(newContentItem); break; + case "top": glayRoot.contentItems[0].addChild(newContentItem, 0); break; + case "bottom": glayRoot.contentItems[0].addChild(newContentItem); break; case "left": case "right": default: // if not going in a row layout, must add already existing content into column - const collayout = instance._goldenLayout.root.contentItems[0]; + const collayout = glayRoot.contentItems[0]; const newRow = collayout.layoutManager.createContentItem({ type: "row" }, instance._goldenLayout); - CollectionDockingView.Instance._goldenLayout.saveScrollTops(collayout.element); + instance._goldenLayout.saveScrollTops(collayout.element); collayout.parent.replaceChild(collayout, newRow); if (pullSide === "left") { newRow.addChild(collayout, undefined, true); @@ -250,7 +245,7 @@ export class CollectionDockingView extends CollectionSubView() { newRow.addChild(newContentItem, undefined, true); newRow.addChild(collayout, 0, true); } - CollectionDockingView.Instance._goldenLayout.restoreScrollTops(collayout.element); + instance._goldenLayout.restoreScrollTops(collayout.element); collayout.config.width = 50; newContentItem.config.width = 50; @@ -289,19 +284,19 @@ export class CollectionDockingView extends CollectionSubView() { this._goldenLayout.unbind('stackCreated', this.stackCreated); } catch (e) { } } + this.tabMap.clear(); + this._goldenLayout.destroy(); } - this.tabMap.clear(); - this._goldenLayout?.destroy(); - this._goldenLayout = new GoldenLayout(JSON.parse(config)); - this._goldenLayout.on('tabCreated', this.tabCreated); - this._goldenLayout.on('tabDestroyed', this.tabDestroyed); - this._goldenLayout.on('stackCreated', this.stackCreated); - this._goldenLayout.registerComponent('DocumentFrameRenderer', TabDocView); - this._goldenLayout.container = this._containerRef.current; - this._goldenLayout.init(); - this._goldenLayout.root.layoutManager.on('itemDropped', this.tabItemDropped); - this._goldenLayout.root.layoutManager.on('dragStart', this.tabDragStart); - this._goldenLayout.root.layoutManager.on('activeContentItemChanged', this.stateChanged); + const glay = this._goldenLayout = new GoldenLayout(JSON.parse(config)); + glay.on('tabCreated', this.tabCreated); + glay.on('tabDestroyed', this.tabDestroyed); + glay.on('stackCreated', this.stackCreated); + glay.registerComponent('DocumentFrameRenderer', TabDocView); + glay.container = this._containerRef.current; + glay.init(); + glay.root.layoutManager.on('itemDropped', this.tabItemDropped); + glay.root.layoutManager.on('dragStart', this.tabDragStart); + glay.root.layoutManager.on('activeContentItemChanged', this.stateChanged); } } diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 91c6975ea..34fe572e3 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -35,6 +35,7 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV import { CollectionView, CollectionViewType } from './CollectionView'; import "./TabDocView.scss"; import React = require("react"); +import { listSpec } from '../../../fields/Schema'; const _global = (window /* browser */ || global /* node */) as any; interface TabDocViewProps { @@ -246,6 +247,8 @@ export class TabDocView extends React.Component { } if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true; if (!Array.from(CollectionDockingView.Instance.tabMap).map(d => d.DashDoc).includes(curPres)) { + const docs = Cast(Cast(Doc.UserDoc().myOverlayDocs, Doc, null).data, listSpec(Doc), []); + if (docs.includes(curPres)) docs.splice(docs.indexOf(curPres), 1); CollectionDockingView.AddSplit(curPres, "right"); setTimeout(() => DocumentManager.Instance.jumpToDocument(doc, false, undefined, []), 100); // keeps the pinned doc in view since the sidebar shifts things } diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 1a4be8e0c..591480023 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -403,11 +403,11 @@ export class PresBox extends ViewBoxBaseComponent() { // openInTab(targetDoc); } else if (curDoc.presMovement === PresMovement.Pan && targetDoc) { LightboxView.SetLightboxDoc(undefined); - await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, [srcContext], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true); // documents open in new tab instead of on right + 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) { LightboxView.SetLightboxDoc(undefined); //awaiting jump so that new scale can be found, since jumping is async - await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, [srcContext], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom)); // documents open in new tab instead of on right + 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 } // 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. -- cgit v1.2.3-70-g09d2 From d1f268c1788f54c62c0779aba224b5b7d30edb01 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 9 Jun 2022 17:13:49 -0400 Subject: changed tab numbering to be relative to dashboard. --- src/client/util/CurrentUserUtils.ts | 5 ++--- src/client/views/collections/CollectionDockingView.tsx | 12 ++++++------ 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 2d2dda2b8..3107650d9 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1215,8 +1215,6 @@ export class CurrentUserUtils { const presentation = Doc.MakeCopy(userDoc.emptyPresentation as Doc, true); const dashboards = await Cast(userDoc.myDashboards, Doc) as Doc; const dashboardCount = DocListCast(dashboards.data).length + 1; - const emptyPane = Cast(userDoc.emptyPane, Doc, null); - emptyPane["dragFactory-count"] = NumCast(emptyPane["dragFactory-count"]) + 1; const freeformOptions: DocumentOptions = { x: 0, y: 400, @@ -1224,7 +1222,7 @@ export class CurrentUserUtils { _height: 1000, _fitWidth: true, _backgroundGridShow: true, - title: `Untitled Tab ${NumCast(emptyPane["dragFactory-count"])}`, + title: `Untitled Tab 1`, }; const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: `Dashboard ${dashboardCount}` }, id, "row"); @@ -1233,6 +1231,7 @@ export class CurrentUserUtils { // switching the tabs from the datadoc to the regular doc const dashboardTabs = DocListCast(dashboardDoc[DataSym].data); dashboardDoc.data = new List(dashboardTabs); + dashboardDoc["pane-count"] = 1; userDoc.activePresentation = presentation; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index a790a0475..87149a4b8 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -428,10 +428,10 @@ export class CollectionDockingView extends CollectionSubView() { stackCreated = (stack: any) => { stack.header?.element.on('mousedown', (e: any) => { if (e.target === stack.header?.element[0] && e.button === 2) { - const emptyPane = CurrentUserUtils.EmptyPane; - emptyPane["dragFactory-count"] = NumCast(emptyPane["dragFactory-count"]) + 1; + const dashboard= CurrentUserUtils.ActiveDashboard; + dashboard["pane-count"] = NumCast(dashboard["pane-count"]) + 1; const docToAdd = Docs.Create.FreeformDocument([], { - _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _backgroundGridShow: true, _fitWidth: true, title: `Untitled Tab ${NumCast(emptyPane["dragFactory-count"])}`, + _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _backgroundGridShow: true, _fitWidth: true, title: `Untitled Tab ${NumCast(dashboard["pane-count"])}`, }); this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd); CollectionDockingView.AddSplit(docToAdd, "", stack); @@ -455,10 +455,10 @@ export class CollectionDockingView extends CollectionSubView() { .off('click') //unbind the current click handler .click(action(() => { // stack.config.fixed = !stack.config.fixed; // force the stack to have a fixed size - const emptyPane = CurrentUserUtils.EmptyPane; - emptyPane["dragFactory-count"] = NumCast(emptyPane["dragFactory-count"]) + 1; + const dashboard = CurrentUserUtils.ActiveDashboard; + dashboard["pane-count"] = NumCast(dashboard["pane-count"]) + 1; const docToAdd = Docs.Create.FreeformDocument([], { - _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _fitWidth: true, _backgroundGridShow: true, title: `Untitled Tab ${NumCast(emptyPane["dragFactory-count"])}` + _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _fitWidth: true, _backgroundGridShow: true, title: `Untitled Tab ${NumCast(dashboard["pane-count"])}` }); this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd); CollectionDockingView.AddSplit(docToAdd, "", stack); -- cgit v1.2.3-70-g09d2 From 1ab1ff51b5b5769079db1922d5013ec4680a1aa1 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 10 Jun 2022 09:10:54 -0400 Subject: fixed closing tabs to move to headerBar --- src/client/views/collections/CollectionDockingView.tsx | 2 ++ src/client/views/collections/TabDocView.tsx | 12 ++---------- 2 files changed, 4 insertions(+), 10 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index a790a0475..e657bd502 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -412,6 +412,8 @@ export class CollectionDockingView extends CollectionSubView() { } tabDestroyed = (tab: any) => { + Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", tab.DashDoc); + Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", tab.DashDoc, undefined, true, true); const dview = CollectionDockingView.Instance.props.Document; const fieldKey = CollectionDockingView.Instance.props.fieldKey; Doc.RemoveDocFromList(dview, fieldKey, tab.DashDoc); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 142013d1a..6c4437aed 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -115,20 +115,12 @@ export class TabDocView extends React.Component { } })); }; - - closeWrap.className = "lm_iconWrap"; - closeWrap.id = "lm_closeWrap"; - closeWrap.onclick = (e: MouseEvent) => { - tab.header.parent.contentItem.remove(); - Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", tab.DashDoc); - Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", tab.DashDoc, undefined, true, true); - }; + const docIcon = ; - const closeIcon = ; + const closeIcon = ; ReactDOM.render(docIcon, iconWrap); ReactDOM.render(closeIcon, closeWrap); tab.reactComponents = [iconWrap, closeWrap]; - // tab.element[0].append(closeWrap); tab.element[0].prepend(iconWrap); tab._disposers.layerDisposer = reaction(() => ({ layer: tab.DashDoc.activeLayer, color: this.tabColor }), ({ layer, color }) => { -- cgit v1.2.3-70-g09d2 From 04fd9f20ccdc204dad5724008b076cbf9ea7b874 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 10 Jun 2022 13:02:49 -0400 Subject: fixed some initialization problems with tabs --- src/client/util/History.ts | 6 ++-- .../views/collections/CollectionDockingView.tsx | 32 ++++++++++++---------- 2 files changed, 22 insertions(+), 16 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/util/History.ts b/src/client/util/History.ts index e6f75a7db..632348306 100644 --- a/src/client/util/History.ts +++ b/src/client/util/History.ts @@ -58,8 +58,10 @@ export namespace HistoryUtil { export function getState(): ParsedUrl { const state = copyState(history.state); - state.initializers = state.initializers || {}; - return state; + if (state) { + state.initializers = state.initializers || {}; + } + return state ?? {initializers:{}}; } // export function addHandler(handler: (state: ParsedUrl | null) => void) { diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 4119fb5ba..d2687df17 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -188,10 +188,13 @@ export class CollectionDockingView extends CollectionSubView() { stack.addChild(docContentConfig, undefined); stack.setActiveContentItem(stack.contentItems[stack.contentItems.length - 1]); } else { - const newItemStackConfig = { type: 'stack', content: [docContentConfig] }; - const newContentItem = glayRoot.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout); + const newContentItem = () => { + const newItem = glayRoot.layoutManager.createContentItem({ type: 'stack', content: [docContentConfig] }, instance._goldenLayout); + newItem.callDownwards('_$init'); + return newItem; + } if (glayRoot.contentItems.length === 0) { // if no rows / columns - glayRoot.addChild(newContentItem); + glayRoot.addChild(newContentItem()); } else if (glayRoot.contentItems[0].isStack) { glayRoot.contentItems[0].addChild(docContentConfig); } else if ( @@ -203,32 +206,33 @@ export class CollectionDockingView extends CollectionSubView() { else if (instance._goldenLayout.root.contentItems[0].isRow) { // if row switch (pullSide) { default: - case "right": glayRoot.contentItems[0].addChild(newContentItem); break; - case "left": glayRoot.contentItems[0].addChild(newContentItem, 0); break; + case "right": glayRoot.contentItems[0].addChild(newContentItem()); break; + case "left": glayRoot.contentItems[0].addChild(newContentItem(), 0); break; case "top": case "bottom": // if not going in a row layout, must add already existing content into column const rowlayout = glayRoot.contentItems[0]; const newColumn = rowlayout.layoutManager.createContentItem({ type: "column" }, instance._goldenLayout); + const newItem = newContentItem(); instance._goldenLayout.saveScrollTops(rowlayout.element); rowlayout.parent.replaceChild(rowlayout, newColumn); if (pullSide === "top") { newColumn.addChild(rowlayout, undefined, true); - newColumn.addChild(newContentItem, 0, true); + newColumn.addChild(newItem, 0, true); } else if (pullSide === "bottom") { - newColumn.addChild(newContentItem, undefined, true); + newColumn.addChild(newItem, undefined, true); newColumn.addChild(rowlayout, 0, true); } instance._goldenLayout.restoreScrollTops(rowlayout.element); rowlayout.config.height = 50; - newContentItem.config.height = 50; + newItem.config.height = 50; } } else {// if (instance._goldenLayout.root.contentItems[0].isColumn) { // if column switch (pullSide) { - case "top": glayRoot.contentItems[0].addChild(newContentItem, 0); break; - case "bottom": glayRoot.contentItems[0].addChild(newContentItem); break; + case "top": glayRoot.contentItems[0].addChild(newContentItem(), 0); break; + case "bottom": glayRoot.contentItems[0].addChild(newContentItem()); break; case "left": case "right": default: @@ -236,23 +240,23 @@ export class CollectionDockingView extends CollectionSubView() { const collayout = glayRoot.contentItems[0]; const newRow = collayout.layoutManager.createContentItem({ type: "row" }, instance._goldenLayout); + const newItem = newContentItem(); instance._goldenLayout.saveScrollTops(collayout.element); collayout.parent.replaceChild(collayout, newRow); if (pullSide === "left") { newRow.addChild(collayout, undefined, true); - newRow.addChild(newContentItem, 0, true); + newRow.addChild(newItem, 0, true); } else { - newRow.addChild(newContentItem, undefined, true); + newRow.addChild(newItem, undefined, true); newRow.addChild(collayout, 0, true); } instance._goldenLayout.restoreScrollTops(collayout.element); collayout.config.width = 50; - newContentItem.config.width = 50; + newItem.config.width = 50; } } instance._ignoreStateChange = JSON.stringify(instance._goldenLayout.toConfig()); - newContentItem.callDownwards('_$init'); } return instance.layoutChanged(); -- cgit v1.2.3-70-g09d2 From c0826fb904f5d2448635b5dae1fc4337fead939e Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 20 Jun 2022 05:31:25 -0400 Subject: lots of changes to try to cleanup CurrentUserUtils so changes can be made without rebuilding the DB. --- src/client/documents/Documents.ts | 10 +- src/client/util/CurrentUserUtils.ts | 1216 +++++++++----------- src/client/util/DocumentManager.ts | 3 +- src/client/util/Scripting.ts | 2 +- src/client/views/DocComponent.tsx | 2 +- src/client/views/GlobalKeyHandler.ts | 2 +- src/client/views/MainView.tsx | 36 +- src/client/views/OverlayView.tsx | 2 +- src/client/views/PropertiesView.tsx | 5 +- .../views/collections/CollectionDockingView.tsx | 2 +- src/client/views/collections/CollectionMenu.tsx | 6 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- .../collectionLinear/CollectionLinearView.tsx | 4 +- src/client/views/linking/LinkPopup.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 8 +- src/client/views/nodes/FilterBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 12 +- src/client/views/nodes/button/FontIconBox.tsx | 2 +- src/client/views/nodes/trails/PresBox.tsx | 8 +- src/fields/Doc.ts | 5 +- src/fields/util.ts | 3 + src/mobile/MobileInterface.tsx | 2 +- 22 files changed, 629 insertions(+), 711 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 5f009573e..927996af2 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -178,10 +178,15 @@ export class DocumentOptions { hidden?: boolean; _hidden?: boolean; pointerEvents?: string; // pointer events that the documentview should have - mediaState?: string; // status of media document: "pendingRecording", "recording", "paused", "playing" + mediaState?: string; // status of audio/video media document: "pendingRecording", "recording", "paused", "playing" + recording?: boolean; // whether WebCam is recording or not autoPlayAnchors?: boolean; // whether to play audio/video when an anchor is clicked in a stackedTimeline. dontPlayLinkOnSelect?: boolean; // whether an audio/video should start playing when a link is followed to it. toolTip?: string; // tooltip to display on hover + contextMenuFilters?: List; + contextMenuScripts?: List; + contextMenuLabels?: List; + contextMenuIcons?: List; dontUndo?: boolean; // whether button clicks should be undoable (this is set to true for Undo/Redo/and sidebar buttons that open the siebar panel) description?: string; // added for links layout?: string | Doc; // default layout string for a document @@ -238,7 +243,7 @@ export class DocumentOptions { isPushpin?: boolean; isGroup?: boolean; // whether a collection should use a grouping UI behavior _removeDropProperties?: List; // list of properties that should be removed from a document when it is dropped. e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document - + noteType?: string; // BACKGROUND GRID _backgroundGridShow?: boolean; @@ -286,6 +291,7 @@ export class DocumentOptions { clickFactory?: Doc; // document to create when clicking on a button with a suitable onClick script onDragStart?: ScriptField; //script to execute at start of drag operation -- e.g., when a "creator" button is dragged this script generates a different document to drop cloneFieldFilter?: List; // fields not to copy when the document is clonedclipboard?: Doc; + filterBoolean ?: string; useCors?: boolean; icon?: string; target?: Doc; // available for use in scripts as the primary target document diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index b4e18a8bb..afb1442bf 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1,16 +1,17 @@ import { computed, observable, reaction } from "mobx"; import * as rp from 'request-promise'; -import { DataSym, Doc, DocListCast, DocListCastAsync } from "../../fields/Doc"; +import { DataSym, Doc, DocListCast, DocListCastAsync, StrListCast } from "../../fields/Doc"; import { Id } from "../../fields/FieldSymbols"; import { InkTool } from "../../fields/InkField"; import { List } from "../../fields/List"; import { PrefetchProxy } from "../../fields/Proxy"; import { RichTextField } from "../../fields/RichTextField"; +import { listSpec } from "../../fields/Schema"; import { ComputedField, ScriptField } from "../../fields/ScriptField"; -import { BoolCast, Cast, DateCast, DocCast, NumCast, PromiseValue, StrCast } from "../../fields/Types"; +import { BoolCast, Cast, DateCast, DocCast, FieldValue, NumCast, PromiseValue, ScriptCast, StrCast } from "../../fields/Types"; import { ImageField, nullAudio } from "../../fields/URLField"; import { SharingPermissions } from "../../fields/util"; -import { Utils } from "../../Utils"; +import { OmitKeys, Utils } from "../../Utils"; import { DocServer } from "../DocServer"; import { Docs, DocumentOptions, DocUtils } from "../documents/Documents"; import { DocumentType } from "../documents/DocumentTypes"; @@ -42,17 +43,17 @@ interface Button { toolTip?: string; icon?: string; btnType?: ButtonType; - click?: string; numBtnType?: NumButtonType; numBtnMin?: number; numBtnMax?: number; switchToggle?: boolean; - script?: string; width?: number; - list?: string[]; + btnList?: List; ignoreClick?: boolean; buttonText?: string; - hidden?: string; + scripts?: { script?: string; onClick?: string; } + funcs?: { [key:string]: string }; + subMenu?: Button[]; } export let resolvedPorts: { server: number, socket: number }; @@ -73,101 +74,134 @@ export class CurrentUserUtils { @observable public static headerBarHeight: number = 0; @observable public static searchPanelWidth: number = 0; - // sets up the default User Templates - slideView, headerView - static setupExperimentalTemplateButtons(doc: Doc) { - if (doc["template-experimental-buttons"] === undefined) { - const requiredTypeNameFields = [ - { - type: "slide", icon: "address-card", template: Docs.Create.MultirowDocument( - [ - Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }), - Docs.Create.TextDocument("", { title: "text", _height: 100, system: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) }) - ], - { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, system: true } - ) - }, - { - type: "mobile", icon: "mobile", template: this.mobileButton({ title: "NEW MOBILE BUTTON", onClick: undefined, }, - [this.createToolButton({ ignoreClick: true, icon: "mobile", backgroundColor: "transparent" }), - this.mobileTextContainer({}, - [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")]) - ] - ) - }, - ]; - const requiredTypes = requiredTypeNameFields.map(({ type, icon, template }) => { - if (doc[`template-button-${type}`] === undefined) { - template.isTemplateDoc = makeTemplate(template); - doc[`template-button-${type}`] = CurrentUserUtils.createToolButton({ - onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'), - dragFactory: new PrefetchProxy(template) as any as Doc, - title: type, - icon, - }); + static AssignScripts(doc:Doc, scripts?:{ [key: string]: string;}, functions?:{[key:string]: string}) { + scripts && Object.keys(scripts).map(key => { + if (ScriptCast(doc[key])?.script.originalScript !== scripts[key] && scripts[key]) { + doc[key] = ScriptField.MakeScript(scripts[key], { dragData: DragManager.DocumentDragData.name, value:"any", scriptContext: "any" }, {"_readOnly_": true}); + } + }); + functions && Object.keys(functions).map(key => { + const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); + if (ScriptCast(cfield)?.script.originalScript !== functions[key] && functions[key]) { + doc[key] = ComputedField.MakeFunction(functions[key], { dragData: DragManager.DocumentDragData.name }, {"_readOnly_": true}); + } + }); + return doc; + } + static AssignOpts(doc:Doc|undefined, reqdOpts:DocumentOptions, items?:Doc[]) { + if (doc) { + const compareValues = (val1:any, val2:any) => { + if (val1 instanceof List && val2 instanceof List && val1.length === val2.length) { + return !val1.some(v => !val2.includes(v)) || !val2.some(v => val1.includes(v)); + } + return val1 === val2; + } + Object.entries(reqdOpts).forEach(pair => { + const targetDoc = pair[0].startsWith("_") ? doc : Doc.GetProto(doc as Doc); + if (!Object.getOwnPropertyNames(targetDoc).includes(pair[0].replace(/^_/,"")) || + !compareValues(pair[1], targetDoc[pair[0]])) { + targetDoc[pair[0]] = pair[1]; } - return doc[`template-button-${type}`] as Doc; }); - - doc["template-experimental-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument(requiredTypes, { - title: "Experimental Tools", _xMargin: 0, _showTitle: "title", _chromeHidden: true, - hidden: ComputedField.MakeFunction("IsNoviceMode()") as any, - _stayInCollection: true, _hideContextMenu: true, _forceActive: true, - _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true, - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true - })); + items?.forEach(item => !DocListCast(doc.data).includes(item) && Doc.AddDocToList(Doc.GetProto(doc), "data", item)); } - return doc["template-experimental-buttons"] as Doc; + return doc; } - // setup the different note type skins - static setupNoteTemplates(doc: Doc) { - if (doc["template-notes"] === undefined) { - const requiredTypeNameFields = [ - { type: "Note", backgroundColor: "yellow", icon: "sticky-note" }, - { type: "Idea", backgroundColor: "pink", icon: "lightbulb" }, - { type: "Topic", backgroundColor: "lightblue", icon: "book-open" }]; - const requiredTypes = requiredTypeNameFields.map(({ type, backgroundColor, icon }) => - doc[`template-note-${type}`] as Doc ?? - (() => { - const noteView = Docs.Create.TextDocument("", { title: "text", backgroundColor, system: true, icon }); - noteView.isTemplateDoc = makeTemplate(noteView, true, type); - return doc[`template-note-${type}`] = new PrefetchProxy(noteView); - })()); - - doc["template-notes"] = new PrefetchProxy(Docs.Create.TreeDocument(requiredTypes, { title: "Note Layouts", _height: 75, system: true })); - } + // initializes experimental advanced template views - slideView, headerView + static setupExperimentalTemplateButtons(doc: Doc, field="template-experimental-buttons") { + const tempDocs = DocCast(doc[field]); + const requiredTypeNameFields:{opts:DocumentOptions, template:() => Doc}[] = [ + { + opts:{type: "slide", icon: "address-card"}, template: () => Docs.Create.MultirowDocument( + [ + Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }), + Docs.Create.TextDocument("", { title: "text", _height: 100, system: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) }) + ], + { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, system: true } + ) + }, + { + opts:{type: "mobile", icon: "mobile"}, template: () => this.mobileButton({ title: "NEW MOBILE BUTTON", onClick: undefined, }, + [this.createToolButton({ ignoreClick: true, icon: "mobile", backgroundColor: "transparent" }), + this.mobileTextContainer({}, + [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")]) + ] + ) + }, + ]; + const requiredTypes = requiredTypeNameFields.map(({ opts, template }) => { + const docType = DocListCast(tempDocs?.data)?.find(doc => doc.title === opts.type); + const reqdOpts = { + dragFactory: template(), + title: opts.type, + icon: opts.icon + }; + const reqdScripts = {onDragStart: 'copyDragFactory(this.dragFactory)'}; + const makeTemp = (doc:Doc) => { + doc.isTemplateDoc = makeTemplate(doc); + return doc; + } + return this.AssignScripts(!docType ? makeTemp(CurrentUserUtils.createToolButton(reqdOpts)) : this.AssignOpts(docType, reqdOpts)!, reqdScripts)!; + }); + + const reqdOpts = { + title: "Experimental Tools", _xMargin: 0, _showTitle: "title", _chromeHidden: true, + _stayInCollection: true, _hideContextMenu: true, _forceActive: true, system: true, + _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true, + }; + const reqdScripts = {dropConverter : "convertToButtons(dragData)"}; + const reqdFuncs = {hidden: "IsNoviceMode()"} + return this.AssignScripts(!tempDocs ? + (doc[field] = Docs.Create.MasonryDocument(requiredTypes, reqdOpts)) : + this.AssignOpts(tempDocs, reqdOpts, requiredTypes)!, + reqdScripts, reqdFuncs); + } + + /// Initializes templates that can be applied to notes + static setupNoteTemplates(doc: Doc, field="template-notes") { + const tempNotes = DocCast(doc[field]); + const reqdTempOpts:DocumentOptions[] = [ + { noteType: "Note", backgroundColor: "yellow", icon: "sticky-note"}, + { noteType: "Idea", backgroundColor: "pink", icon: "lightbulb" }, + { noteType: "Topic", backgroundColor: "lightblue", icon: "book-open" }]; + const reqdNoteList = reqdTempOpts.map(opts => { + const reqdOpts = {...opts, title: "text", system: true}; + const noteType = tempNotes ? DocListCast(tempNotes.data).find(doc => doc.noteType === opts.noteType): undefined; + const makeTemp = (doc:Doc, noteType?:string) => { + doc.isTemplateDoc = makeTemplate(doc, true, noteType??"Note"); + return doc; + } + return this.AssignOpts(noteType, reqdOpts) ?? makeTemp(Docs.Create.TextDocument("",reqdOpts), opts.noteType); + }); - return doc["template-notes"] as Doc; + const reqdOpts:DocumentOptions = { title: "Note Layouts", _height: 75, system: true }; + return this.AssignOpts(tempNotes, reqdOpts, reqdNoteList) ?? (doc[field] = Docs.Create.TreeDocument(reqdNoteList, reqdOpts)); } - // creates Note templates, and initial "user" templates + /// Initializes collection of templates for notes and click functions static setupDocTemplates(doc: Doc) { - if (doc.templateDocs === undefined) { - doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([ - CurrentUserUtils.setupNoteTemplates(doc), - CurrentUserUtils.setupExperimentalTemplateButtons(doc), - CurrentUserUtils.setupClickEditorTemplates(doc) - ], { - title: "template layouts", _xMargin: 0, system: true, - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }) - })); - } + const templates = [ + CurrentUserUtils.setupNoteTemplates(doc), + CurrentUserUtils.setupClickEditorTemplates(doc) + ]; + const reqdOpts = { title: "template layouts", _xMargin: 0, system: true, }; + const reqdScripts = { dropConverter: "convertToButtons(dragData)" }; + return this.AssignScripts(this.AssignOpts(DocCast(doc.templateDocs), reqdOpts, templates) ?? (doc.templateDocs = Docs.Create.TreeDocument(templates, reqdOpts)), reqdScripts); } // setup templates for different document types when they are iconified from Document Decorations - static setupDefaultIconTemplates(doc: Doc) { - const templateIconsDoc = Cast(doc["template-icons"], Doc, null); + static setupDefaultIconTemplates(doc: Doc, field="template-icons") { + const templateIconsDoc = DocCast(doc[field]); const makeIconTemplate = (type: DocumentType | undefined, templateField: string, iconTemplate: () => Doc) => { const iconFieldName = "icon" + (type ? "_" + type : ""); if (!templateIconsDoc?.[iconFieldName]) { const template = MakeTemplate(iconTemplate(), true, iconFieldName, templateField); if (templateIconsDoc) { - templateIconsDoc[iconFieldName] = new PrefetchProxy(template); - Doc.AddDocToList(templateIconsDoc, "data", template); - } else { - return template; + templateIconsDoc[iconFieldName] = template; } + return template; } }; const deiconifyScript = () => ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }); @@ -182,46 +216,57 @@ export class CurrentUserUtils { const fontBox = () => Docs.Create.FontIconDocument({ _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, system: true, onClick: deiconifyScript() }); - if (!templateIconsDoc) { - const newIconsList = [ - makeIconTemplate(undefined, "title", () => labelBox({ _backgroundColor: "dimgray" })), - makeIconTemplate(DocumentType.AUDIO, "title", () => labelBox({ _backgroundColor: "lightgreen" })), - makeIconTemplate(DocumentType.PDF, "title", () => labelBox({ _backgroundColor: "pink" })), - makeIconTemplate(DocumentType.WEB, "title", () => labelBox({ _backgroundColor: "brown" })), - makeIconTemplate(DocumentType.RTF, "text", () => labelBox({ _showTitle: "creationDate" })), - makeIconTemplate(DocumentType.IMG, "data", () => imageBox("", { _height: undefined, })), - makeIconTemplate(DocumentType.COL, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})), - makeIconTemplate(DocumentType.VID, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})), - makeIconTemplate(DocumentType.BUTTON, "data", fontBox), - //nasty hack .. templates are looked up exclusively by type -- but we want a template for a document with a certain field (transcription) .. so this hack and the companion hack in createCustomView does this for now - makeIconTemplate("transcription" as any, "transcription", () => labelBox({ _backgroundColor: "orange" })), - // makeIconTemplate(DocumentType.PDF, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})) - ].filter(d => d).map(d => d!); - - doc["template-icons"] = Docs.Create.TreeDocument(newIconsList, { title: "icon templates", _height: 75, system: true }); - } + const iconTemplates = [ + makeIconTemplate(undefined, "title", () => labelBox({ _backgroundColor: "dimgray" })), + makeIconTemplate(DocumentType.AUDIO, "title", () => labelBox({ _backgroundColor: "lightgreen" })), + makeIconTemplate(DocumentType.PDF, "title", () => labelBox({ _backgroundColor: "pink" })), + makeIconTemplate(DocumentType.WEB, "title", () => labelBox({ _backgroundColor: "brown" })), + makeIconTemplate(DocumentType.RTF, "text", () => labelBox({ _showTitle: "creationDate" })), + makeIconTemplate(DocumentType.IMG, "data", () => imageBox("", { _height: undefined, })), + makeIconTemplate(DocumentType.COL, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})), + makeIconTemplate(DocumentType.VID, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})), + makeIconTemplate(DocumentType.BUTTON, "data", fontBox), + //nasty hack .. templates are looked up exclusively by type -- but we want a template for a document with a certain field (transcription) .. so this hack and the companion hack in createCustomView does this for now + makeIconTemplate("transcription" as any, "transcription", () => labelBox({ _backgroundColor: "orange" })), + // makeIconTemplate(DocumentType.PDF, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})) + ].filter(d => d).map(d => d!); + + const reqdOpts = { title: "icon templates", _height: 75, system: true }; + this.AssignOpts(templateIconsDoc, reqdOpts, iconTemplates) ?? (doc[field] = Docs.Create.TreeDocument(iconTemplates, reqdOpts)); } + /// initalizes the set of default versions of most document types static creatorBtnDescriptors(doc: Doc): { - title: string, toolTip: string, icon: string, drag?: string, ignoreClick?: boolean, - click?: string, backgroundColor?: string, dragFactory?: Doc, noviceMode?: boolean, clickFactory?: Doc + title: string, toolTip: string, icon: string, ignoreClick?: boolean, dragFactory?: Doc, + backgroundColor?: string, clickFactory?: Doc, scripts?: { onClick?: string, onDragStart?: string}, funcs?: {onDragStart?:string, hidden?: string}, }[] { const standardOps = () => ({ _fitWidth: true, system: true, "dragFactory-count": 0, cloneFieldFilter: new List(["system"]) }); - if (doc.emptyPresentation === undefined) { - doc.emptyPresentation = Docs.Create.PresDocument({ ...standardOps(), title: "Untitled Presentation", _viewType: CollectionViewType.Stacking, _width: 400, _height: 500, targetDropAction: "alias", _chromeHidden: true, boxShadow: "0 0" }); - } - if (doc.emptyCollection === undefined) { - doc.emptyCollection = Docs.Create.FreeformDocument([], { ...standardOps(), title: "freeform", _width: 150, _height: 100 }); - } - if (doc.emptyPane === undefined) { - doc.emptyPane = Docs.Create.FreeformDocument([], { ...standardOps(), title: "Untitled Tab", _backgroundGridShow: true, _width: 500, _height: 800 }); - } - if (doc.emptySlide === undefined) { - doc.emptySlide = Docs.Create.TreeDocument([], { - ...standardOps(), title: ComputedField.MakeFunction('self.text?.Text') as any, _viewType: CollectionViewType.Tree, treeViewHasOverlay: true, _fontSize: "20px", _autoHeight: true, "dragFactory-count": undefined, - allowOverlayDrop: true, treeViewType: TreeViewType.outline, _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, backgroundColor: "white" - }); - } + const emptyThings:{key:string, // the field name where the empty thing will be stored + opts:DocumentOptions, // the document options that are required for the empty thing + funcs?:{[key:string]: any}, // computed fields that are rquired for the empth thing + creator:(opts:DocumentOptions)=> any // how to create the empty thing if it doesn't exist + }[] = [ + {key: "emptyPresentation", creator: Docs.Create.PresDocument, opts: { title: "Untitled Presentation", _viewType: CollectionViewType.Stacking, _width: 400, _height: 500, targetDropAction: "alias" as any, _chromeHidden: true, boxShadow: "0 0" }}, + {key: "emptyCollection", creator: (opts) => Docs.Create.FreeformDocument([], opts), opts: { title: "freeform", _width: 150, _height: 100 }}, + {key: "emptyPane", creator: (opts) => Docs.Create.FreeformDocument([], opts), opts : { title: "Untitled Tab", _backgroundGridShow: true, _width: 500, _height: 800 }}, + {key: "emptySlide", creator: (opts) => Docs.Create.TreeDocument([], opts), funcs: {title: 'self.text?.Text'}, opts: { + _viewType: CollectionViewType.Tree, treeViewHasOverlay: true, _fontSize: "20px", _autoHeight: true, + "dragFactory-count": undefined, allowOverlayDrop: true, treeViewType: TreeViewType.outline, _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, backgroundColor: "white" + }}, + {key: "emptyComparison", creator: Docs.Create.ComparisonDocument, opts: { title: "Comparer", _width: 300, _height: 300 }}, + {key: "emptyScript", creator: (opts) => Docs.Create.ScriptingDocument(undefined, opts), opts: { title: "script", _width: 200, _height: 250, }}, + {key: "emptyScreenshot", creator: Docs.Create.ScreenshotDocument, opts: { title: "empty screenshot", _width: 400, _height: 200 }}, + {key: "emptyWebCam", creator: (opts) => Docs.Create.WebCamDocument("", opts), opts: { _width: 400, _height: 200, title: "recording", recording:true, system: true, cloneFieldFilter: new List(["system"]) }}, + {key: "emptyAudio", creator: (opts) => Docs.Create.AudioDocument(nullAudio, opts), opts: { title: "audio recording", x: 200, y: 200, _width: 200, _height: 100, }}, + {key: "emptyNote", creator: (opts) => Docs.Create.TextDocument("", opts), opts: { title: "text note", _width: 200, _autoHeight: true }}, + {key: "emptyButton", creator: Docs.Create.ButtonDocument, opts: { title: "Button", _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, }}, + {key: "emptyWebpage", creator: (opts) => Docs.Create.WebDocument("http://www.bing.com/", opts), opts: { title: "webpage", _nativeWidth: 850, _height: 512, _width: 400, useCors: true, }}, + {key: "emptyMap", creator: (opts) => Docs.Create.MapDocument([], opts), opts: { title: "map", _showSidebar: true, _width: 800, _height: 600, }} + ]; + + emptyThings.forEach(thing => + this.AssignScripts(this.AssignOpts(DocCast(doc[thing.key]), {...standardOps(), ...thing.opts}) ?? (doc[thing.key] = thing.creator({...standardOps(), ...thing.opts})), thing.funcs)) + if (doc.emptyHeader === undefined) { const json = { doc: { @@ -242,196 +287,124 @@ export class CurrentUserUtils { selection: { type: "text", anchor: 1, head: 1 }, storedMarks: [] }; - const headerTemplate = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { - ...standardOps(), title: "text", _height: 70, - _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true, - }, "header"); const headerBtnHgt = 10; - headerTemplate[DataSym].layout = + const headerTemplate = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { + ...standardOps(), title: "text", _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true, + layout: "" + ` ` + " " + ` Metadata` + - ""; + "" + }, "header"); // "
" + // " " + // " " + // "
"; - (headerTemplate.proto as Doc).isTemplateDoc = makeTemplate(headerTemplate.proto as Doc, true, "headerView"); + Doc.GetProto(headerTemplate).isTemplateDoc = makeTemplate(Doc.GetProto(headerTemplate), true, "headerView"); doc.emptyHeader = headerTemplate; } - if (doc.emptyComparison === undefined) { - doc.emptyComparison = Docs.Create.ComparisonDocument({ ...standardOps(), title: "Comparer", _width: 300, _height: 300 }); - } - if (doc.emptyScript === undefined) { - doc.emptyScript = Docs.Create.ScriptingDocument(undefined, { ...standardOps(), title: "script", _width: 200, _height: 250, }); - } - if (doc.emptyScreenshot === undefined) { - doc.emptyScreenshot = Docs.Create.ScreenshotDocument({ ...standardOps(), title: "empty screenshot", _width: 400, _height: 200 }); - } - if (doc.emptyWall === undefined) { - doc.emptyWall = Docs.Create.WebCamDocument("", { _width: 400, _height: 200, title: "recording", system: true, cloneFieldFilter: new List(["system"]) }); - (doc.emptyWall as Doc).recording = true; - } - if (doc.emptyAudio === undefined) { - doc.emptyAudio = Docs.Create.AudioDocument(nullAudio, { ...standardOps(), title: "audio recording", x: 200, y: 200, _width: 200, _height: 100, }); - } - if (doc.emptyNote === undefined) { - doc.emptyNote = Docs.Create.TextDocument("", { ...standardOps(), title: "text note", _width: 200, _autoHeight: true }); - } - if (doc.emptyButton === undefined) { - doc.emptyButton = Docs.Create.ButtonDocument({ ...standardOps(), title: "Button", _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, }); - } - if (doc.emptyWebpage === undefined) { - doc.emptyWebpage = Docs.Create.WebDocument("http://www.bing.com/", { ...standardOps(), title: "webpage", _nativeWidth: 850, _height: 512, _width: 400, useCors: true, }); - } - if (doc.emptyMap === undefined) { - doc.emptyMap = Docs.Create.MapDocument([], { ...standardOps(), title: "map", _showSidebar: true, _width: 800, _height: 600, }); - } - if (doc.activeMobileMenu === undefined) { - this.setupActiveMobileMenu(doc); - } + return [ - { toolTip: "Tap to create a note in a new pane, drag for a note", title: "Note", icon: "sticky-note", click: 'openOnRight(copyDragFactory(this.clickFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyNote as Doc, noviceMode: true, clickFactory: doc.emptyNote as Doc, }, - { toolTip: "Tap to create a collection in a new pane, drag for a collection", title: "Col", icon: "folder", click: 'openOnRight(copyDragFactory(this.clickFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyCollection as Doc, noviceMode: true, clickFactory: doc.emptyPane as Doc, }, - { toolTip: "Tap to create a webpage in a new pane, drag for a webpage", title: "Web", icon: "globe-asia", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyWebpage as Doc, noviceMode: true }, - { toolTip: "Tap to create a progressive slide", title: "Slide", icon: "file", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptySlide as Doc }, - { toolTip: "Tap to create a comparison box in a new pane, drag for a comparison box", title: "Compare", icon: "columns", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyComparison as Doc, noviceMode: true }, - { toolTip: "Tap to create a screen grabber in a new pane, drag for a screen grabber", title: "Grab", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScreenshot as Doc }, - { toolTip: "Tap to create a videoWall", title: "Wall", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyWall as Doc }, - { toolTip: "Tap to create an audio recorder in a overlay pane, drag for an audio recorder", title: "Audio", icon: "microphone", click: 'openInOverlay(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyAudio as Doc, noviceMode: true }, - { toolTip: "Tap to create a button in a new pane, drag for a button", title: "Button", icon: "bolt", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyButton as Doc }, - // { toolTip: "Tap to create a presentation in a new pane, drag for a presentation", title: "Trails", icon: "pres-trail", click: 'openOnRight(Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory))', drag: `Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory)`, dragFactory: doc.emptyPresentation as Doc, noviceMode: true }, - { toolTip: "Tap to create a scripting box in a new pane, drag for a scripting box", title: "Script", icon: "terminal", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScript as Doc }, - { toolTip: "Tap to create a mobile view in a new pane, drag for a mobile view", title: "Phone", icon: "mobile", click: 'openOnRight(Doc.UserDoc().activeMobileMenu)', drag: 'this.dragFactory', dragFactory: doc.activeMobileMenu as Doc }, - { toolTip: "Tap to create a custom header note document, drag for a custom header note", title: "Custom", icon: "window-maximize", click: 'openOnRight(delegateDragFactory(this.dragFactory))', drag: 'delegateDragFactory(this.dragFactory)', dragFactory: doc.emptyHeader as Doc }, - { toolTip: "Toggle a Calculator REPL", title: "repl", icon: "calculator", click: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' }, - { toolTip: "Tap to create a map in the new pane, drag for a map", title: "Map", icon: "map-marker-alt", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyMap as Doc, noviceMode: true } - ]; - + { toolTip: "Tap or drag to create a note", title: "Note", icon: "sticky-note", dragFactory: doc.emptyNote as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, }, + { toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.clickFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, clickFactory: doc.emptyPane as Doc, }, + { toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, }, + { toolTip: "Tap or drag to create a comparison box", title: "Compare", icon: "columns", dragFactory: doc.emptyComparison as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, }, + { toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, scripts: {onClick: 'openInOverlay(copyDragFactory(this.dragFactory))',onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, }, + { toolTip: "Tap or drag to create a map", title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, }, + { toolTip: "Tap or drag to create a custom note", title: "Custom", icon: "window-maximize", dragFactory: doc.emptyHeader as Doc, scripts: {onClick: 'openOnRight(delegateDragFactory(this.dragFactory))', onDragStart: '{ return delegateDragFactory(this.dragFactory);}'}, }, + { toolTip: "Tap or drag to create a progressive slide",title: "Slide", icon: "file", dragFactory: doc.emptySlide as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs: { hidden: 'IsNoviceMode()'} }, + { toolTip: "Tap or drag to create a screen grabber", title: "Grab", icon: "photo-video", dragFactory: doc.emptyScreenshot as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs: { hidden: 'IsNoviceMode()'} }, + { toolTip: "Tap or drag to create a WebCam recorder", title: "WebCam", icon: "photo-video", dragFactory: doc.emptyWebCam as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs: { hidden: 'IsNoviceMode()'}}, + { toolTip: "Tap or drag to create a button", title: "Button", icon: "bolt", dragFactory: doc.emptyButton as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs:{ hidden: 'IsNoviceMode()'} }, + { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs: { hidden: 'IsNoviceMode()'}}, + { toolTip: "Tap or drag to create a mobile view", title: "Phone", icon: "mobile", dragFactory: doc.activeMobileMenu as Doc, scripts: {onClick: 'openOnRight(Doc.UserDoc().activeMobileMenu)', onDragStart: 'this.dragFactory'}, funcs: {hidden: 'IsNoviceMode()'} }, + { toolTip: "Toggle a Calculator REPL", title: "repl", icon: "calculator", scripts: {onClick: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' } }, + // { toolTip: "Tap or drag to create a presentation", title: "Trails", icon: "pres-trail", dragFactory: doc.emptyPresentation as Doc,scripts: {onClick: 'openOnRight(Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory))', onDragStart: `Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory)`}, funcs: {hidden: 'IsNoviceMode()'} }, + ]; } - // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools - static setupCreatorButtons(doc: Doc) { - let alreadyCreatedButtons: string[] = []; - const dragCreatorSet = Cast(doc.myItemCreators, Doc, null); - if (dragCreatorSet) { - alreadyCreatedButtons = DocListCast(dragCreatorSet.data).map(d => StrCast(d.title)); - } - const buttons = CurrentUserUtils.creatorBtnDescriptors(doc).filter(d => !alreadyCreatedButtons?.includes(d.title)); - const creatorBtns = buttons.map(({ title, toolTip, icon, ignoreClick, drag, click, backgroundColor, dragFactory, noviceMode, clickFactory }) => Docs.Create.FontIconDocument({ - _nativeWidth: 50, _nativeHeight: 50, _width: 35, _height: 35, - icon, - title, - toolTip, - btnType: ButtonType.ToolButton, - ignoreClick, - _dropAction: "alias", - onDragStart: drag ? ScriptField.MakeFunction(drag) : undefined, - onClick: click ? ScriptField.MakeScript(click) : undefined, - backgroundColor: backgroundColor ? backgroundColor : Colors.DARK_GRAY, - color: Colors.WHITE, - _hideContextMenu: true, - _removeDropProperties: new List(["_stayInCollection"]), - _stayInCollection: true, - dragFactory, - clickFactory, - hidden: !noviceMode ? ComputedField.MakeFunction("IsNoviceMode()") as any : undefined, - system: true, - })); + /// Initalizes the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools + static setupCreatorButtons(doc: Doc, dragCreatorDoc?:Doc):Doc { + const creatorBtns = CurrentUserUtils.creatorBtnDescriptors(doc).map((reqdOpts) => { + const btn = dragCreatorDoc ? DocListCast(dragCreatorDoc.data).find(doc => doc.title === reqdOpts.title): undefined; + const opts:DocumentOptions = {...OmitKeys(reqdOpts, ["backgroundColor"]).omit, + _nativeWidth: 50, _nativeHeight: 50, _width: 35, _height: 35, _hideContextMenu: true, _stayInCollection: true, _dropAction: "alias", + btnType: ButtonType.ToolButton, backgroundColor: reqdOpts.backgroundColor ?? Colors.DARK_GRAY, color: Colors.WHITE, system: true, + _removeDropProperties: new List(["_stayInCollection"]), + }; + return this.AssignScripts(this.AssignOpts(btn, opts) ?? Docs.Create.FontIconDocument(opts), reqdOpts.scripts, reqdOpts.funcs); + }); - if (dragCreatorSet === undefined) { - doc.myItemCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, { - title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, - _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true, - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true - })); - } else { - creatorBtns.forEach(nb => Doc.AddDocToList(doc.myItemCreators as Doc, "data", nb)); - } - return doc.myItemCreators as Doc; + const reqdOpts = { + title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, system: true, + _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true, + }; + const reqdScripts = { dropConverter: "convertToButtons(dragData)" }; + return this.AssignScripts(this.AssignOpts(dragCreatorDoc, reqdOpts, creatorBtns) ?? Docs.Create.MasonryDocument(creatorBtns, reqdOpts), reqdScripts); } - static menuBtnDescriptions(doc: Doc) { - const badgeValue = ScriptField.MakeFunction("((len) => len ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length)") + /// returns descriptions needed to buttons for the left sidebar to open up panes displaying different collections of documents + static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}}[] { + const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())"; return [ - { title: "Dashboards", target: Cast(doc.myDashboards, Doc, null), icon: "desktop", click: 'selectMainMenu(self)' }, - { title: "Search", target: Cast(doc.mySearchPanel, Doc, null), icon: "search", click: 'selectMainMenu(self)' }, - { title: "Files", target: Cast(doc.myFilesystem, Doc, null), icon: "folder-open", click: 'selectMainMenu(self)' }, - { title: "Tools", target: Cast(doc.myTools, Doc, null), icon: "wrench", click: 'selectMainMenu(self)', hidden: "IsNoviceMode()" }, - { title: "Imports", target: Cast(doc.myImportDocs, Doc, null), icon: "upload", click: 'selectMainMenu(self)' }, - { title: "Recently Closed", target: Cast(doc.myRecentlyClosedDocs, Doc, null), icon: "archive", click: 'selectMainMenu(self)' }, - { title: "Shared with me", target: Cast(doc.mySharedDocs, Doc, null), icon: "users", click: 'selectMainMenu(self)', badgeValue}, - { title: "Trails", target: Cast(doc.myTrails, Doc, null), icon: "pres-trail", click: 'selectMainMenu(self)' }, - { title: "User Doc", target: Cast(doc.myUserDoc, Doc, null), icon: "address-card", click: 'selectMainMenu(self)', hidden: "IsNoviceMode()" }, + { title: "Dashboards", target: CurrentUserUtils.MyDashboards, icon: "desktop", scripts:{onClick: 'selectMainMenu(self)'} }, + { title: "Search", target: CurrentUserUtils.MySearcher, icon: "search", scripts:{onClick: 'selectMainMenu(self)'} }, + { title: "Files", target: CurrentUserUtils.MyFilesystem, icon: "folder-open", scripts:{onClick: 'selectMainMenu(self)'} }, + { title: "Tools", target: CurrentUserUtils.MyTools, icon: "wrench", scripts:{onClick: 'selectMainMenu(self)'}, funcs: {hidden: "IsNoviceMode()"} }, + { title: "Imports", target: CurrentUserUtils.MyImports, icon: "upload", scripts:{onClick: 'selectMainMenu(self)'} }, + { title: "Recently Closed", target: CurrentUserUtils.MyRecentlyClosed, icon: "archive", scripts:{onClick: 'selectMainMenu(self)'} }, + { title: "Shared with me", target: CurrentUserUtils.MySharedDocs, icon: "users", scripts:{onClick: 'selectMainMenu(self)'}, funcs:{badgeValue:badgeValue}}, + { title: "Trails", target: CurrentUserUtils.MyTrails, icon: "pres-trail", scripts:{onClick: 'selectMainMenu(self)'} }, + { title: "User Doc", target: CurrentUserUtils.MyUserDocView, icon: "address-card",scripts:{onClick: 'selectMainMenu(self)'}, funcs: {hidden: "IsNoviceMode()"} }, ]; } - static async setupMenuPanel(doc: Doc, sharingDocumentId: string, linkDatabaseId: string) { - if (doc.menuStack === undefined) { - await this.setupLinkDocs(doc, linkDatabaseId); - await this.setupSharedDocs(doc, sharingDocumentId); // sets up the right sidebar collection for mobile upload documents and sharing - const menuBtns = CurrentUserUtils.menuBtnDescriptions(doc).map(({ title, target, icon, click, badgeValue, hidden }) => - Docs.Create.FontIconDocument({ - icon, - btnType: ButtonType.MenuButton, - _stayInCollection: true, - _hideContextMenu: true, - _chromeHidden: true, - system: true, - dontUndo: true, - title, - target, - dontRegisterView: true, - hidden: hidden ? ComputedField.MakeFunction("IsNoviceMode()") as any : undefined, - _dropAction: "alias", - _removeDropProperties: new List(["dropAction", "_stayInCollection"]), - _width: 60, - _height: 60, - badgeValue, - onClick: ScriptField.MakeScript(click, { scriptContext: "any" }) - }) - ); - - doc.searchBtn = menuBtns.find(btn => btn.title === "Search"); - - doc.menuStack = new PrefetchProxy(Docs.Create.StackingDocument(menuBtns, { - title: "menuItemPanel", - childDropAction: "alias", - _chromeHidden: true, - backgroundColor: Colors.DARK_GRAY, - boxShadow: "rgba(0,0,0,0)", - dontRegisterView: true, - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), - ignoreClick: true, - _gridGap: 0, - _yMargin: 0, - _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, system: true - })); - } - return doc.menuStack as Doc; + /// setup the left sidebar container and panels that can be displayed within it + static setupLeftSidebarPanel(doc: Doc, field="myLeftSidebarPanel") { + this.AssignOpts(DocCast(doc[field]), {}) ?? (doc[field] = ((doc:Doc) => {doc.system = true; return doc;})(new Doc())); + CurrentUserUtils.setupSearcher(doc, "mySearcher"); + CurrentUserUtils.setupToolsBtnPanel(doc, "myTools"); + CurrentUserUtils.setupImportSidebar(doc, "myImports"); + CurrentUserUtils.setupDashboards(doc, "myDashboards"); + CurrentUserUtils.setupTrails(doc, "myTrails"); + CurrentUserUtils.setupFilesystem(doc, "myFilesystem"); + CurrentUserUtils.setupRecentlyClosedDocs(doc, "myRecentlyClosed"); + CurrentUserUtils.setupUserDocView(doc, "myUserDocView"); } + /// Initializes the left sidebar menu buttons and the panels they open up + static setupLeftSidebarMenu(doc: Doc, field="myLeftSidebarMenu") { + this.setupLeftSidebarPanel(doc); // the tools/panels opened up by the menu buttons + const myLeftSidebarMenu = DocCast(doc[field]); + const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, scripts, funcs }) => { + const btnDoc = myLeftSidebarMenu ? DocListCast(myLeftSidebarMenu.data).find(doc => doc.title === title) : undefined; + const reqdBtnOpts:DocumentOptions = { + title, icon, target, btnType: ButtonType.MenuButton, system: true, dontUndo: true, dontRegisterView: true, + _width: 60, _height: 60, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, _dropAction: "alias", + _removeDropProperties: new List(["dropAction", "_stayInCollection"]), + }; + return this.AssignScripts(this.AssignOpts(btnDoc, reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), scripts, funcs); + }); - // Sets up mobile menu if it is undefined creates a new one, otherwise returns existing menu - static setupActiveMobileMenu(doc: Doc) { - if (doc.activeMobileMenu === undefined) { - doc.activeMobileMenu = this.setupMobileMenu(); - } - return doc.activeMobileMenu as Doc; + const reqdStackOpts:DocumentOptions ={ + title: "menuItemPanel", childDropAction: "alias", backgroundColor: Colors.DARK_GRAY, boxShadow: "rgba(0,0,0,0)", dontRegisterView: true, ignoreClick: true, + _chromeHidden: true, _gridGap: 0, _yMargin: 0, _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, system: true + }; + const reqdScripts = { dropConverter: "convertToButtons(dragData)" } + return this.AssignScripts(this.AssignOpts(myLeftSidebarMenu, reqdStackOpts, menuBtns) ?? (doc[field] = Docs.Create.StackingDocument(menuBtns, reqdStackOpts)), reqdScripts); } - // Sets up mobileMenu stacking document - static setupMobileMenu() { - const menu = new PrefetchProxy(Docs.Create.StackingDocument(this.setupMobileButtons(), { - _width: 980, ignoreClick: true, _lockedPosition: false, title: "home", _yMargin: 100, system: true, _chromeHidden: true, - })); - return menu; + // Sets up mobile menu if it is undefined creates a new one, otherwise returns existing menu + static setupActiveMobileMenu(doc: Doc, field="activeMobileMenu") { + const reqdOpts = { _width: 980, ignoreClick: true, _lockedPosition: false, title: "home", _yMargin: 100, system: true, _chromeHidden: true,}; + this.AssignOpts(DocCast(doc[field]), reqdOpts, this.setupMobileButtons()) ?? (doc[field] = Docs.Create.StackingDocument(this.setupMobileButtons(), reqdOpts)); } - // SEts up mobile buttons for inside mobile menu + // Sets up mobile buttons for inside mobile menu static setupMobileButtons(doc?: Doc, buttons?: string[]) { + return []; const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, backgroundColor?: string, info: string, dragFactory?: Doc }[] = [ { title: "DASHBOARDS", icon: "bars", click: 'switchToMobileLibrary()', backgroundColor: "lightgrey", info: "Access your Dashboards from your mobile, and navigate through all of your documents. " }, { title: "UPLOAD", icon: "upload", click: 'openMobileUploads()', backgroundColor: "lightgrey", info: "Upload files from your mobile device so they can be accessed on Dash Web." }, @@ -533,375 +506,329 @@ export class CurrentUserUtils { }); } - static setupLibrary(userDoc: Doc) { - return CurrentUserUtils.setupDashboards(userDoc); - } - - // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker. - // when clicked, this panel will be displayed in the target container (ie, sidebarContainer) - static setupToolsBtnPanel(doc: Doc) { - // setup a masonry view of all he creators - const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc); - const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc); - - doc.myCreators = doc.myCreators ?? new PrefetchProxy(Docs.Create.StackingDocument([creatorBtns, templateBtns], { - title: "all Creators", _yMargin: 0, _autoHeight: true, _xMargin: 0, _fitWidth: true, - _width: 500, _height: 300, ignoreClick: true, _lockedPosition: true, system: true, _chromeHidden: true, - })); - if (!DocListCast(doc.myCreators).includes(creatorBtns) || !DocListCast(doc.myCreators).includes(templateBtns)) Doc.GetProto(doc.myCreators as Doc).data = new List([creatorBtns, templateBtns]); - - doc.myColorPicker = doc.myColorPicker ?? new PrefetchProxy(Docs.Create.ColorDocument({ - title: "color picker", _width: 220, _dropAction: "alias", _hideContextMenu: true, _stayInCollection: true, _forceActive: true, _removeDropProperties: new List(["dropAction", "_stayInCollection", "_hideContextMenu", "forceActive"]), system: true - })); - - doc.myTools = doc.myTools ?? new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc], { - title: "My Tools", _showTitle: "title", _width: 500, _yMargin: 20, ignoreClick: true, _lockedPosition: true, _forceActive: true, - system: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, boxShadow: "0 0", - })) as any as Doc; - if (!DocListCast(doc.myTools).includes(doc.myCreators as Doc)) Doc.GetProto(doc.myTools as Doc).data = new List([doc.myCreators as Doc]); - } - - static async setupDashboards(doc: Doc) { - // setup dashboards library item - await doc.myDashboards; - if (doc.myDashboards === undefined) { - const newDashboard = ScriptField.MakeScript(`createNewDashboard(Doc.UserDoc())`); - const newDashboardButton: Doc = Docs.Create.FontIconDocument({ onClick: newDashboard, _forceActive: true, toolTip: "Create new dashboard", _stayInCollection: true, _hideContextMenu: true, title: "new dashboard", btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "New trail", icon: "plus", system: true }); - doc.myDashboards = new PrefetchProxy(Docs.Create.TreeDocument([], { - title: "My Dashboards", _showTitle: "title", _height: 400, childHideLinkButton: true, freezeChildren: "remove|add", - treeViewHideTitle: true, _gridGap: 5, _forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, ignoreClick: true, buttonMenu: true, buttonMenuDoc: newDashboardButton, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, system: true, - explainer: "This is your collection of dashboards. A dashboard represents the tab configuration of your workspace. To manage documents as folders, go to the Files." - })); - const toggleDarkTheme = ScriptField.MakeScript(`this.colorScheme = this.colorScheme ? undefined : "${ColorScheme.Dark}"`); - const toggleComic = ScriptField.MakeScript(`toggleComicMode()`); - const snapshotDashboard = ScriptField.MakeScript(`snapshotDashboard()`); - const shareDashboard = ScriptField.MakeScript(`shareDashboard(self)`); - const removeDashboard = ScriptField.MakeScript('removeDashboard(self)'); - const developerFilter = ScriptField.MakeFunction('!IsNoviceMode()'); - // (doc.myDashboards as any as Doc).childContextMenuScripts = new List([newDashboard!, shareDashboard!, removeDashboard!]); - // (doc.myDashboards as any as Doc).childContextMenuLabels = new List(["Create New Dashboard", "Share Dashboard", "Remove Dashboard"]); - // (doc.myDashboards as any as Doc).childContextMenuIcons = new List(["plus", "user-friends", "times"]); - (doc.myDashboards as any as Doc).childContextMenuScripts = new List([newDashboard!, toggleDarkTheme!, toggleComic!, snapshotDashboard!, shareDashboard!, removeDashboard!]); - (doc.myDashboards as any as Doc).childContextMenuLabels = new List(["Create New Dashboard", "Toggle Dark Theme", "Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard"]); - (doc.myDashboards as any as Doc).childContextMenuIcons = new List(["plus", "chalkboard", "tv", "camera", "users", "times"]); - (doc.myDashboards as any as Doc).childContextMenuFilters = new List([undefined as any, developerFilter, developerFilter, developerFilter, undefined as any, undefined as any]); - } - return doc.myDashboards as any as Doc; + /// Search option on the left side button panel + static setupSearcher(doc: Doc, field:string) { + const reqdOpts:DocumentOptions = { + dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Search Panel", system: true, childDropAction: "alias", + _lockedPosition: true, _viewType: CollectionViewType.Schema, _searchDoc: true, + }; + this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.SearchDocument(reqdOpts)); } - static setupPresentations(doc: Doc) { - if (doc.myTrails === undefined) { - const newTrail = ScriptField.MakeScript(`createNewPresentation()`); - const newTrailButton: Doc = Docs.Create.FontIconDocument({ onClick: newTrail, _forceActive: true, toolTip: "Create new trail", _stayInCollection: true, _hideContextMenu: true, title: "New trail", btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "New trail", icon: "plus", system: true }); - doc.myTrails = new PrefetchProxy(Docs.Create.TreeDocument([], { - title: "My Trails", _showTitle: "title", _height: 100, - treeViewHideTitle: true, _fitWidth: true, _gridGap: 5, _forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, ignoreClick: true, buttonMenu: true, buttonMenuDoc: newTrailButton, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true, - explainer: "All of the trails that you have created will appear here." - })); - (doc.myTrails as any as Doc).contextMenuScripts = new List([newTrail!]); - (doc.myTrails as any as Doc).contextMenuLabels = new List(["Create New Trail"]); - (doc.myTrails as any as Doc).childContextMenuIcons = new List(["plus"]); - } - return doc.myTrails as any as Doc; + /// Initializes the panel of draggable tools that is opened from the left sidebar. + static setupToolsBtnPanel(doc: Doc, field:string) { + const myTools = DocCast(doc[field]); + const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc, DocListCast(myTools?.data)?.length ? DocListCast(myTools.data)[0]:undefined); + //const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc); + const reqdToolOps:DocumentOptions = { + title: "My Tools", system: true, ignoreClick: true, boxShadow: "0 0", + _showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, + }; + this.AssignOpts(myTools, reqdToolOps, [creatorBtns, /*templateBtns*/]) ?? (doc[field] = Docs.Create.StackingDocument([creatorBtns, /*templateBtns*/], reqdToolOps)); } - static async setupFilesystem(doc: Doc) { - await doc.myFilesystem; - if (doc.myFilesystem === undefined) { - doc.myFileOrphans = Docs.Create.TreeDocument([], { title: "Unfiled", _stayInCollection: true, system: true, isFolder: true }); - // doc.myFileRoot = Docs.Create.TreeDocument([], { title: "file root", _stayInCollection: true, system: true, isFolder: true }); - const newFolder = ScriptField.MakeFunction(`makeTopLevelFolder()`, { scriptContext: "any" })!; - const newFolderButton: Doc = Docs.Create.FontIconDocument({ - onClick: newFolder, _forceActive: true, toolTip: "Create new folder", - _stayInCollection: true, _hideContextMenu: true, title: "New folder", btnType: ButtonType.ClickButton, _width: 30, _height: 30, - buttonText: "New folder", icon: "folder-plus", system: true - }); - doc.myFilesystem = new PrefetchProxy(Docs.Create.TreeDocument([doc.myFileOrphans as Doc], { - title: "My Documents", _showTitle: "title", buttonMenu: true, buttonMenuDoc: newFolderButton, _height: 100, - treeViewHideTitle: true, _gridGap: 5, _forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, ignoreClick: true, - isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "proto", system: true, - explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard." - })); - (doc.myFilesystem as any as Doc).contextMenuScripts = new List([newFolder]); - (doc.myFilesystem as any as Doc).contextMenuLabels = new List(["Create new folder"]); - (doc.myFilesystem as any as Doc).childContextMenuIcons = new List(["plus"]); + /// initializes the left sidebar dashboard pane + static setupDashboards(doc: Doc, field:string) { + var myDashboards = DocCast(doc[field]); + + const newDashboard = `createNewDashboard(Doc.UserDoc())`; + const reqdBtnOpts:DocumentOptions = { _forceActive: true, _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, + title: "new dashboard", btnType: ButtonType.ClickButton, toolTip: "Create new dashboard", buttonText: "New trail", icon: "plus", system: true }; + const reqdBtnScript = {onClick: newDashboard,} + const newDashboardButton = this.AssignScripts(this.AssignOpts(DocCast(myDashboards?.buttonMenuDoc), reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript); + + const reqdOpts:DocumentOptions = { + title: "My Dashboards", childHideLinkButton: true, freezeChildren: "remove|add", treeViewHideTitle: true, boxShadow: "0 0", childDontRegisterViews: true, + targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, system: true, treeViewTruncateTitleWidth: 150, ignoreClick: true, + buttonMenu: true, buttonMenuDoc: newDashboardButton, childDropAction: "alias", + _showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true, + contextMenuLabels: new List(["Create New Dashboard"]), + contextMenuIcons: new List(["plus"]), + childContextMenuLabels: new List(["Toggle Dark Theme", "Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard"]),// entries must be kept in synch with childContextMenuScripts, childContextMenuIcons, and childContextMenuFilters + childContextMenuIcons: new List(["chalkboard", "tv", "camera", "users", "times"]), // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters + explainer: "This is your collection of dashboards. A dashboard represents the tab configuration of your workspace. To manage documents as folders, go to the Files." + }; + myDashboards = this.AssignOpts(myDashboards, reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([], reqdOpts)); + const toggleDarkTheme = `this.colorScheme = this.colorScheme ? undefined : "${ColorScheme.Dark}"`; + const contextMenuScripts = [newDashboard]; + const childContextMenuScripts = [toggleDarkTheme, `toggleComicMode()`, `snapshotDashboard()`, `shareDashboard(self)`, 'removeDashboard(self)']; // entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuFilters + const childContextMenuFilters = ['!IsNoviceMode()', '!IsNoviceMode()', '!IsNoviceMode()', undefined as any, undefined as any];// entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuScripts + if (Cast(myDashboards.contextMenuScripts, listSpec(ScriptField), null)?.length !== contextMenuScripts.length) { + myDashboards.contextMenuScripts = new List(contextMenuScripts.map(script => ScriptField.MakeFunction(script)!)); + } + if (Cast(myDashboards.childContextMenuScripts, listSpec(ScriptField), null)?.length !== childContextMenuScripts.length) { + myDashboards.childContextMenuScripts = new List(childContextMenuScripts.map(script => ScriptField.MakeFunction(script)!)); + } + if (Cast(myDashboards.childContextMenuFilters, listSpec(ScriptField), null)?.length !== childContextMenuFilters.length) { + myDashboards.childContextMenuFilters = new List(childContextMenuFilters.map(script => !script ? script: ScriptField.MakeFunction(script)!)); } - return doc.myFilesystem as any as Doc; } - static setupRecentlyClosedDocs(doc: Doc) { - if (doc.myRecentlyClosedDocs === undefined) { - const clearAll = ScriptField.MakeScript(`getProto(self).data = new List([])`); - const clearDocsButton: Doc = Docs.Create.FontIconDocument({ onClick: clearAll, _forceActive: true, toolTip: "Empty recently closed", _stayInCollection: true, _hideContextMenu: true, title: "Empty", btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "Empty", icon: "trash", system: true }); - doc.myRecentlyClosedDocs = new PrefetchProxy(Docs.Create.TreeDocument([], { - title: "My Recently Closed", _showTitle: "title", buttonMenu: true, buttonMenuDoc: clearDocsButton, childHideLinkButton: true, - treeViewHideTitle: true, _gridGap: 5, _forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, ignoreClick: true, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true, - explainer: "Recently closed documents appear in this menu. They will only be deleted if you explicity empty this list." - - })); - (doc.myRecentlyClosedDocs as any as Doc).contextMenuScripts = new List([clearAll!]); - (doc.myRecentlyClosedDocs as any as Doc).contextMenuLabels = new List(["Empty recently closed"]); - (doc.myRecentlyClosedDocs as any as Doc).contextMenuIcons = new List(["trash"]); - + /// initializes the left sidebar Trails pane + static setupTrails(doc: Doc, field:string) { + var myTrails = DocCast(doc[field]); + const reqdBtnOpts:DocumentOptions = { _forceActive: true, _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, + title: "New trail", toolTip: "Create new trail", btnType: ButtonType.ClickButton, buttonText: "New trail", icon: "plus", system: true }; + const reqdBtnScript = {onClick: `createNewPresentation()`}; + const newTrailButton = this.AssignScripts(this.AssignOpts(DocCast(myTrails?.buttonMenuDoc), reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript); + + const reqdOpts:DocumentOptions = { + title: "My Trails", _showTitle: "title", _height: 100, + treeViewHideTitle: true, _fitWidth: true, _gridGap: 5, _forceActive: true, childDropAction: "alias", + treeViewTruncateTitleWidth: 150, ignoreClick: true, buttonMenu: true, buttonMenuDoc: newTrailButton, + contextMenuIcons: new List(["plus"]), + contextMenuLabels: new List(["Create New Trail"]), + _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true, + explainer: "All of the trails that you have created will appear here." + }; + myTrails = this.AssignOpts(myTrails, reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([],reqdOpts )); + const contextMenuScripts = [reqdBtnScript.onClick]; + if (Cast(myTrails.contextMenuScripts, listSpec(ScriptField), null)?.length !== contextMenuScripts.length) { + myTrails.contextMenuScripts = new List(contextMenuScripts.map(script => ScriptField.MakeFunction(script)!)); } } - static setupFilterDocs(doc: Doc) { - // setup Filter item - if (doc.currentFilter === undefined) { - doc.currentFilter = Docs.Create.FilterDocument({ - title: "Unnamed Filter", _height: 150, - treeViewHideTitle: true, _xPadding: 5, _yPadding: 5, _gridGap: 5, _forceActive: true, childDropAction: "none", - treeViewTruncateTitleWidth: 150, ignoreClick: true, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true, _autoHeight: true, _fitWidth: true - }); - const clearAll = ScriptField.MakeScript(`getProto(self).data = new List([])`); - (doc.currentFilter as Doc).contextMenuScripts = new List([clearAll!]); - (doc.currentFilter as Doc).contextMenuLabels = new List(["Clear All"]); - (doc.currentFilter as Doc).filterBoolean = "AND"; + /// initializes the left sidebar File system pane + static setupFilesystem(doc: Doc, field:string) { + var myFilesystem = DocCast(doc[field]); + const reqdOrphansOpts:DocumentOptions = { title: "Unfiled", _stayInCollection: true, system: true, isFolder: true }; + this.AssignOpts(DocCast(doc.myFileOrphans), reqdOrphansOpts) ?? (doc.myFileOrphans = Docs.Create.TreeDocument([], reqdOrphansOpts)); + + const newFolder = `makeTopLevelFolder()`; + const newFolderOpts: DocumentOptions = { + _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _width: 30, _height: 30, + title: "New folder", btnType: ButtonType.ClickButton, toolTip: "Create new folder", buttonText: "New folder", icon: "folder-plus", system: true + }; + const newFolderScript = { onClick: newFolder}; + const newFolderButton = this.AssignScripts(this.AssignOpts(DocCast(myFilesystem?.buttonMenuDoc), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript); + + const reqdOpts:DocumentOptions = { _showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true, + title: "My Documents", buttonMenu: true, buttonMenuDoc: newFolderButton, treeViewHideTitle: true, targetDropAction: "proto", system: true, + isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, boxShadow: "0 0", childDontRegisterViews: true, + treeViewTruncateTitleWidth: 150, ignoreClick: true, childDropAction: "alias", + childContextMenuLabels: new List(["Create new folder"]), + childContextMenuIcons: new List(["plus"]), + explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard." + }; + myFilesystem = this.AssignOpts(myFilesystem, reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([DocCast(doc.myFileOrphans)], reqdOpts)); + const childContextMenuScripts = [newFolder]; + if (Cast(myFilesystem.childContextMenuScripts, listSpec(ScriptField), null)?.length !== childContextMenuScripts.length) { + myFilesystem.childContextMenuScripts = new List(childContextMenuScripts.map(script => ScriptField.MakeFunction(script)!)); } } - static setupUserDoc(doc: Doc) { - if (doc.myUserDoc === undefined) { - doc.treeViewOpen = true; - doc.treeViewExpandedView = "fields"; - doc.myUserDoc = new PrefetchProxy(Docs.Create.TreeDocument([doc], { - treeViewHideTitle: true, _gridGap: 5, _forceActive: true, title: "My UserDoc", _showTitle: "title", - treeViewTruncateTitleWidth: 150, ignoreClick: true, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true - })) as any as Doc; + /// initializes the panel displaying docs that have been recently closed + static setupRecentlyClosedDocs(doc: Doc, field:string) { + const reqdOpts:DocumentOptions = { _showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, + title: "My Recently Closed", buttonMenu: true, childHideLinkButton: true, treeViewHideTitle: true, childDropAction: "alias", system: true, + treeViewTruncateTitleWidth: 150, ignoreClick: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", + contextMenuLabels: new List(["Empty recently closed"]), + contextMenuIcons:new List(["trash"]), + explainer: "Recently closed documents appear in this menu. They will only be deleted if you explicity empty this list." + }; + const recentlyClosed = this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([], reqdOpts)); + + const clearAll = (target:string) => `getProto(${target}).data = new List([])`; + const clearBtnsOpts:DocumentOptions = { _width: 30, _height: 30, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, + title: "Empty", target: recentlyClosed, btnType: ButtonType.ClickButton, buttonText: "Empty", icon: "trash", system: true, + toolTip: "Empty recently closed",}; + const clearBtnsScripts = {onClick: clearAll("self.target")} + const clearDocsButton = this.AssignScripts( + this.AssignOpts(DocCast(recentlyClosed?.clearDocsBtn), clearBtnsOpts) ?? (recentlyClosed.clearDocsBtn = Docs.Create.FontIconDocument(clearBtnsOpts)), + clearBtnsScripts); + + if (recentlyClosed.buttonMenuDoc !== clearDocsButton) Doc.GetProto(recentlyClosed).buttonMenuDoc = clearDocsButton; + + if (!Cast(recentlyClosed.contextMenuScripts, listSpec(ScriptField),null)?.find((script) => script.script.originalScript === clearAll("self"))) { + recentlyClosed.contextMenuScripts = new List([ScriptField.MakeScript(clearAll("self"))!]) } } - static setupSidebarContainer(doc: Doc) { - if (doc.sidebar === undefined) { - const sidebarContainer = new Doc(); - sidebarContainer.system = true; - doc.sidebar = new PrefetchProxy(sidebarContainer); - } - return doc.sidebar as Doc; + /// creates a new, empty filter doc + static createFilterDoc() { + const clearAll = `getProto(self).data = new List([])`; + const reqdOpts:DocumentOptions = { + _lockedPosition: true, _autoHeight: true, _fitWidth: true, _height: 150, _xPadding: 5, _yPadding: 5, _gridGap: 5, _forceActive: true, + title: "Unnamed Filter", filterBoolean: "AND", boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, system: true, + childDropAction: "none", treeViewHideTitle: true, treeViewTruncateTitleWidth: 150, + childContextMenuLabels: new List(["Clear All"]), + childContextMenuScripts: new List([ScriptField.MakeFunction(clearAll)!]), + }; + return Docs.Create.FilterDocument(reqdOpts); } - // setup the list of sidebar mode buttons which determine what is displayed in the sidebar - static async setupSidebarButtons(doc: Doc) { - CurrentUserUtils.setupSidebarContainer(doc); - CurrentUserUtils.setupToolsBtnPanel(doc); - CurrentUserUtils.setupImportSidebar(doc); - CurrentUserUtils.setupDashboards(doc); - CurrentUserUtils.setupPresentations(doc); - CurrentUserUtils.setupFilesystem(doc); - CurrentUserUtils.setupRecentlyClosedDocs(doc); - CurrentUserUtils.setupUserDoc(doc); + /// initializes the left sidebar panel view of the UserDoc + static setupUserDocView(doc: Doc, field:string) { + const reqdOpts:DocumentOptions = { + _lockedPosition: true, _gridGap: 5, _forceActive: true, title: Doc.CurrentUserEmail +"-view", + boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, system: true, + treeViewHideTitle: true, treeViewTruncateTitleWidth: 150 + }; + if (!doc[field]) this.AssignOpts(doc, {treeViewOpen: true, treeViewExpandedView: "fields" }) + this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([doc], reqdOpts)); } - static linearButtonList = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, { - ...opts, _gridGap: 0, _xMargin: 5, _yMargin: 5, boxShadow: "0 0", _forceActive: true, + static linearButtonList = (title: string, opts: DocumentOptions, docs: Doc[]) => Docs.Create.LinearDocument(docs, { + title, ...opts, _gridGap: 0, _xMargin: 5, _yMargin: 5, boxShadow: "0 0", _forceActive: true, dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), _lockedPosition: true, system: true, flexDirection: "row" - })) as any as Doc + }) - static createToolButton = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ + static createToolButton = (opts: DocumentOptions) => Docs.Create.FontIconDocument({ btnType: ButtonType.ToolButton, _forceActive: true, _dropAction: "alias", _hideContextMenu: true, _removeDropProperties: new List(["_dropAction", "_hideContextMenu", "stayInCollection"]), _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, system: true, ...opts, - })) as any as Doc - - /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window - static setupDockedButtons(doc: Doc) { - if (doc.dockedBtns === undefined) { - const dockBtn = (opts: DocumentOptions) => CurrentUserUtils.createToolButton({ _width: 30, _height: 30, dontUndo: true, _stayInCollection: true, ...opts }); - const btnDescs = [ - { title: "undo", opts: () => ({ icon: "undo-alt", onClick: ScriptField.MakeScript("undo()"), toolTip: "Click to undo" }) }, - { title: "redo", opts: () => ({ icon: "redo-alt", onClick: ScriptField.MakeScript("redo()"), toolTip: "Click to redo" }) } - ]; - doc.dockedBtns = CurrentUserUtils.linearButtonList({ - title: "docked buttons", _height: 40, flexGap: 0, linearViewFloating: true, - childDontRegisterViews: true, linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true - }, btnDescs.map(desc => doc[`dockedBtn-${desc.title}`] as Doc ?? (doc[`dockedBtn-${desc.title}`] = dockBtn({ title: desc.title, ...desc.opts() })))); + }) + + /// initializes the required buttons in the expanding button menu at the bottom of the Dash window + static setupDockedButtons(doc: Doc, field="myDockedBtns") { + const dockedBtns = DocCast(doc[field]); + const dockBtn = (title:string, onClick: string, opts: DocumentOptions) => { + const btn = this.AssignOpts(DocListCast(dockedBtns?.data)?.find(doc => doc.title === title), opts) ?? + CurrentUserUtils.createToolButton({title, ...opts}); + this.AssignScripts(btn, {onClick}) + return btn; } + const btnDescs = [// setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet + { title: "undo", click: "undo()", opts: { icon: "undo-alt", toolTip: "Click to undo" }}, + { title: "redo", click:"redo()", opts: { icon: "redo-alt", toolTip: "Click to redo" }} + ]; + const btns = btnDescs.map(desc => dockBtn(desc.title, desc.click, {_width: 30, _height: 30, dontUndo: true, _stayInCollection: true, ...desc.opts})); + const dockBtnsReqdOpts = { + title: "docked buttons", _height: 40, flexGap: 0, linearViewFloating: true, + childDontRegisterViews: true, linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true + }; + reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "redo")!).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true }); + reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "undo")!).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true }); + return this.AssignOpts(dockedBtns, dockBtnsReqdOpts, btns) ?? (doc[field] = CurrentUserUtils.linearButtonList("dockedBtns", dockBtnsReqdOpts, btns)); } - static textTools(doc: Doc) { - const tools: Button[] = - [ - { - title: "Font", toolTip: "Font", width: 100, btnType: ButtonType.DropdownList, ignoreClick: true, - list: ["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia", - "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"], - script: 'setFont(value, _readOnly_)' - }, - { title: "Size", toolTip: "Font size", width: 75, btnType: ButtonType.NumberButton, numBtnMax: 200, numBtnMin: 0, numBtnType: NumButtonType.DropdownOptions, ignoreClick: true, script: 'setFontSize(value, _readOnly_)' }, - { title: "Color", toolTip: "Font color", btnType: ButtonType.ColorButton, icon: "font", ignoreClick: true, script: 'setFontColor(value, _readOnly_)' }, - { title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", click: 'toggleBold(_readOnly_)' }, - { title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", click: 'toggleItalic(_readOnly_)' }, - { title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", click: 'toggleUnderline(_readOnly_)' }, - { title: "Bullets", toolTip: "Bullet List", btnType: ButtonType.ToggleButton, icon: "list", click: 'setBulletList("bullet", _readOnly_)' }, - { title: "#", toolTip: "Number List", btnType: ButtonType.ToggleButton, icon: "list-ol", click: 'setBulletList("decimal", _readOnly_)' }, - - // { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", click: 'toggleStrikethrough()'}, - // { title: "Superscript", tooltip: "Superscript", btnType: ButtonType.ToggleButton, icon: "superscript", click: 'toggleSuperscript()'}, - // { title: "Subscript", tooltip: "Subscript", btnType: ButtonType.ToggleButton, icon: "subscript", click: 'toggleSubscript()'}, - { title: "Left", toolTip: "Left align", btnType: ButtonType.ToggleButton, icon: "align-left", click: 'setAlignment("left", _readOnly_)' }, - { title: "Center", toolTip: "Center align", btnType: ButtonType.ToggleButton, icon: "align-center", click: 'setAlignment("center", _readOnly_)' }, - { title: "Right", toolTip: "Right align", btnType: ButtonType.ToggleButton, icon: "align-right", click: 'setAlignment("right", _readOnly_)' }, - { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", click: 'toggleNoAutoLinkAnchor(_readOnly_)' }, - ]; - return tools; + static textTools():Button[] { + return [ + { + title: "Font", toolTip: "Font", width: 100, btnType: ButtonType.DropdownList, ignoreClick: true, + btnList: new List(["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia", "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"]), + scripts :{script : 'setFont(value, _readOnly_)'} + }, + { title: "Size", toolTip: "Font size", width: 75, btnType: ButtonType.NumberButton, numBtnMax: 200, numBtnMin: 0, numBtnType: NumButtonType.DropdownOptions, ignoreClick: true, scripts: {script: '{ return setFontSize(value, _readOnly_);}'} }, + { title: "Color", toolTip: "Font color", btnType: ButtonType.ColorButton, icon: "font", ignoreClick: true, scripts:{script: '{ return setFontColor(value, _readOnly_); }'}}, + { title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", scripts: {onClick: '{ return toggleBold(_readOnly_); }'} }, + { title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", scripts: {onClick: '{ return toggleItalic(_readOnly_);}'} }, + { title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline",scripts: {onClick:'{ return toggleUnderline(_readOnly_);}'} }, + { title: "Bullets", toolTip: "Bullet List", btnType: ButtonType.ToggleButton, icon: "list", scripts: {onClick: '{ return setBulletList("bullet", _readOnly_);}'} }, + { title: "#", toolTip: "Number List", btnType: ButtonType.ToggleButton, icon: "list-ol", scripts: {onClick: '{ return setBulletList("decimal", _readOnly_);}'} }, + + // { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", scripts: {onClick:: 'toggleStrikethrough()'}}, + // { title: "Superscript", tooltip: "Superscript", btnType: ButtonType.ToggleButton, icon: "superscript", scripts: {onClick:: 'toggleSuperscript()'}}, + // { title: "Subscript", tooltip: "Subscript", btnType: ButtonType.ToggleButton, icon: "subscript", scripts: {onClick:: 'toggleSubscript()'}}, + { title: "Left", toolTip: "Left align", btnType: ButtonType.ToggleButton, icon: "align-left", scripts: {onClick:'{ return setAlignment("left", _readOnly_);}' }}, + { title: "Center", toolTip: "Center align", btnType: ButtonType.ToggleButton, icon: "align-center", scripts: {onClick:'{ return setAlignment("center", _readOnly_);}'} }, + { title: "Right", toolTip: "Right align", btnType: ButtonType.ToggleButton, icon: "align-right", scripts: {onClick:'{ return setAlignment("right", _readOnly_);}'} }, + { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", scripts: {onClick:'{ return toggleNoAutoLinkAnchor(_readOnly_);}'}}, + ]; } - static inkTools(doc: Doc) { - const tools: Button[] = [ - { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", click: 'setActiveInkTool("pen", _readOnly_)' }, - { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", click: 'setActiveInkTool("write", _readOnly_)' }, - { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", click: 'setActiveInkTool("eraser", _readOnly_)' }, - // { title: "Highlighter", toolTip: "Highlighter (Ctrl+H)", btnType: ButtonType.ToggleButton, icon: "highlighter", click: 'setActiveInkTool("highlighter")' }, - { title: "Circle", toolTip: "Circle (Ctrl+Shift+C)", btnType: ButtonType.ToggleButton, icon: "circle", click: 'setActiveInkTool("circle", _readOnly_)' }, + static inkTools():Button[] { + return [ + { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", scripts:{onClick:'{ return setActiveInkTool("pen", _readOnly_);}' }}, + { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", scripts:{onClick:'{ return setActiveInkTool("write", _readOnly_);}'} }, + { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", scripts:{onClick:'{ return setActiveInkTool("eraser", _readOnly_);}' }}, + // { title: "Highlighter", toolTip: "Highlighter (Ctrl+H)", btnType: ButtonType.ToggleButton, icon: "highlighter", scripts:{onClick: 'setActiveInkTool("highlighter")'} }, + { title: "Circle", toolTip: "Circle (Ctrl+Shift+C)", btnType: ButtonType.ToggleButton, icon: "circle", scripts:{onClick:'{ return setActiveInkTool("circle", _readOnly_);}'} }, // { title: "Square", toolTip: "Square (Ctrl+Shift+S)", btnType: ButtonType.ToggleButton, icon: "square", click: 'setActiveInkTool("square")' }, - { title: "Line", toolTip: "Line (Ctrl+Shift+L)", btnType: ButtonType.ToggleButton, icon: "minus", click: 'setActiveInkTool("line", _readOnly_)' }, - { title: "Fill", toolTip: "Fill color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", script: "setFillColor(value, _readOnly_)" }, - { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberButton, numBtnType: NumButtonType.Slider, numBtnMin: 1, ignoreClick: true, script: 'setStrokeWidth(value, _readOnly_)' }, - { title: "Color", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", ignoreClick: true, script: 'setStrokeColor(value, _readOnly_)' }, + { title: "Line", toolTip: "Line (Ctrl+Shift+L)", btnType: ButtonType.ToggleButton, icon: "minus", scripts:{onClick: '{ return setActiveInkTool("line", _readOnly_);}' }}, + { title: "Fill", toolTip: "Fill color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", scripts: {script: "{ return setFillColor(value, _readOnly_);}"} }, + { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberButton, numBtnType: NumButtonType.Slider, numBtnMin: 1, ignoreClick: true, scripts: {script: '{ return setStrokeWidth(value, _readOnly_);}'} }, + { title: "Color", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", ignoreClick: true, scripts: {script: '{ return setStrokeColor(value, _readOnly_);}'} }, ]; - return tools; } - static schemaTools(doc: Doc) { - const tools: Button[] = - [{ title: "Show preview", toolTip: "Show preview of selected document", btnType: ButtonType.ToggleButton, buttonText: "Show Preview", icon: "eye", click: 'toggleSchemaPreview(_readOnly_)', }]; - return tools; + static schemaTools():Button[] { + return [{ title: "Show preview", toolTip: "Show preview of selected document", btnType: ButtonType.ToggleButton, buttonText: "Show Preview", icon: "eye", scripts:{onClick:'toggleSchemaPreview(_readOnly_)'}, }]; } - static webTools(doc: Doc) { - const tools: Button[] = - [ - { title: "Back", toolTip: "Go back", btnType: ButtonType.ClickButton, icon: "arrow-left", click: 'webBack(_readOnly_)' }, - { title: "Forward", toolTip: "Go forward", btnType: ButtonType.ClickButton, icon: "arrow-right", click: 'webForward(_readOnly_)' }, - //{ title: "Reload", toolTip: "Reload webpage", btnType: ButtonType.ClickButton, icon: "redo-alt", click: 'webReload()' }, - { title: "URL", toolTip: "URL", width: 250, btnType: ButtonType.EditableText, icon: "lock", ignoreClick: true, script: 'webSetURL(value, _readOnly_)' }, - ]; - - return tools; + static webTools() { + return [ + { title: "Back", toolTip: "Go back", btnType: ButtonType.ClickButton, icon: "arrow-left", click: 'webBack(_readOnly_)' }, + { title: "Forward", toolTip: "Go forward", btnType: ButtonType.ClickButton, icon: "arrow-right", click: 'webForward(_readOnly_)' }, + //{ title: "Reload", toolTip: "Reload webpage", btnType: ButtonType.ClickButton, icon: "redo-alt", click: 'webReload()' }, + { title: "URL", toolTip: "URL", width: 250, btnType: ButtonType.EditableText, icon: "lock", ignoreClick: true, script: 'webSetURL(value, _readOnly_)' }, + ]; } - static contextMenuTools(doc: Doc) { + static contextMenuTools():Button[] { return [ { title: "Perspective", toolTip: "View", width: 100, btnType: ButtonType.DropdownList, ignoreClick: true, - list: [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Tree, - CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.Multicolumn, - CollectionViewType.Multirow, CollectionViewType.Time, CollectionViewType.Carousel, - CollectionViewType.Carousel3D, CollectionViewType.Linear, CollectionViewType.Map, - CollectionViewType.Grid], - script: 'setView(value, _readOnly_)', + btnList: new List([CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Tree, + CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.Multicolumn, + CollectionViewType.Multirow, CollectionViewType.Time, CollectionViewType.Carousel, + CollectionViewType.Carousel3D, CollectionViewType.Linear, CollectionViewType.Map, + CollectionViewType.Grid]), + scripts: {script: 'setView(value, _readOnly_)'}, }, // Always show - { title: "Back", toolTip: "Prev Animation Frame", width: 20, btnType: ButtonType.ClickButton, click: 'prevKeyFrame(_readOnly_)', icon: "chevron-left", hidden: 'IsNoviceMode()' }, - { title: "Fwd", toolTip: "Next Animation Frame", width: 20, btnType: ButtonType.ClickButton, click: 'nextKeyFrame(_readOnly_)', icon: "chevron-right", hidden: 'IsNoviceMode()' }, - { title: "Fill", toolTip: "Background Fill Color", width: 20, btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", script: "setBackgroundColor(value, _readOnly_)", hidden: 'selectedDocumentType()' }, // Only when a document is selected - { title: "Header", toolTip: "Header Color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "heading", script: "setHeaderColor(value, _readOnly_)", hidden: 'selectedDocumentType()', }, - { title: "Overlay", toolTip: "Overlay", btnType: ButtonType.ToggleButton, icon: "layer-group", click: 'toggleOverlay(_readOnly_)', hidden: 'selectedDocumentType(undefined, "freeform", true)' }, // Only when floating document is selected in freeform + { title: "Back", toolTip: "Prev Animation Frame", width: 20, btnType: ButtonType.ClickButton,icon: "chevron-left", scripts:{onClick: 'prevKeyFrame(_readOnly_)'}, funcs: {hidden: 'IsNoviceMode()'} }, + { title: "Fwd", toolTip: "Next Animation Frame", width: 20, btnType: ButtonType.ClickButton, icon: "chevron-right", scripts:{onClick: 'nextKeyFrame(_readOnly_)'}, funcs: {hidden: 'IsNoviceMode()'}}, + { title: "Fill", toolTip: "Background Fill Color", width: 20, btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", scripts: { script: "setBackgroundColor(value, _readOnly_)"}, funcs:{ hidden: 'selectedDocumentType()' }}, // Only when a document is selected + { title: "Header", toolTip: "Header Color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "heading", scripts: {script: "setHeaderColor(value, _readOnly_)"}, funcs : {hidden: 'selectedDocumentType()'} }, + { title: "Overlay", toolTip: "Overlay", btnType: ButtonType.ToggleButton, icon: "layer-group", scripts: {onClick : 'toggleOverlay(_readOnly_)'}, funcs: {hidden: 'selectedDocumentType(undefined, "freeform", true)'} }, // Only when floating document is selected in freeform // { title: "Alias", btnType: ButtonType.ClickButton, icon: "copy", hidden: 'selectedDocumentType()' }, // Only when a document is selected - { title: "Text", type: "textTools", subMenu: CurrentUserUtils.textTools(doc), expanded: 'selectedDocumentType("rtf")' }, // Always available - { title: "Ink", type: "inkTools", subMenu: CurrentUserUtils.inkTools(doc), expanded: 'selectedDocumentType("ink")' }, // Always available - { title: "Web", type: "webTools", subMenu: CurrentUserUtils.webTools(doc), hidden: 'selectedDocumentType("web")' }, // Only when Web is selected - { title: "Schema", type: "schemaTools", subMenu: CurrentUserUtils.schemaTools(doc), hidden: 'selectedDocumentType(undefined, "schema")' } // Only when Schema is selected + { title: "Text", icon: "text", subMenu: CurrentUserUtils.textTools(), funcs: { linearViewIsExpanded: `selectedDocumentType("${DocumentType.RTF}")`} }, // Always available + { title: "Ink", icon: "ink", subMenu: CurrentUserUtils.inkTools(), funcs: { linearViewIsExpanded: `selectedDocumentType("${DocumentType.INK}")`} }, // Always available + { title: "Web", icon: "web", subMenu: CurrentUserUtils.webTools(), funcs: { linearViewIsExpanded: `selectedDocumentType("${DocumentType.WEB}")`, hidden: `!selectedDocumentType("${DocumentType.WEB}")`} }, // Only when Web is selected + { title: "Schema", icon: "schema", subMenu: CurrentUserUtils.schemaTools(), funcs: { linearViewIsExpanded: `selectedDocumentType(undefined, "${CollectionViewType.Schema}")`, hidden: `!selectedDocumentType(undefined, "${CollectionViewType.Schema}")`} } // Only when Schema is selected ]; } - // Sets up the default context menu buttons - static setupContextMenuButtons(doc: Doc) { - const btnFunc = (params: Button) => Docs.Create.FontIconDocument({ - title: params.title, icon: params.icon, toolTip: params.toolTip, color: Colors.WHITE, system: true, dontUndo: true, ignoreClick: params.ignoreClick, + /// initializes a context menu button for the top bar context menu + static setupContextMenuButton(params:Button, btnDoc?:Doc) { + const reqdOpts:DocumentOptions = { + title: params.title, btnType: params.btnType, icon: params.icon, toolTip: params.toolTip, ignoreClick: params.ignoreClick, + numBtnType: params.numBtnType, numBtnMin: params.numBtnMin, numBtnMax: params.numBtnMax,_nativeHeight: 30, btnList: params.btnList, + backgroundColor: params.scripts?.onClick ? undefined: "transparent", /// a bit hacky. if an onClick is specified, then we assume we assume a toggle use onClick to get the backgroundColor (see below). Otherwise, assume a transparent background _nativeWidth: params.width ? params.width : 30, - _nativeHeight: 30, _width: params.width ? params.width : 30, _height: 30, - btnType: params.btnType, - numBtnType: params.numBtnType, numBtnMin: params.numBtnMin, numBtnMax: params.numBtnMax, - btnList: new List(params.list), + color: Colors.WHITE, system: true, dontUndo: true, _stayInCollection: true, _hideContextMenu: true, _lockedPosition: true, _dropAction: "alias", _removeDropProperties: new List(["dropAction", "_stayInCollection"]), - script: params.script ? ScriptField.MakeScript(params.script, { value: "any" }) : undefined, - backgroundColor: params.click ? ComputedField.MakeFunction(params.click) as any : "transparent", - onClick: params.click ? ScriptField.MakeScript(params.click, { scriptContext: "any" }, { _readOnly_: false }) : undefined, - hidden: params.hidden ? ComputedField.MakeFunction(params.hidden) as any : undefined, - }); - if (doc.contextMenuBtns === undefined) { - doc.contextMenuBtns = CurrentUserUtils.linearButtonList( - { title: "menu buttons", flexGap: 0, childDontRegisterViews: true, linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 }, - CurrentUserUtils.contextMenuTools(doc).map(params => - !params.subMenu ? - btnFunc(params) : - CurrentUserUtils.linearButtonList({ - title: params.title, - childDontRegisterViews: true, - linearViewSubMenu: true, flexGap: 0, ignoreClick: true, - linearViewExpandable: true, icon: params.title, _height: 30, - linearViewIsExpanded: params.expanded ? !(ComputedField.MakeFunction(params.expanded) as any) : undefined, - hidden: params.hidden ? ComputedField.MakeFunction(params.hidden) as any : undefined, - }, params.subMenu.map(btnFunc)))); - } else { - const menuBtnList = DocListCast((doc.contextMenuBtns as Doc).data); - let prev = ""; - CurrentUserUtils.contextMenuTools(doc).forEach(params => { - const menuBtnDoc = menuBtnList.find(doc => doc.title === params.title); - if (!menuBtnDoc) { - const newMenuBtnDoc = !params.subMenu ? - btnFunc(params) : - CurrentUserUtils.linearButtonList({ - title: params.title, - childDontRegisterViews: true, - linearViewSubMenu: true, flexGap: 0, ignoreClick: true, - linearViewExpandable: true, icon: params.title, _height: 30, - linearViewIsExpanded: params.expanded ? !(ComputedField.MakeFunction(params.expanded) as any) : undefined, - hidden: params.hidden ? ComputedField.MakeFunction(params.hidden) as any : undefined, - }, params.subMenu.map(btnFunc)); - const after = menuBtnList.find(doc => doc.title === prev); - Doc.AddDocToList(doc.contextMenuBtns as Doc, "data", newMenuBtnDoc, after, false, !after); - } - const subMenuBtnList = menuBtnDoc?.data ? DocListCast(menuBtnDoc.data) : undefined; - if (menuBtnDoc && subMenuBtnList && params.subMenu && DocListCast(doc.data).length !== subMenuBtnList.length) { - let prevSub = ""; - params.subMenu.forEach(sub => { - if (!subMenuBtnList.find(doc => doc.title === sub.title)) { - const newSubMenuBtnDoc = btnFunc(sub); - const after = subMenuBtnList.find(doc => doc.title === prevSub); - Doc.AddDocToList(menuBtnDoc, "data", newSubMenuBtnDoc, after, false, !prevSub); - } - prevSub = params.title; - }); - } - prev = params.title; - }); + }; + const reqdFuncs:{[key:string]:any} = { + ...params.funcs, + backgroundColor: params.scripts?.onClick /// a bit hacky. if onClick is set, then we assume it returns a color value when queried with '_readOnly_'. This will be true for toggle buttons, but not generally } + return this.AssignScripts(this.AssignOpts(btnDoc, reqdOpts) ?? Docs.Create.FontIconDocument(reqdOpts), params.scripts, reqdFuncs); } - // sets up the default set of documents to be shown in the Overlay layer - static setupOverlays(doc: Doc) { - if (doc.myOverlayDocs === undefined) { - doc.myOverlayDocs = new PrefetchProxy(Docs.Create.FreeformDocument([], { title: "overlay documents", backgroundColor: "#aca3a6", system: true })); - } + /// Initializes all the default buttons for the top bar context menu + static setupContextMenuButtons(doc: Doc, field="myContextMenuBtns") { + const ctxtMenuBtnsDoc = DocCast(doc[field]); + const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => { + const menuBtnDoc = DocListCast(ctxtMenuBtnsDoc?.data).find(doc => doc.title === params.title); + if (!params.subMenu) { + return this.setupContextMenuButton(params, menuBtnDoc); + } else { + const reqdSubMenuOpts = { title: params.title, icon: params.icon, childDontRegisterViews: true, flexGap: 0, _height: 30, ignoreClick: true, + linearViewSubMenu: true, linearViewExpandable: true, }; + const reqdSubMenuFuncs:{[key:string]:any} = { ...params.funcs}; + return this.AssignScripts(this.AssignOpts(menuBtnDoc, reqdSubMenuOpts) ?? + CurrentUserUtils.linearButtonList("submenu", reqdSubMenuOpts, params.subMenu.map(sub => + this.setupContextMenuButton(sub, DocListCast(menuBtnDoc?.data).find(doc => doc.title === sub.title)) + )), undefined, reqdSubMenuFuncs); + } + }); + const reqdCtxtOpts = { title: "menu buttons", flexGap: 0, childDontRegisterViews: true, linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 }; + return this.AssignOpts(ctxtMenuBtnsDoc, reqdCtxtOpts) ?? (doc[field] = CurrentUserUtils.linearButtonList("contextMenuButtons", reqdCtxtOpts, ctxtMenuBtns)); } - // the initial presentation Doc to use - static setupDefaultPresentation(doc: Doc) { - if (doc["template-presentation"] === undefined) { - doc["template-presentation"] = new PrefetchProxy(Docs.Create.PresElementBoxDocument({ - title: "pres element template", backgroundColor: "transparent", _xMargin: 5, _fitWidth: true, _height: 46, isTemplateDoc: true, isTemplateForField: "data", system: true - })); - } + /// collection of documents rendered in the overlay layer above all tabs and other UI + static setupOverlays(doc: Doc, field = "myOverlayDocs") { + const reqdOpts = { title: "overlay documents", backgroundColor: "#aca3a6", system: true }; + return this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.FreeformDocument([], reqdOpts)); } - - // Sharing sidebar is where shared documents are contained + + /// The database of all links on all documents static async setupLinkDocs(doc: Doc, linkDatabaseId: string) { if (doc.myLinkDatabase === undefined) { let linkDocs = Docs.newAccount ? undefined : await DocServer.GetRefField(linkDatabaseId); @@ -915,6 +842,8 @@ export class CurrentUserUtils { doc.myLinkDatabase = new PrefetchProxy(linkDocs); } } + + /// Shared documents option on the left side button panel // A user's sharing document is where all documents that are shared to that user are placed. // When the user views one of these documents, it will be added to the sharing documents 'viewed' list field // The sharing document also stores the user's color value which helps distinguish shared documents from personal documents @@ -941,37 +870,26 @@ export class CurrentUserUtils { }; const sharedDocs = Docs.newAccount ? undefined : DocCast(doc.mySharedDocs) ?? DocCast(await DocServer.GetRefField(sharingDocumentId + "outer")); - if (!(sharedDocs instanceof Doc)) { - doc.mySharedDocs = new PrefetchProxy( - Docs.Create.TreeDocument([], {...sharedDocOpts, ...sharedRequiredDocOpts}, sharingDocumentId + "outer", sharingDocumentId)); - } else { - Object.entries(sharedRequiredDocOpts).forEach(pair => { - const targetDoc = pair[0].startsWith("_") ? sharedDocs as Doc : Doc.GetProto(sharedDocs as Doc); - targetDoc[pair[0]] = pair[1]; - }); - } + return this.AssignOpts(DocCast(sharedDocs), sharedRequiredDocOpts) ?? + (doc.mySharedDocs = Docs.Create.TreeDocument([], {...sharedDocOpts, ...sharedRequiredDocOpts}, sharingDocumentId + "outer", sharingDocumentId)); } - // Import sidebar is where shared documents are contained - static setupImportSidebar(doc: Doc) { - if (doc.myImportDocs === undefined) { - const newImportButton: Doc = Docs.Create.FontIconDocument({ onClick: ScriptField.MakeScript("importDocument()"), _forceActive: true, toolTip: "Import from computer", _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, title: "Import", btnType: ButtonType.ClickButton, buttonText: "Import", icon: "upload", system: true }); - doc.myImportDocs = new PrefetchProxy(Docs.Create.StackingDocument([], { - title: "My Imports", _forceActive: true, buttonMenu: true, buttonMenuDoc: newImportButton, ignoreClick: true, _showTitle: "title", _stayInCollection: true, _hideContextMenu: true, childLimitHeight: 0, - childDropAction: "copy", _autoHeight: true, _yMargin: 50, _gridGap: 15, boxShadow: "0 0", _lockedPosition: true, system: true, _chromeHidden: true, - dontRegisterView: true, explainer: "This is where documents that are Imported into Dash will go." - })); - } - } - - // Search sidebar is where searches within the document are performed - static setupSearchSidebar(doc: Doc) { - if (doc.mySearchPanel === undefined) { - doc.mySearchPanel = new PrefetchProxy(Docs.Create.SearchDocument({ - dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, _searchDoc: true, - childDropAction: "alias", _lockedPosition: true, _viewType: CollectionViewType.Schema, title: "Search Panel", system: true - })) as any as Doc; - } + /// Import option on the left side button panel + static setupImportSidebar(doc: Doc, field:string) { + const reqdOpts:DocumentOptions = { + title: "My Imports", _forceActive: true, buttonMenu: true, ignoreClick: true, _showTitle: "title", + _stayInCollection: true, _hideContextMenu: true, childLimitHeight: 0, + childDropAction: "copy", _autoHeight: true, _yMargin: 50, _gridGap: 15, boxShadow: "0 0", _lockedPosition: true, system: true, _chromeHidden: true, + dontRegisterView: true, explainer: "This is where documents that are Imported into Dash will go." + }; + const myImports = this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.StackingDocument([], reqdOpts)); + + const reqdBtnOpts:DocumentOptions = { _forceActive: true, toolTip: "Import from computer", + _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, title: "Import", btnType: ButtonType.ClickButton, + buttonText: "Import", icon: "upload", system: true }; + const reqdBtnScripts = { onClick: "importDocument()" }; + const newImportBtn = this.AssignOpts(DocCast(myImports.buttonMenuDoc), reqdBtnOpts) ?? (myImports.buttonMenuDoc = Docs.Create.FontIconDocument(reqdBtnOpts)); + this.AssignScripts(newImportBtn, reqdBtnScripts); } static setupClickEditorTemplates(doc: Doc) { @@ -1033,8 +951,8 @@ export class CurrentUserUtils { }, { fireImmediately: true }); // Document properties on load doc.system = true; - doc.noviceMode = doc.noviceMode === undefined ? "true" : doc.noviceMode; doc.title = Doc.CurrentUserEmail; + doc.noviceMode = doc.noviceMode === undefined ? "true" : doc.noviceMode; doc._raiseWhenDragged = true; doc._showLabel = true; doc._showMenuLabel = true; @@ -1053,29 +971,22 @@ export class CurrentUserUtils { doc.defaultAclPrivate = BoolCast(doc.defaultAclPrivate, false); doc.activeCollectionNestedBackground = Cast(doc.activeCollectionNestedBackground, "string", null); doc.noviceMode = BoolCast(doc.noviceMode, true); - doc.savedFilters = new List(); + !doc.savedFilters && (doc.savedFilters = new List()); doc.filterDocCount = 0; doc.freezeChildren = "remove|add"; doc.myPublishedDocs = doc.myPublishedDocs ?? new List(); - doc.myHeaderBarDoc = doc.myHeaderBarDoc ?? Docs.Create.MulticolumnDocument([], { title: "header bar", system: true }); + doc.myHeaderBar = doc.myHeaderBar?? Docs.Create.MulticolumnDocument([], { title: "header bar", system: true }); // drop down panel at top of dashboard for stashing documents + await this.setupLinkDocs(doc, linkDatabaseId); + await this.setupSharedDocs(doc, sharingDocumentId); // sets up the right sidebar collection for mobile upload documents and sharing this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon this.setupDocTemplates(doc); // sets up the template menu of templates - this.setupImportSidebar(doc); // sets up the import sidebar - this.setupSearchSidebar(doc); // sets up the search sidebar this.setupActiveMobileMenu(doc); // sets up the current mobile menu for Dash Mobile - this.setupOverlays(doc); // documents in overlay layer - this.setupContextMenuButtons(doc); // set up context menu buttons + this.setupOverlays(doc); // sets up the overlay panel where documents and other widgets can be added to float over the rest of the dashboard + this.setupContextMenuButtons(doc); // set up the row of buttons at the top of the dashboard that change depending on what is selected this.setupDockedButtons(doc); // the bottom bar of font icons - await this.setupSidebarButtons(doc); // the pop-out left sidebar of tools/panels - await this.setupMenuPanel(doc, sharingDocumentId, linkDatabaseId); + this.setupLeftSidebarMenu(doc); // the left-side column of buttons that open their contents in a flyout panel on the left if (!doc.globalScriptDatabase) doc.globalScriptDatabase = Docs.Prototypes.MainScriptDocument(); - setTimeout(() => this.setupDefaultPresentation(doc), 0); // presentation that's initially triggered - - // setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet - doc["dockedBtn-undo"] && reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(doc["dockedBtn-undo"] as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true }); - doc["dockedBtn-redo"] && reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(doc["dockedBtn-redo"] as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true }); - setTimeout(() => DocServer.UPDATE_SERVER_CACHE(), 2500); doc.fieldInfos = await Docs.setupFieldInfos(); if (doc.activeDashboard instanceof Doc) { @@ -1227,7 +1138,7 @@ export class CurrentUserUtils { public static async snapshotDashboard(userDoc: Doc) { const copy = await CollectionDockingView.Copy(CurrentUserUtils.ActiveDashboard); - Doc.AddDocToList(Cast(userDoc.myDashboards, Doc, null), "data", copy); + Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", copy); CurrentUserUtils.openDashboard(userDoc, copy); } @@ -1277,15 +1188,24 @@ export class CurrentUserUtils { return tbox; } - public static get DockedBtns() { return Cast(Doc.UserDoc().dockedBtns, Doc, null); } - public static get MySearchPanelDoc() { return Cast(Doc.UserDoc().mySearchPanelDoc, Doc, null); } - public static get ActiveDashboard() { return Cast(Doc.UserDoc().activeDashboard, Doc, null); } - public static get MyHeaderBarDoc() { return Cast(Doc.UserDoc().myHeaderBarDoc, Doc, null); } - public static get ActivePresentation() { return Cast(Doc.UserDoc().activePresentation, Doc, null); } - public static get MyRecentlyClosed() { return Cast(Doc.UserDoc().myRecentlyClosedDocs, Doc, null); } - public static get MyDashboards() { return Cast(Doc.UserDoc().myDashboards, Doc, null); } - public static get EmptyPane() { return Cast(Doc.UserDoc().emptyPane, Doc, null); } - public static get OverlayDocs() { return DocListCast((Doc.UserDoc().myOverlayDocs as Doc)?.data); } + public static get MyUserDocView() { return DocCast(Doc.UserDoc().myUserDocView); } + public static get MyDockedBtns() { return DocCast(Doc.UserDoc().myDockedBtns); } + public static get MySearcher() { return DocCast(Doc.UserDoc().mySearcher); } + public static get MyFilesystem() { return DocCast(Doc.UserDoc().myFilesystem); } + public static get MyHeaderBar() { return DocCast(Doc.UserDoc().myHeaderBar); } + public static get MyTools() { return DocCast(Doc.UserDoc().myTools); } + public static get MyDashboards() { return DocCast(Doc.UserDoc().myDashboards); } + public static get MyLeftSidebarMenu() { return DocCast(Doc.UserDoc().myLeftSidebarMenu); } + public static get MyLeftSidebarPanel() { return DocCast(Doc.UserDoc().myLeftSidebarPanel); } + public static get MySharedDocs() { return DocCast(Doc.UserDoc().mySharedDocs); } + public static get MyTrails() { return DocCast(Doc.UserDoc().myTrails); } + public static get MyImports() { return DocCast(Doc.UserDoc().myImports); } + public static get MyContextMenuBtns() { return DocCast(Doc.UserDoc().myContextMenuBtns); } + public static get MyRecentlyClosed() { return DocCast(Doc.UserDoc().myRecentlyClosed); } + public static get MyOverlayDocs() { return DocListCast(DocCast(Doc.UserDoc().myOverlayDocs)?.data); } + public static get ActiveDashboard() { return DocCast(Doc.UserDoc().activeDashboard); } + public static get ActivePresentation() { return DocCast(Doc.UserDoc().activePresentation); } + public static get EmptyPane() { return DocCast(Doc.UserDoc().emptyPane); } public static set SelectedTool(tool: InkTool) { Doc.UserDoc().activeInkTool = tool; } @computed public static get SelectedTool(): InkTool { return StrCast(Doc.UserDoc().activeInkTool, InkTool.None) as InkTool; } } @@ -1298,7 +1218,7 @@ ScriptingGlobals.add(function openDragFactory(dragFactory: Doc) { view && SelectionManager.SelectView(view, false); } }); -ScriptingGlobals.add(function MySharedDocs() { return Doc.SharingDoc(); }, "document containing all shared Docs"); +ScriptingGlobals.add(function MySharedDocs() { return CurrentUserUtils.MySharedDocs; }, "document containing all shared Docs"); ScriptingGlobals.add(function IsNoviceMode() { return Doc.UserDoc().noviceMode; }, "is Dash in novice mode"); ScriptingGlobals.add(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }, "switches between comic and normal document rendering"); ScriptingGlobals.add(function snapshotDashboard() { CurrentUserUtils.snapshotDashboard(Doc.UserDoc()); }, "creates a snapshot copy of a dashboard"); @@ -1329,15 +1249,15 @@ ScriptingGlobals.add(function selectedDocumentType(docType?: DocumentType, colTy const parentDoc: Doc = Cast(selected.context, Doc, null); selected = parentDoc; } - if (selected && docType && selected.type === docType) return false; - else if (selected && colType && selected.viewType === colType) return false; - else if (selected && !colType && !docType) return false; - else return true; + if (selected && docType && selected.type === docType) return true; + else if (selected && colType && selected.viewType === colType) return true; + else if (selected && !colType && !docType) return true; + else return false; }); ScriptingGlobals.add(function makeTopLevelFolder() { const folder = Docs.Create.TreeDocument([], { title: "Untitled folder", _stayInCollection: true, isFolder: true }); TreeView._editTitleOnLoad = { id: folder[Id], parent: undefined }; - return Doc.AddDocToList(Doc.UserDoc().myFilesystem as Doc, "data", folder); + return Doc.AddDocToList(CurrentUserUtils.MyFilesystem, "data", folder); }); ScriptingGlobals.add(function nextKeyFrame(readOnly: boolean) { if (readOnly) return; diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index a82f99d5a..0435cd535 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -10,6 +10,7 @@ import { CollectionView } from '../views/collections/CollectionView'; import { LightboxView } from '../views/LightboxView'; import { DocumentView, ViewAdjustment } from '../views/nodes/DocumentView'; import { LinkAnchorBox } from '../views/nodes/LinkAnchorBox'; +import { CurrentUserUtils } from './CurrentUserUtils'; import { ScriptingGlobals } from './ScriptingGlobals'; import { SelectionManager } from './SelectionManager'; @@ -296,7 +297,7 @@ export function DocFocusOrOpen(doc: Doc, collectionDoc?: Doc) { Doc.linkFollowHighlight(dv?.props.Document, false); } else { - const context = doc.context !== Doc.UserDoc().myFilesystem && Cast(doc.context, Doc, null); + const context = doc.context !== CurrentUserUtils.MyFilesystem && Cast(doc.context, Doc, null); const showDoc = context || doc; const bestAlias = showDoc === Doc.GetProto(showDoc) ? DocListCast(showDoc.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail) : showDoc; diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 223b0268c..3791bec73 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -223,7 +223,7 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp paramList.push(`${key}: ${typeof val === "object" ? Object.getPrototypeOf(val).constructor.name : typeof val}`); } const paramString = paramList.join(", "); - const body = addReturn ? `return ${script};` : script; + const body = addReturn && !script.startsWith("{ return") ? `return ${script};` : script; const reqTypes = requiredType ? `: ${requiredType}` : ''; const funcScript = `(function(${paramString})${reqTypes} { ${body} })`; host.writeFile("file.ts", funcScript); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 8486b3d62..be5927497 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -141,7 +141,7 @@ export function ViewBoxAnnotatableComponent

() const toRemove = value.filter(v => docs.includes(v)); if (toRemove.length !== 0) { - const recent = Cast(Doc.UserDoc().myRecentlyClosedDocs, Doc) as Doc; + const recent = CurrentUserUtils.MyRecentlyClosed; toRemove.forEach(doc => { leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey); Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc); diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 767efdbc2..16d7c9a23 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -235,7 +235,7 @@ export class KeyManager { if (SelectionManager.Views().length === 1 && SelectionManager.Views()[0].ComponentView?.search) { SelectionManager.Views()[0].ComponentView?.search?.("", false, false); } else { - const searchBtn = Doc.UserDoc().searchBtn as Doc; + const searchBtn = CurrentUserUtils.MySearcher; if (searchBtn) { MainView.Instance.selectMenu(searchBtn); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 5fd76c388..7e3916b3f 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -10,7 +10,7 @@ import * as ReactDOM from 'react-dom'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { PrefetchProxy } from '../../fields/Proxy'; import { ScriptField } from '../../fields/ScriptField'; -import { PromiseValue, StrCast } from '../../fields/Types'; +import { DocCast, PromiseValue, StrCast } from '../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; @@ -79,7 +79,7 @@ export class MainView extends React.Component { @observable private _dashUIWidth: number = 0; // width of entire main dashboard region including left menu buttons and properties panel (but not including the dashboard selector button row) @observable private _dashUIHeight: number = 0; // height of entire main dashboard region including top menu buttons @observable private _panelContent: string = "none"; - @observable private _sidebarContent: any = this.userDoc?.sidebar; + @observable private _sidebarContent: any = CurrentUserUtils.MyLeftSidebarPanel; @observable private _leftMenuFlyoutWidth: number = 0; @computed private get dashboardTabHeight() { return 27; } // 27 comes form lm.config.defaultConfig.dimensions.headerHeight in goldenlayout.js @@ -92,7 +92,7 @@ export class MainView extends React.Component { @computed private get userDoc() { return Doc.UserDoc(); } @computed private get colorScheme() { return StrCast(CurrentUserUtils.ActiveDashboard?.colorScheme); } @computed private get mainContainer() { return this.userDoc ? CurrentUserUtils.ActiveDashboard : CurrentUserUtils.GuestDashboard; } - @computed private get headerBarDoc() { return this.userDoc ? CurrentUserUtils.MyHeaderBarDoc : CurrentUserUtils.MyHeaderBarDoc; } + @computed private get headerBarDoc() { return CurrentUserUtils.MyHeaderBar; } @computed public get mainFreeform(): Opt { return (docs => (docs?.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); } headerBarDocWidth = () => this.mainDocViewWidth(); @@ -249,24 +249,8 @@ export class MainView extends React.Component { @action createNewFolder = async () => { - if (!await this.userDoc.myFilesystem) { - this.userDoc.myFileOrphans = Docs.Create.TreeDocument([], { title: "Unfiled", _stayInCollection: true, system: true, isFolder: true }); - const newFolder = ScriptField.MakeFunction(`createNewFolder()`, { scriptContext: "any" })!; - const newFolderButton: Doc = Docs.Create.FontIconDocument({ - onClick: newFolder, _forceActive: true, toolTip: "New folder", _stayInCollection: true, _hideContextMenu: true, title: "New folder", - btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "New folder", icon: "folder-plus", system: true - }); - this.userDoc.myFilesystem = new PrefetchProxy(Docs.Create.TreeDocument([this.userDoc.myFileOrphans as Doc], { - title: "My Documents", _showTitle: "title", buttonMenu: true, buttonMenuDoc: newFolderButton, _height: 100, - treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, ignoreClick: true, - isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "proto", system: true, - explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard." - })); - } const folder = Docs.Create.TreeDocument([], { title: "Untitled folder", _stayInCollection: true, isFolder: true }); - Doc.AddDocToList(this.userDoc.myFilesystem as Doc, "data", folder); + Doc.AddDocToList(CurrentUserUtils.MyFilesystem, "data", folder); } @observable _exploreMode = false; @@ -397,7 +381,7 @@ export class MainView extends React.Component { addDocTab={this.addDocTabFunc} pinToPres={emptyFunction} docViewPath={returnEmptyDoclist} - styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards || this._sidebarContent.proto === Doc.UserDoc().myFilesystem ? DashboardStyleProvider : DefaultStyleProvider} + styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards || this._sidebarContent.proto === CurrentUserUtils.MyFilesystem ? DashboardStyleProvider : DefaultStyleProvider} rootSelected={returnTrue} removeDocument={returnFalse} ScreenToLocalTransform={this.mainContainerXf} @@ -423,7 +407,7 @@ export class MainView extends React.Component { @computed get leftMenuPanel() { return

(doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.RemoveDocFromList(Doc.UserDoc().dockedBtns as Doc, "data", doc), true); + remButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.RemoveDocFromList(CurrentUserUtils.MyDockedBtns, "data", doc), true); moveButtonDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => this.remButtonDoc(doc) && addDocument(doc); - addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", doc), true); + addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.AddDocToList(CurrentUserUtils.MyDockedBtns, "data", doc), true); buttonBarXf = () => { if (!this._docBtnRef.current) return Transform.Identity(); @@ -543,9 +527,9 @@ export class MainView extends React.Component { @computed get docButtons() { return !(this.userDoc.dockedBtns instanceof Doc) ? (null) : -
+
{ + return CurrentUserUtils.MyOverlayDocs?.map(d => { let offsetx = 0, offsety = 0; const dref = React.createRef(); const onPointerMove = action((e: PointerEvent, down: number[]) => { diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 16eb95cf4..2cf334ae1 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -931,7 +931,7 @@ export class PropertiesView extends React.Component { * If it doesn't exist, it creates it. */ checkFilterDoc() { - if (!this.selectedDoc.currentFilter) CurrentUserUtils.setupFilterDocs(this.selectedDoc); + if (!this.selectedDoc.currentFilter) this.selectedDoc.currentFilter = CurrentUserUtils.createFilterDoc(); } /** @@ -944,8 +944,7 @@ export class PropertiesView extends React.Component { this.selectedDoc._docRangeFilters = new List(); (this.selectedDoc.currentFilter as Doc)._docFiltersList = currentDocFilters; (this.selectedDoc.currentFilter as Doc)._docRangeFiltersList = currentDocRangeFilters; - this.selectedDoc.currentFilter = undefined; - CurrentUserUtils.setupFilterDocs(this.selectedDoc); + this.selectedDoc.currentFilter = CurrentUserUtils.createFilterDoc(); } /** diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index d2687df17..1ebbe08ef 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -416,7 +416,7 @@ export class CollectionDockingView extends CollectionSubView() { } tabDestroyed = (tab: any) => { - Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", tab.DashDoc); + Doc.AddDocToList(CurrentUserUtils.MyHeaderBar, "data", tab.DashDoc); Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", tab.DashDoc, undefined, true, true); const dview = CollectionDockingView.Instance.props.Document; const fieldKey = CollectionDockingView.Instance.props.fieldKey; diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 39f6466d6..1c25421f5 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -99,7 +99,7 @@ export class CollectionMenu extends AntimodeMenu{ } @computed get contMenuButtons() { - const selDoc = Doc.UserDoc().contextMenuBtns; + const selDoc = CurrentUserUtils.MyContextMenuBtns; return !(selDoc instanceof Doc) ? (null) :
{ this.target._docFilters = undefined; this.target._searchFilterDocs = undefined; }), initialize: (button: Doc) => { - button['target-docFilters'] = (Cast(Doc.UserDoc().mySearchPanelDoc, Doc, null)._docFilters || Cast(Doc.UserDoc().activeDashboard, Doc, null)._docFilters) instanceof ObjectField ? - ObjectField.MakeCopy((Cast(Doc.UserDoc().mySearchPanelDoc, Doc, null)._docFilters || Cast(Doc.UserDoc().activeDashboard, Doc, null)._docFilters) as any as ObjectField) : undefined; + button['target-docFilters'] = (CurrentUserUtils.MySearcher._docFilters || CurrentUserUtils.ActiveDashboard._docFilters) instanceof ObjectField ? + ObjectField.MakeCopy((CurrentUserUtils.MySearcher._docFilters || CurrentUserUtils.ActiveDashboard._docFilters) as any as ObjectField) : undefined; button['target-searchFilterDocs'] = CurrentUserUtils.ActiveDashboard._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(CurrentUserUtils.ActiveDashboard._searchFilterDocs as any as ObjectField) : undefined; }, }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 52e99f26b..c07e44fcc 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -985,7 +985,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || CurrentUserUtils.OverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; + if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || CurrentUserUtils.MyOverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming e.stopPropagation(); } @@ -1031,7 +1031,7 @@ export class CollectionFreeFormView extends CollectionSubView {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))}
- {!DocumentLinksButton.StartLink || this.layoutDoc !== CurrentUserUtils.DockedBtns ? null : + {!DocumentLinksButton.StartLink || this.layoutDoc !== CurrentUserUtils.MyDockedBtns ? null : e.stopPropagation()} > @@ -226,7 +226,7 @@ export class CollectionLinearView extends CollectionSubView() { } - {!CollectionStackedTimeline.CurrentlyPlaying || !CollectionStackedTimeline.CurrentlyPlaying.length || this.layoutDoc !== CurrentUserUtils.DockedBtns ? (null) : + {!CollectionStackedTimeline.CurrentlyPlaying || !CollectionStackedTimeline.CurrentlyPlaying.length || this.layoutDoc !== CurrentUserUtils.MyDockedBtns ? (null) : Currently playing: diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx index 4b33ef8ae..a6f6bd35f 100644 --- a/src/client/views/linking/LinkPopup.tsx +++ b/src/client/views/linking/LinkPopup.tsx @@ -68,8 +68,8 @@ export class LinkPopup extends React.Component { className="linkPopup-searchBox searchBox-input" /> */} 3 || Math.abs(this._downY - touch.clientY) > 3)) { if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler)) { @@ -563,7 +563,7 @@ export class DocumentViewInternal extends DocComponent 3 || Math.abs(this._downY - e.clientY) > 3) { if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) { document.removeEventListener("pointermove", this.onPointerMove); diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx index e3708d7b9..5add09653 100644 --- a/src/client/views/nodes/FilterBox.tsx +++ b/src/client/views/nodes/FilterBox.tsx @@ -35,7 +35,7 @@ export class FilterBox extends ViewBoxBaseComponent() { constructor(props: Readonly) { super(props); const targetDoc = FilterBox.targetDoc; - if (targetDoc && !targetDoc.currentFilter) CurrentUserUtils.setupFilterDocs(targetDoc); + if (targetDoc && !targetDoc.currentFilter) targetDoc.currentFilter = CurrentUserUtils.createFilterDoc(); } public static LayoutString(fieldKey: string) { return FieldView.LayoutString(FilterBox, fieldKey); } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 10974ca03..967158cbf 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -156,20 +156,22 @@ export class WebBox extends ViewBoxAnnotatableComponent { this._annotationKeySuffix = () => this._urlHash + "-annotations"; + const reqdFuncs:{[key:string]: string} = {}; // bcz: need to make sure that doc.data-annotations points to the currently active web page's annotations (this could/should be when the doc is created) - this.dataDoc[this.fieldKey + "-annotations"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-annotations"`); - this.dataDoc[this.fieldKey + "-sidebar"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-sidebar"`); + reqdFuncs[this.fieldKey + "-annotations"] = `copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-annotations"`; + reqdFuncs[this.fieldKey + "-sidebar"] = `copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-sidebar"`; + CurrentUserUtils.AssignScripts(this.dataDoc, {}, reqdFuncs); }); - reaction(() => this.props.isSelected() || this.isAnyChildContentActive() || Doc.isBrushedHighlightedDegree(this.props.Document), + reaction(() => this.props.isSelected(true) || this.isAnyChildContentActive() || Doc.isBrushedHighlightedDegree(this.props.Document), async (selected) => { if (selected) { this._webPageHasBeenRendered = true; - } else if ((!this.props.isContentActive() || SnappingManager.GetIsDragging()) && // update thumnail when unselected AND (no child annotation is active OR we've started dragging the document in which case no additional deselect will occur so this is the only chance to update the thumbnail) + } else if ((!this.props.isContentActive(true) || SnappingManager.GetIsDragging()) && // update thumnail when unselected AND (no child annotation is active OR we've started dragging the document in which case no additional deselect will occur so this is the only chance to update the thumbnail) !this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && // don't create a thumbnail when double-clicking to enter lightbox because thumbnail will be empty LightboxView.LightboxDoc !== this.rootDoc) { // don't create a thumbnail if entering Lightbox from maximize either, since thumb will be empty. this.updateThumb(); } - }, { fireImmediately: this.props.isSelected() || this.isAnyChildContentActive() || (Doc.isBrushedHighlightedDegree(this.props.Document) ? true : false) }); + }, { fireImmediately: this.props.isSelected(true) || this.isAnyChildContentActive() || (Doc.isBrushedHighlightedDegreeUnmemoized(this.props.Document) ? true : false) }); this._disposers.autoHeight = reaction(() => this.layoutDoc._autoHeight, autoHeight => { diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index 97e6eddfe..f29dfe489 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -521,7 +521,7 @@ export class FontIconBox extends DocComponent() {
{this.icon === "pres-trail" ? trailsIcon : } {menuLabel} - +
); break; diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 1dd6fef9b..52b03b0a5 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -623,7 +623,7 @@ export class PresBox extends ViewBoxBaseComponent() { */ @action updateMinimize = async () => { - if (CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { + if (CurrentUserUtils.MyOverlayDocs.includes(this.layoutDoc)) { this.layoutDoc.presStatus = PresStatus.Edit; Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc); CollectionDockingView.AddSplit(this.rootDoc, "right"); @@ -868,7 +868,7 @@ export class PresBox extends ViewBoxBaseComponent() { } break; case "Escape": - if (CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { this.updateMinimize(); } + if (CurrentUserUtils.MyOverlayDocs.includes(this.layoutDoc)) { this.updateMinimize(); } else if (this.layoutDoc.presStatus === "edit") { this._selectedArray.clear(); this._eleArray.length = this._dragArray.length = 0; } else this.layoutDoc.presStatus = "edit"; if (this._presTimer) clearTimeout(this._presTimer); @@ -2511,7 +2511,7 @@ export class PresBox extends ViewBoxBaseComponent() { const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === Doc.UserDoc().activePresentation); const presEnd: boolean = !this.layoutDoc.presLoop && (this.itemIndex === this.childDocs.length - 1); const presStart: boolean = !this.layoutDoc.presLoop && (this.itemIndex === 0); - return CurrentUserUtils.OverlayDocs.includes(this.rootDoc) ? + return CurrentUserUtils.MyOverlayDocs.includes(this.rootDoc) ?
e.stopPropagation()}>
{"Loop"}
}>
() {
: -
+
{this.topPanel} {this.toolbar} {this.newDocumentToolbarDropdown} diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 7b72787d1..94be286f5 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -941,6 +941,9 @@ export namespace Doc { export function isBrushedHighlightedDegree(doc: Doc) { return Doc.IsHighlighted(doc) ? DocBrushStatus.highlighted : Doc.IsBrushedDegree(doc); } + export function isBrushedHighlightedDegreeUnmemoized(doc: Doc) { + return Doc.IsHighlighted(doc) ? DocBrushStatus.highlighted : Doc.IsBrushedDegreeUnmemoized(doc); + } export class DocBrush { BrushedDoc: ObservableMap = new ObservableMap(); @@ -980,7 +983,7 @@ export namespace Doc { export function SearchQuery(): string { return manager._searchQuery; } export function SetSearchQuery(query: string) { runInAction(() => manager._searchQuery = query); } export function UserDoc(): Doc { return manager._user_doc; } - export function SharingDoc(): Doc { return Cast(Doc.UserDoc().mySharedDocs, Doc, null); } + export function SharingDoc(): Doc { return CurrentUserUtils.MySharedDocs; } export function LinkDBDoc(): Doc { return Cast(Doc.UserDoc().myLinkDatabase, Doc, null); } export function SetUserDoc(doc: Doc) { return (manager._user_doc = doc); } diff --git a/src/fields/util.ts b/src/fields/util.ts index d1e565774..37b9be31b 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -88,6 +88,9 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number delete target.__fields[prop]; } else { target.__fieldKeys && (target.__fieldKeys[prop] = true); + // if (target.__fields[prop] !== value) { + // console.log("ASSIGN " + prop + " " + value); + // } target.__fields[prop] = value; } //if (typeof value === "object" && !(value instanceof ObjectField)) debugger; diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 78ec706d7..c5c6fb688 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -68,7 +68,7 @@ export class MobileInterface extends React.Component { constructor(props: Readonly<{}>) { super(props); - this._library = CurrentUserUtils.setupLibrary(Doc.UserDoc()); // to access documents in Dash Web + this._library = CurrentUserUtils.setupDashboards(Doc.UserDoc()); // to access documents in Dash Web MobileInterface.Instance = this; } -- cgit v1.2.3-70-g09d2 From b292a055401af6236e0537cfad603016d77a535a Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 20 Jun 2022 13:40:07 -0400 Subject: a bunch of changes to make some userDoc() field accesses more typesafe by going through CurrentUserUtils. Some normalization of naming/functionality in CurrentUserUtils --- src/client/apis/youtube/YoutubeBox.tsx | 2 +- src/client/documents/Documents.ts | 6 +- src/client/util/CurrentUserUtils.ts | 118 +++++++++++---------- src/client/util/SettingsManager.tsx | 16 +-- src/client/util/SharingManager.tsx | 4 +- src/client/views/DashboardView.tsx | 4 +- src/client/views/DocComponent.tsx | 6 +- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/GestureOverlay.tsx | 12 +-- src/client/views/GlobalKeyHandler.ts | 8 +- src/client/views/InkStrokeProperties.ts | 4 +- src/client/views/InkTranscription.tsx | 2 +- src/client/views/InkingStroke.tsx | 2 +- src/client/views/MainView.tsx | 4 +- src/client/views/OverlayView.tsx | 8 +- src/client/views/PropertiesButtons.tsx | 4 +- src/client/views/PropertiesView.tsx | 86 ++++++++------- src/client/views/TemplateMenu.tsx | 11 +- .../views/collections/CollectionDockingView.tsx | 22 ++-- src/client/views/collections/CollectionMenu.tsx | 35 +++--- .../views/collections/CollectionStackingView.tsx | 2 +- .../CollectionStackingViewFieldColumn.tsx | 4 +- .../views/collections/CollectionTreeView.tsx | 8 +- src/client/views/collections/CollectionView.tsx | 14 +-- src/client/views/collections/TabDocView.tsx | 2 +- src/client/views/collections/TreeView.tsx | 6 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 30 +++--- .../collections/collectionFreeForm/MarqueeView.tsx | 6 +- .../collectionSchema/CollectionSchemaHeaders.tsx | 2 +- src/client/views/nodes/AudioBox.tsx | 5 +- src/client/views/nodes/ColorBox.tsx | 3 +- src/client/views/nodes/DocumentView.tsx | 40 +++---- src/client/views/nodes/FilterBox.tsx | 47 ++++---- src/client/views/nodes/ImageBox.tsx | 4 +- src/client/views/nodes/LabelBox.tsx | 2 +- src/client/views/nodes/MapBox/MapBox.tsx | 4 +- src/client/views/nodes/VideoBox.tsx | 6 +- src/client/views/nodes/WebBox.tsx | 6 +- src/client/views/nodes/button/FontIconBox.tsx | 35 +++--- .../views/nodes/formattedText/FormattedTextBox.tsx | 12 +-- .../views/nodes/formattedText/RichTextMenu.tsx | 1 - src/client/views/nodes/trails/PresBox.tsx | 30 +++--- src/client/views/nodes/trails/PresElementBox.tsx | 16 +-- src/client/views/pdf/PDFViewer.tsx | 2 +- src/client/views/topbar/TopBar.tsx | 10 +- src/client/views/webcam/DashWebRTCVideo.tsx | 2 +- src/fields/Doc.ts | 18 ++-- src/fields/util.ts | 2 +- src/mobile/MobileInterface.tsx | 20 ++-- 49 files changed, 360 insertions(+), 335 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx index c5ff2db68..e14dc60b4 100644 --- a/src/client/apis/youtube/YoutubeBox.tsx +++ b/src/client/apis/youtube/YoutubeBox.tsx @@ -351,7 +351,7 @@ export class YoutubeBox extends React.Component { const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting; - const classname = "webBox-cont" + (this.props.isSelected() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? "-interactive" : ""); + const classname = "webBox-cont" + (this.props.isSelected() && CurrentUserUtils.ActiveTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? "-interactive" : ""); return ( <>
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 927996af2..f96bffb3c 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -687,7 +687,7 @@ export namespace Docs { ![DocumentType.LINK, DocumentType.MARKER, DocumentType.LABEL].includes(viewDoc.type as any) && DocUtils.MakeLinkToActiveAudio(() => viewDoc); !Doc.IsSystem(dataDoc) && ![DocumentType.MARKER, DocumentType.KVP, DocumentType.LINK, DocumentType.LINKANCHOR].includes(proto.type as any) && - !dataDoc.isFolder && !dataProps.annotationOn && Doc.AddDocToList(Cast(Doc.UserDoc().myFileOrphans, Doc, null), "data", dataDoc); + !dataDoc.isFolder && !dataProps.annotationOn && Doc.AddDocToList(CurrentUserUtils.MyFileOrphans, undefined, dataDoc); updateCachedAcls(dataDoc); updateCachedAcls(viewDoc); @@ -802,7 +802,7 @@ export namespace Docs { I.rotation = 0; I.data = new InkField(points); I.creationDate = new DateField; - I["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; + I["acl-Public"] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; I["acl-Override"] = "None"; I.links = ComputedField.MakeFunction("links(self)"); I[Initializing] = false; @@ -1204,7 +1204,7 @@ export namespace DocUtils { created = Docs.Create.RecordingDocument((field).url.href, resolved); layout = RecordingBox.LayoutString; } else if (field instanceof InkField) { - created = Docs.Create.InkDocument(ActiveInkColor(), CurrentUserUtils.SelectedTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), (field).inkData, resolved); + created = Docs.Create.InkDocument(ActiveInkColor(), CurrentUserUtils.ActiveTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), (field).inkData, resolved); layout = InkingStroke.LayoutString; } else if (field instanceof List && field[0] instanceof Doc) { created = Docs.Create.StackingDocument(DocListCast(field), resolved); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index afb1442bf..7a38886fe 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -74,16 +74,16 @@ export class CurrentUserUtils { @observable public static headerBarHeight: number = 0; @observable public static searchPanelWidth: number = 0; - static AssignScripts(doc:Doc, scripts?:{ [key: string]: string;}, functions?:{[key:string]: string}) { + static AssignScripts(doc:Doc, scripts?:{ [key: string]: string;}, funcs?:{[key:string]: string}) { scripts && Object.keys(scripts).map(key => { if (ScriptCast(doc[key])?.script.originalScript !== scripts[key] && scripts[key]) { doc[key] = ScriptField.MakeScript(scripts[key], { dragData: DragManager.DocumentDragData.name, value:"any", scriptContext: "any" }, {"_readOnly_": true}); } }); - functions && Object.keys(functions).map(key => { + funcs && Object.keys(funcs).map(key => { const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); - if (ScriptCast(cfield)?.script.originalScript !== functions[key] && functions[key]) { - doc[key] = ComputedField.MakeFunction(functions[key], { dragData: DragManager.DocumentDragData.name }, {"_readOnly_": true}); + if (ScriptCast(cfield)?.script.originalScript !== funcs[key] && funcs[key]) { + doc[key] = ComputedField.MakeFunction(funcs[key], { dragData: DragManager.DocumentDragData.name }, {"_readOnly_": true}); } }); return doc; @@ -180,14 +180,14 @@ export class CurrentUserUtils { } /// Initializes collection of templates for notes and click functions - static setupDocTemplates(doc: Doc) { + static setupDocTemplates(doc: Doc, field="myTemplates") { const templates = [ CurrentUserUtils.setupNoteTemplates(doc), CurrentUserUtils.setupClickEditorTemplates(doc) ]; const reqdOpts = { title: "template layouts", _xMargin: 0, system: true, }; const reqdScripts = { dropConverter: "convertToButtons(dragData)" }; - return this.AssignScripts(this.AssignOpts(DocCast(doc.templateDocs), reqdOpts, templates) ?? (doc.templateDocs = Docs.Create.TreeDocument(templates, reqdOpts)), reqdScripts); + return this.AssignScripts(this.AssignOpts(DocCast(doc[field]), reqdOpts, templates) ?? (doc[field] = Docs.Create.TreeDocument(templates, reqdOpts)), reqdScripts); } // setup templates for different document types when they are iconified from Document Decorations @@ -329,7 +329,7 @@ export class CurrentUserUtils { static setupCreatorButtons(doc: Doc, dragCreatorDoc?:Doc):Doc { const creatorBtns = CurrentUserUtils.creatorBtnDescriptors(doc).map((reqdOpts) => { const btn = dragCreatorDoc ? DocListCast(dragCreatorDoc.data).find(doc => doc.title === reqdOpts.title): undefined; - const opts:DocumentOptions = {...OmitKeys(reqdOpts, ["backgroundColor"]).omit, + const opts:DocumentOptions = {...OmitKeys(reqdOpts, ["funcs", "scripts", "backgroundColor"]).omit, _nativeWidth: 50, _nativeHeight: 50, _width: 35, _height: 35, _hideContextMenu: true, _stayInCollection: true, _dropAction: "alias", btnType: ButtonType.ToolButton, backgroundColor: reqdOpts.backgroundColor ?? Colors.DARK_GRAY, color: Colors.WHITE, system: true, _removeDropProperties: new List(["_stayInCollection"]), @@ -562,6 +562,7 @@ export class CurrentUserUtils { if (Cast(myDashboards.childContextMenuFilters, listSpec(ScriptField), null)?.length !== childContextMenuFilters.length) { myDashboards.childContextMenuFilters = new List(childContextMenuFilters.map(script => !script ? script: ScriptField.MakeFunction(script)!)); } + return myDashboards; } /// initializes the left sidebar Trails pane @@ -728,13 +729,13 @@ export class CurrentUserUtils { static inkTools():Button[] { return [ - { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", scripts:{onClick:'{ return setActiveInkTool("pen", _readOnly_);}' }}, - { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", scripts:{onClick:'{ return setActiveInkTool("write", _readOnly_);}'} }, - { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", scripts:{onClick:'{ return setActiveInkTool("eraser", _readOnly_);}' }}, - // { title: "Highlighter", toolTip: "Highlighter (Ctrl+H)", btnType: ButtonType.ToggleButton, icon: "highlighter", scripts:{onClick: 'setActiveInkTool("highlighter")'} }, - { title: "Circle", toolTip: "Circle (Ctrl+Shift+C)", btnType: ButtonType.ToggleButton, icon: "circle", scripts:{onClick:'{ return setActiveInkTool("circle", _readOnly_);}'} }, - // { title: "Square", toolTip: "Square (Ctrl+Shift+S)", btnType: ButtonType.ToggleButton, icon: "square", click: 'setActiveInkTool("square")' }, - { title: "Line", toolTip: "Line (Ctrl+Shift+L)", btnType: ButtonType.ToggleButton, icon: "minus", scripts:{onClick: '{ return setActiveInkTool("line", _readOnly_);}' }}, + { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", scripts:{onClick:'{ return setActiveTool("pen", _readOnly_);}' }}, + { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", scripts:{onClick:'{ return setActiveTool("write", _readOnly_);}'} }, + { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", scripts:{onClick:'{ return setActiveTool("eraser", _readOnly_);}' }}, + // { title: "Highlighter", toolTip: "Highlighter (Ctrl+H)", btnType: ButtonType.ToggleButton, icon: "highlighter", scripts:{onClick: 'setActiveTool("highlighter")'} }, + { title: "Circle", toolTip: "Circle (Ctrl+Shift+C)", btnType: ButtonType.ToggleButton, icon: "circle", scripts:{onClick:'{ return setActiveTool("circle", _readOnly_);}'} }, + // { title: "Square", toolTip: "Square (Ctrl+Shift+S)", btnType: ButtonType.ToggleButton, icon: "square", click: 'setActiveTool("square")' }, + { title: "Line", toolTip: "Line (Ctrl+Shift+L)", btnType: ButtonType.ToggleButton, icon: "minus", scripts:{onClick: '{ return setActiveTool("line", _readOnly_);}' }}, { title: "Fill", toolTip: "Fill color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", scripts: {script: "{ return setFillColor(value, _readOnly_);}"} }, { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberButton, numBtnType: NumButtonType.Slider, numBtnMin: 1, ignoreClick: true, scripts: {script: '{ return setStrokeWidth(value, _readOnly_);}'} }, { title: "Color", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", ignoreClick: true, scripts: {script: '{ return setStrokeColor(value, _readOnly_);}'} }, @@ -941,41 +942,39 @@ export class CurrentUserUtils { } static async updateUserDocument(doc: Doc, sharingDocumentId: string, linkDatabaseId: string) { - if (!doc.globalGroupDatabase) doc.globalGroupDatabase = Docs.Prototypes.MainGroupDocument(); - await DocListCastAsync((doc.globalGroupDatabase as Doc).data); - reaction(() => DateCast((doc.globalGroupDatabase as Doc)["data-lastModified"]), + doc.globalGroupDatabase ?? (doc.globalGroupDatabase = Docs.Prototypes.MainGroupDocument()); + await DocListCastAsync(DocCast(doc.globalGroupDatabase).data); + reaction(() => DateCast(DocCast(doc.globalGroupDatabase)["data-lastModified"]), async () => { - const groups = await DocListCastAsync((doc.globalGroupDatabase as Doc).data); + const groups = await DocListCastAsync(DocCast(doc.globalGroupDatabase).data); const mygroups = groups?.filter(group => JSON.parse(StrCast(group.members)).includes(Doc.CurrentUserEmail)) || []; SnappingManager.SetCachedGroups(["Public", ...mygroups?.map(g => StrCast(g.title))]); }, { fireImmediately: true }); // Document properties on load - doc.system = true; - doc.title = Doc.CurrentUserEmail; - doc.noviceMode = doc.noviceMode === undefined ? "true" : doc.noviceMode; - doc._raiseWhenDragged = true; - doc._showLabel = true; - doc._showMenuLabel = true; - doc.textAlign = StrCast(doc.textAlign, "left"); - doc.activeInkColor = StrCast(doc.activeInkColor, "rgb(0, 0, 0)"); - doc.activeInkWidth = Number(StrCast(doc.activeInkWidth, "1")); - doc.activeInkBezier = StrCast(doc.activeInkBezier, "0"); - doc.activeFillColor = StrCast(doc.activeFillColor, ""); - doc.activeArrowStart = StrCast(doc.activeArrowStart, ""); - doc.activeArrowEnd = StrCast(doc.activeArrowEnd, ""); - doc.activeDash = StrCast(doc.activeDash, "0"); - doc.fontSize = StrCast(doc.fontSize, "12px"); - doc.fontFamily = StrCast(doc.fontFamily, "Arial"); - doc.fontColor = StrCast(doc.fontColor, "black"); - doc.fontHighlight = StrCast(doc.fontHighlight, ""); - doc.defaultAclPrivate = BoolCast(doc.defaultAclPrivate, false); - doc.activeCollectionNestedBackground = Cast(doc.activeCollectionNestedBackground, "string", null); - doc.noviceMode = BoolCast(doc.noviceMode, true); - !doc.savedFilters && (doc.savedFilters = new List()); + doc.system ?? (doc.system = true); + doc.title ?? (doc.title = Doc.CurrentUserEmail); + Doc.noviceMode ?? (Doc.noviceMode = true); + doc._raiseWhenDragged ?? (doc._raiseWhenDragged = true); + doc._showLabel ?? (doc._showLabel = true); + doc._showMenuLabel ?? (doc._showMenuLabel = true); + doc.textAlign ?? (doc.textAlign = "left"); + doc.activeInkColor ?? (doc.activeInkColor = "rgb(0, 0, 0)");; + doc.activeInkWidth ?? (doc.activeInkWidth = 1); + doc.activeInkBezier ?? (doc.activeInkBezier = "0"); + doc.activeFillColor ?? (doc.activeFillColor = ""); + doc.activeArrowStart ?? (doc.activeArrowStart = ""); + doc.activeArrowEnd ?? (doc.activeArrowEnd = ""); + doc.activeDash ?? (doc.activeDash == "0"); + doc.fontSize ?? (doc.fontSize = "12px"); + doc.fontFamily ?? (doc.fontFamily = "Arial"); + doc.fontColor ?? (doc.fontColor = "black"); + doc.fontHighlight ?? (doc.fontHighlight = ""); + doc.defaultAclPrivate ?? (doc.defaultAclPrivate = false); + doc.savedFilters ?? (doc.savedFilters = new List()); doc.filterDocCount = 0; doc.freezeChildren = "remove|add"; - doc.myPublishedDocs = doc.myPublishedDocs ?? new List(); - doc.myHeaderBar = doc.myHeaderBar?? Docs.Create.MulticolumnDocument([], { title: "header bar", system: true }); // drop down panel at top of dashboard for stashing documents + doc.myPublishedDocs ?? (doc.myPublishedDocs = new List()); + doc.myHeaderBar ?? (doc.myHeaderBar = Docs.Create.MulticolumnDocument([], { title: "header bar", system: true })); // drop down panel at top of dashboard for stashing documents await this.setupLinkDocs(doc, linkDatabaseId); await this.setupSharedDocs(doc, sharingDocumentId); // sets up the right sidebar collection for mobile upload documents and sharing this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon @@ -985,7 +984,7 @@ export class CurrentUserUtils { this.setupContextMenuButtons(doc); // set up the row of buttons at the top of the dashboard that change depending on what is selected this.setupDockedButtons(doc); // the bottom bar of font icons this.setupLeftSidebarMenu(doc); // the left-side column of buttons that open their contents in a flyout panel on the left - if (!doc.globalScriptDatabase) doc.globalScriptDatabase = Docs.Prototypes.MainScriptDocument(); + doc.globalScriptDatabase ?? ( doc.globalScriptDatabase = Docs.Prototypes.MainScriptDocument()); setTimeout(() => DocServer.UPDATE_SERVER_CACHE(), 2500); doc.fieldInfos = await Docs.setupFieldInfos(); @@ -1022,7 +1021,7 @@ export class CurrentUserUtils { const userDoc = Docs.newAccount ? new Doc(userDocumentId, true) : field as Doc; Docs.newAccount &&(userDoc.activePage = "home"); const updated = this.updateUserDocument(Doc.SetUserDoc(userDoc), sharingDocumentId, linkDatabaseId); - (await DocListCastAsync(Cast(Doc.UserDoc().myLinkDatabase, Doc, null)?.data))?.forEach(async link => { // make sure anchors are loaded to avoid incremental updates to computedFn's in LinkManager + (await DocListCastAsync(Doc.LinkDBDoc()?.data))?.forEach(async link => { // make sure anchors are loaded to avoid incremental updates to computedFn's in LinkManager const a1 = await Cast(link?.anchor1, Doc, null); const a2 = await Cast(link?.anchor2, Doc, null); }); @@ -1097,7 +1096,7 @@ export class CurrentUserUtils { } } } else if (input.files && input.files.length !== 0) { - const importDocs = Cast(Doc.UserDoc().myImportDocs, Doc, null); + const importDocs = CurrentUserUtils.MyImports; const disposer = OverlayView.ShowSpinner(); DocListCastAsync(importDocs.data).then(async list => { const results = await DocUtils.uploadFilesToDocs(Array.from(input.files || []), {}); @@ -1115,9 +1114,10 @@ export class CurrentUserUtils { } public static CaptureDashboardThumbnail() { + const activeDashboard = CurrentUserUtils.ActiveDashboard; const docView = CollectionDockingView.Instance.props.DocumentView?.(); const content = docView?.ContentDiv; - if (docView && content) { + if (docView && content && activeDashboard) { const _width = Number(getComputedStyle(content).width.replace("px","")); const _height = Number(getComputedStyle(content).height.replace("px","")); return CollectionFreeFormView.UpdateIcon( @@ -1130,20 +1130,22 @@ export class CurrentUserUtils { const proto = Cast(img.proto, Doc, null)!; proto["data-nativeWidth"] = _width; proto["data-nativeHeight"] = _height; - Doc.GetProto(CurrentUserUtils.ActiveDashboard).thumb = img; + Doc.GetProto(activeDashboard).thumb = img; }); } } public static async snapshotDashboard(userDoc: Doc) { - const copy = await CollectionDockingView.Copy(CurrentUserUtils.ActiveDashboard); - Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", copy); - CurrentUserUtils.openDashboard(userDoc, copy); + if (CurrentUserUtils.ActiveDashboard) { + const copy = await CollectionDockingView.Copy(CurrentUserUtils.ActiveDashboard); + Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", copy); + CurrentUserUtils.openDashboard(userDoc, copy); + } } public static closeActiveDashboard = () => { - Doc.UserDoc().activeDashboard = undefined; + CurrentUserUtils.ActiveDashboard = undefined; } public static createNewDashboard = async (userDoc: Doc, id?: string) => { @@ -1195,6 +1197,8 @@ export class CurrentUserUtils { public static get MyHeaderBar() { return DocCast(Doc.UserDoc().myHeaderBar); } public static get MyTools() { return DocCast(Doc.UserDoc().myTools); } public static get MyDashboards() { return DocCast(Doc.UserDoc().myDashboards); } + public static get MyFileOrphans() { return DocCast(Doc.UserDoc().myFileOrphans); } + public static get MyTemplates() { return DocCast(Doc.UserDoc().myTemplates); } public static get MyLeftSidebarMenu() { return DocCast(Doc.UserDoc().myLeftSidebarMenu); } public static get MyLeftSidebarPanel() { return DocCast(Doc.UserDoc().myLeftSidebarPanel); } public static get MySharedDocs() { return DocCast(Doc.UserDoc().mySharedDocs); } @@ -1202,12 +1206,16 @@ export class CurrentUserUtils { public static get MyImports() { return DocCast(Doc.UserDoc().myImports); } public static get MyContextMenuBtns() { return DocCast(Doc.UserDoc().myContextMenuBtns); } public static get MyRecentlyClosed() { return DocCast(Doc.UserDoc().myRecentlyClosed); } - public static get MyOverlayDocs() { return DocListCast(DocCast(Doc.UserDoc().myOverlayDocs)?.data); } + public static get MyOverlayDocs() { return DocCast(Doc.UserDoc().myOverlayDocs); } public static get ActiveDashboard() { return DocCast(Doc.UserDoc().activeDashboard); } + public static set ActiveDashboard(val:Doc|undefined) { Doc.UserDoc().activeDashboard = val; } public static get ActivePresentation() { return DocCast(Doc.UserDoc().activePresentation); } + public static set ActivePresentation(val) { Doc.UserDoc().activePresentation = val; } + public static get ActivePage() { return StrCast(Doc.UserDoc().activePage); } + public static set ActivePage(val) { Doc.UserDoc().activePage = val; } public static get EmptyPane() { return DocCast(Doc.UserDoc().emptyPane); } - public static set SelectedTool(tool: InkTool) { Doc.UserDoc().activeInkTool = tool; } - @computed public static get SelectedTool(): InkTool { return StrCast(Doc.UserDoc().activeInkTool, InkTool.None) as InkTool; } + public static set ActiveTool(tool: InkTool) { Doc.UserDoc().activeTool = tool; } + public static get ActiveTool(): InkTool { return StrCast(Doc.UserDoc().activeTool, InkTool.None) as InkTool; } } ScriptingGlobals.add(function openDragFactory(dragFactory: Doc) { @@ -1219,7 +1227,7 @@ ScriptingGlobals.add(function openDragFactory(dragFactory: Doc) { } }); ScriptingGlobals.add(function MySharedDocs() { return CurrentUserUtils.MySharedDocs; }, "document containing all shared Docs"); -ScriptingGlobals.add(function IsNoviceMode() { return Doc.UserDoc().noviceMode; }, "is Dash in novice mode"); +ScriptingGlobals.add(function IsNoviceMode() { return Doc.noviceMode; }, "is Dash in novice mode"); ScriptingGlobals.add(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }, "switches between comic and normal document rendering"); ScriptingGlobals.add(function snapshotDashboard() { CurrentUserUtils.snapshotDashboard(Doc.UserDoc()); }, "creates a snapshot copy of a dashboard"); ScriptingGlobals.add(function createNewDashboard() { return CurrentUserUtils.createNewDashboard(Doc.UserDoc()); }, "creates a new dashboard when called"); diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index 6a26dfdc7..382274462 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -38,7 +38,7 @@ export class SettingsManager extends React.Component<{}> { @observable activeTab = "Accounts"; @computed get backgroundColor() { return Doc.UserDoc().activeCollectionBackground; } - @computed get colorScheme() { return CurrentUserUtils.ActiveDashboard.colorScheme; } + @computed get colorScheme() { return CurrentUserUtils.ActiveDashboard?.colorScheme; } constructor(props: {}) { super(props); @@ -59,7 +59,7 @@ export class SettingsManager extends React.Component<{}> { } } - @undoBatch selectUserMode = action((e: React.ChangeEvent) => Doc.UserDoc().noviceMode = (e.currentTarget as any)?.value === "Novice"); + @undoBatch selectUserMode = action((e: React.ChangeEvent) => Doc.noviceMode = (e.currentTarget as any)?.value === "Novice"); @undoBatch changeShowTitle = action((e: React.ChangeEvent) => Doc.UserDoc().showTitle = (e.currentTarget as any).value ? "title" : undefined); @undoBatch changeFontFamily = action((e: React.ChangeEvent) => Doc.UserDoc().fontFamily = (e.currentTarget as any).value); @undoBatch changeFontSize = action((e: React.ChangeEvent) => Doc.UserDoc().fontSize = (e.currentTarget as any).value); @@ -78,19 +78,21 @@ export class SettingsManager extends React.Component<{}> { @undoBatch @action changeColorScheme = action((e: React.ChangeEvent) => { + const activeDashboard= CurrentUserUtils.ActiveDashboard; + if (!activeDashboard) return; const scheme: ColorScheme = (e.currentTarget as any).value; switch (scheme) { case ColorScheme.Light: - CurrentUserUtils.ActiveDashboard.colorScheme = undefined; // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss) + activeDashboard.colorScheme = undefined; // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss) addStyleSheetRule(SettingsManager._settingsStyle, "lm_header", { background: "#d3d3d3 !important" }); break; case ColorScheme.Dark: - CurrentUserUtils.ActiveDashboard.colorScheme = ColorScheme.Dark; + activeDashboard.colorScheme = ColorScheme.Dark; addStyleSheetRule(SettingsManager._settingsStyle, "lm_header", { background: "black !important" }); break; case ColorScheme.System: default: window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { - CurrentUserUtils.ActiveDashboard.colorScheme = e.matches ? ColorScheme.Dark : undefined; // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss) + activeDashboard.colorScheme = e.matches ? ColorScheme.Dark : undefined; // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss) }); break; } @@ -254,7 +256,7 @@ export class SettingsManager extends React.Component<{}> {
Modes
- @@ -270,7 +272,7 @@ export class SettingsManager extends React.Component<{}> {
Doc.UserDoc().defaultAclPrivate = !Doc.UserDoc().defaultAclPrivate)} /> + onChange={action(() => Doc.defaultAclPrivate = !Doc.defaultAclPrivate)} />
Default access private
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index f439d4488..d77633b8d 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -369,7 +369,7 @@ export class SharingManager extends React.Component<{}> { const dropdownValues: string[] = Object.values(SharingPermissions); if (!uniform) dropdownValues.unshift("-multiple-"); if (override) dropdownValues.unshift("None"); - return dropdownValues.filter(permission => !Doc.UserDoc().noviceMode || ![SharingPermissions.View, SharingPermissions.SelfEdit].includes(permission as any)).map(permission => + return dropdownValues.filter(permission => !Doc.noviceMode || ![SharingPermissions.View, SharingPermissions.SelfEdit].includes(permission as any)).map(permission => (
- {Doc.UserDoc().noviceMode ? (null) : + {Doc.noviceMode ? (null) :
this.layoutDocAcls = !this.layoutDocAcls)} checked={this.layoutDocAcls} />
} diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index efc1644fe..9a0f25fe3 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -34,8 +34,8 @@ export class DashboardView extends React.Component { clickDashboard = async (e: React.MouseEvent, dashboard: Doc) => { if (e.detail === 2) { - Doc.UserDoc().activeDashboard = dashboard; - Doc.UserDoc().activePage = "dashboard"; + CurrentUserUtils.ActiveDashboard = dashboard; + CurrentUserUtils.ActivePage = "dashboard"; } } diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index be5927497..169bd3873 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -65,7 +65,7 @@ export function ViewBoxBaseComponent

() { isContentActive = (outsideReaction?: boolean) => ( this.props.isContentActive?.() === false ? false : - (CurrentUserUtils.SelectedTool !== InkTool.None || + (CurrentUserUtils.ActiveTool !== InkTool.None || (this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this.props.rootSelected(outsideReaction)) ? true : undefined)) @@ -200,7 +200,7 @@ export function ViewBoxAnnotatableComponent

() if (effectiveAcl === AclAugment) { added.map(doc => { - if ([AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))) inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc); + if ([AclAdmin, AclEdit].includes(GetEffectiveAcl(doc)) && CurrentUserUtils.ActiveDashboard) inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc); doc.context = this.props.Document; if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document; Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc); @@ -213,7 +213,7 @@ export function ViewBoxAnnotatableComponent

() doc.context = this.props.Document; if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document; - inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc); + CurrentUserUtils.ActiveDashboard && inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc); }); const annoDocs = targetDataDoc[annotationKey ?? this.annotationKey] as List; if (annoDocs instanceof List) annoDocs.push(...added); diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 0bbe473d7..9b8f7238d 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -347,7 +347,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV

{this.menuButton}
- {/* {Doc.UserDoc().noviceMode ? (null) :
+ {/* {Doc.noviceMode ? (null) :
{this.moreButton}
} */}
; diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 6afe64868..e960f5cca 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -129,7 +129,7 @@ export class GestureOverlay extends Touchable { // and this seems to be the only way of differentiating pen and touch on touch events if (pt.radiusX > 1 && pt.radiusY > 1) { InkTranscription.Instance.createInkGroup(); - Doc.UserDoc().activeInkTool = InkTool.None; + CurrentUserUtils.ActiveTool = InkTool.None; this.prevPoints.set(pt.identifier, pt); } } @@ -498,18 +498,18 @@ export class GestureOverlay extends Touchable { setupMoveUpEvents(this, e, returnFalse, returnFalse, action((e: PointerEvent, doubleTap?: boolean) => { if (doubleTap) { InkTranscription.Instance.createInkGroup(); - CurrentUserUtils.SelectedTool = InkTool.None; + CurrentUserUtils.ActiveTool = InkTool.None; return; } })); } - if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { + if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool)) { if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { - CurrentUserUtils.SelectedTool = InkTool.Write; + CurrentUserUtils.ActiveTool = InkTool.Write; } this._points.push({ X: e.clientX, Y: e.clientY }); setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction); - // if (CurrentUserUtils.SelectedTool === InkTool.Highlighter) SetActiveInkColor("rgba(245, 230, 95, 0.75)"); + // if (CurrentUserUtils.ActiveTool === InkTool.Highlighter) SetActiveInkColor("rgba(245, 230, 95, 0.75)"); } } @@ -606,7 +606,7 @@ export class GestureOverlay extends Touchable { this._points = []; if (!CollectionFreeFormViewChrome.Instance?._keepPrimitiveMode) { this.InkShape = ""; - Doc.UserDoc().activeInkTool = InkTool.None; + CurrentUserUtils.ActiveTool = InkTool.None; } } // if we're not drawing in a toolglass try to recognize as gesture diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 16d7c9a23..f5122df3f 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -57,7 +57,7 @@ export class KeyManager { public handle = action((e: KeyboardEvent) => { if (e.key?.toLowerCase() === "shift") DocumentDecorations.Instance.AddToSelection = true; - //if (!Doc.UserDoc().noviceMode && e.key.toLocaleLowerCase() === "shift") DocServer.UPDATE_SERVER_CACHE(true); + //if (!Doc.noviceMode && e.key.toLocaleLowerCase() === "shift") DocServer.UPDATE_SERVER_CACHE(true); const keyname = e.key && e.key.toLowerCase(); this.handleGreedy(keyname); @@ -112,7 +112,7 @@ export class KeyManager { DocumentLinksButton.StartLink = undefined; DocumentLinksButton.StartLinkView = undefined; InkStrokeProperties.Instance._controlButton = false; - CurrentUserUtils.SelectedTool = InkTool.None; + CurrentUserUtils.ActiveTool = InkTool.None; DragManager.CompleteWindowDrag?.(true); var doDeselect = true; if (SnappingManager.GetIsDragging()) { @@ -241,9 +241,9 @@ export class KeyManager { } } break; - case "e": CurrentUserUtils.SelectedTool = InkTool.Eraser; + case "e": CurrentUserUtils.ActiveTool = InkTool.Eraser; break; - case "p": CurrentUserUtils.SelectedTool = InkTool.Pen; + case "p": CurrentUserUtils.ActiveTool = InkTool.Pen; break; case "o": const target = SelectionManager.Docs().lastElement(); diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index 0449da483..471ad09e9 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -25,8 +25,8 @@ export class InkStrokeProperties { constructor() { InkStrokeProperties._Instance = this; - reaction(() => this._controlButton, button => button && (CurrentUserUtils.SelectedTool = InkTool.None)); - reaction(() => CurrentUserUtils.SelectedTool, tool => (tool !== InkTool.None) && (this._controlButton = false)); + reaction(() => this._controlButton, button => button && (CurrentUserUtils.ActiveTool = InkTool.None)); + reaction(() => CurrentUserUtils.ActiveTool, tool => (tool !== InkTool.None) && (this._controlButton = false)); } /** diff --git a/src/client/views/InkTranscription.tsx b/src/client/views/InkTranscription.tsx index 8ab54918c..487bbcd00 100644 --- a/src/client/views/InkTranscription.tsx +++ b/src/client/views/InkTranscription.tsx @@ -254,7 +254,7 @@ export class InkTranscription extends React.Component { */ createInkGroup() { // TODO nda - if document being added to is a inkGrouping then we can just add to that group - if (CurrentUserUtils.SelectedTool === InkTool.Write) { + if (CurrentUserUtils.ActiveTool === InkTool.Write) { CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => { // TODO: nda - will probably want to go through ffView unprocessed docs and then see if any of the inksToGroup docs are in it and only use those const selected = ffView.unprocessedDocs; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index aa5a815ac..35d89d2b1 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -345,7 +345,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { onClick: (e: React.MouseEvent) => this._handledClick && e.stopPropagation(), onContextMenu: () => { const cm = ContextMenu.Instance; - !Doc.UserDoc().noviceMode && cm?.addItem({ description: "Recognize Writing", event: this.analyzeStrokes, icon: "paint-brush" }); + !Doc.noviceMode && cm?.addItem({ description: "Recognize Writing", event: this.analyzeStrokes, icon: "paint-brush" }); cm?.addItem({ description: "Toggle Mask", event: () => InkingStroke.toggleMask(this.rootDoc), icon: "paint-brush" }); cm?.addItem({ description: "Edit Points", event: action(() => InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton), icon: "paint-brush" }); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 7e3916b3f..791c64630 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -381,7 +381,7 @@ export class MainView extends React.Component { addDocTab={this.addDocTabFunc} pinToPres={emptyFunction} docViewPath={returnEmptyDoclist} - styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards || this._sidebarContent.proto === CurrentUserUtils.MyFilesystem ? DashboardStyleProvider : DefaultStyleProvider} + styleProvider={this._sidebarContent.proto === CurrentUserUtils.MyDashboards || this._sidebarContent.proto === CurrentUserUtils.MyFilesystem ? DashboardStyleProvider : DefaultStyleProvider} rootSelected={returnTrue} removeDocument={returnFalse} ScreenToLocalTransform={this.mainContainerXf} @@ -656,7 +656,7 @@ export class MainView extends React.Component { {this.mainDashboardArea} ; case "home": return ; - } })(StrCast(Doc.UserDoc().activePage)) + } })(CurrentUserUtils.ActivePage) } diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index bdb3bb857..598fff29a 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -4,7 +4,7 @@ import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; import * as React from "react"; import ReactLoading from 'react-loading'; -import { Doc, WidthSym, HeightSym } from "../../fields/Doc"; +import { Doc, WidthSym, HeightSym, DocListCast } from "../../fields/Doc"; import { Id } from "../../fields/FieldSymbols"; import { Cast, NumCast } from "../../fields/Types"; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, Utils } from "../../Utils"; @@ -149,7 +149,7 @@ export class OverlayView extends React.Component { } removeOverlayDoc = (doc: Doc | Doc[]) => { - (doc instanceof Doc ? [doc] : doc).forEach(doc => Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc)); + (doc instanceof Doc ? [doc] : doc).forEach(doc => Doc.RemoveDocFromList(CurrentUserUtils.MyOverlayDocs, undefined, doc)); return true; } @@ -158,7 +158,7 @@ export class OverlayView extends React.Component { }.bind(this)); @computed get overlayDocs() { - return CurrentUserUtils.MyOverlayDocs?.map(d => { + return DocListCast(CurrentUserUtils.MyOverlayDocs?.data).map(d => { let offsetx = 0, offsety = 0; const dref = React.createRef(); const onPointerMove = action((e: PointerEvent, down: number[]) => { @@ -172,7 +172,7 @@ export class OverlayView extends React.Component { dragData.dropAction = "move"; dragData.removeDocument = (doc: Doc | Doc[]) => { const docs = (doc instanceof Doc) ? [doc] : doc; - docs.forEach(d => Doc.RemoveDocFromList(Cast(Doc.UserDoc().myOverlayDocs, Doc, null), "data", d)); + docs.forEach(d => Doc.RemoveDocFromList(CurrentUserUtils.MyOverlayDocs, undefined, d)); return true; }; dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => { diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 74055f057..9c6d9a108 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -200,7 +200,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { {list}
- {Doc.UserDoc().noviceMode ? (null) :
Edit onClick Script
} + {Doc.noviceMode ? (null) :
Edit onClick Script
}
; } @computed @@ -229,7 +229,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { const isTree = this.selectedDoc?._viewType === CollectionViewType.Tree; const isTabView = this.selectedTabView; const toggle = (ele: JSX.Element | null, style?: React.CSSProperties) =>
{ele}
; - const isNovice = Doc.UserDoc().noviceMode; + const isNovice = Doc.noviceMode; return !this.selectedDoc ? (null) :
{toggle(this.titleButton)} diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 2cf334ae1..90c86fa18 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -11,7 +11,7 @@ import { Id } from "../../fields/FieldSymbols"; import { InkField } from "../../fields/InkField"; import { List } from "../../fields/List"; import { ComputedField } from "../../fields/ScriptField"; -import { BoolCast, Cast, NumCast, StrCast } from "../../fields/Types"; +import { Cast, NumCast, StrCast, DocCast } from "../../fields/Types"; import { denormalizeEmail, GetEffectiveAcl, SharingPermissions } from "../../fields/util"; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents } from "../../Utils"; import { DocumentType } from "../documents/DocumentTypes"; @@ -340,7 +340,7 @@ export class PropertiesView extends React.Component { */ @undoBatch changePermissions = (e: any, user: string) => { - const docs = SelectionManager.Views().length < 2 ? [this.selectedDoc] : SelectionManager.Views().map(docView => docView.props.Document); + const docs = SelectionManager.Views().length < 2 ? (this.selectedDoc ? [this.selectedDoc]:[]) : SelectionManager.Views().map(docView => docView.props.Document); SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, docs); } @@ -355,7 +355,7 @@ export class PropertiesView extends React.Component { value={permission} onChange={e => this.changePermissions(e, user)}> {dropdownValues.filter(permission => - !Doc.UserDoc().noviceMode || ![SharingPermissions.View, SharingPermissions.SelfEdit].includes(permission as any)).map(permission => + !Doc.noviceMode || ![SharingPermissions.View, SharingPermissions.SelfEdit].includes(permission as any)).map(permission => )} ; } @@ -419,7 +419,7 @@ export class PropertiesView extends React.Component { // all selected docs const docs = SelectionManager.Views().length < 2 ? - [this.layoutDocAcls ? this.selectedDoc : this.selectedDoc[DataSym]] + [this.layoutDocAcls ? this.selectedDoc : this.selectedDoc?.[DataSym]] : SelectionManager.Views().map(docView => this.layoutDocAcls ? docView.props.Document : docView.props.Document[DataSym]); const target = docs[0]; @@ -907,7 +907,7 @@ export class PropertiesView extends React.Component { {!this.openSharing ? (null) :
- {!Doc.UserDoc().noviceMode ? (
+ {!Doc.noviceMode ? (
this.layoutDocAcls = !this.layoutDocAcls)} @@ -931,42 +931,46 @@ export class PropertiesView extends React.Component { * If it doesn't exist, it creates it. */ checkFilterDoc() { - if (!this.selectedDoc.currentFilter) this.selectedDoc.currentFilter = CurrentUserUtils.createFilterDoc(); + if (!this.selectedDoc?.currentFilter) this.selectedDoc!.currentFilter = CurrentUserUtils.createFilterDoc(); } /** * Creates a new currentFilter for this.filterDoc, */ createNewFilterDoc = () => { - const currentDocFilters = this.selectedDoc._docFilters; - const currentDocRangeFilters = this.selectedDoc._docRangeFilters; - this.selectedDoc._docFilters = new List(); - this.selectedDoc._docRangeFilters = new List(); - (this.selectedDoc.currentFilter as Doc)._docFiltersList = currentDocFilters; - (this.selectedDoc.currentFilter as Doc)._docRangeFiltersList = currentDocRangeFilters; - this.selectedDoc.currentFilter = CurrentUserUtils.createFilterDoc(); + if (this.selectedDoc) { + const currentDocFilters = this.selectedDoc._docFilters; + const currentDocRangeFilters = this.selectedDoc._docRangeFilters; + this.selectedDoc._docFilters = new List(); + this.selectedDoc._docRangeFilters = new List(); + (this.selectedDoc.currentFilter as Doc)._docFiltersList = currentDocFilters; + (this.selectedDoc.currentFilter as Doc)._docRangeFiltersList = currentDocRangeFilters; + this.selectedDoc.currentFilter = CurrentUserUtils.createFilterDoc(); + } } /** * Updates this.filterDoc's currentFilter and saves the docFilters on the currentFilter */ updateFilterDoc = (doc: Doc) => { - if (doc === this.selectedDoc.currentFilter) return; // causes problems if you try to reapply the same doc - const savedDocFilters = doc._docFiltersList; - const currentDocFilters = this.selectedDoc._docFilters; - this.selectedDoc._docFilters = new List(); - (this.selectedDoc.currentFilter as Doc)._docFiltersList = currentDocFilters; - this.selectedDoc.currentFilter = doc; - doc._docFiltersList = new List(); - this.selectedDoc._docFilters = savedDocFilters; - - const savedDocRangeFilters = doc._docRangeFiltersList; - const currentDocRangeFilters = this.selectedDoc._docRangeFilters; - this.selectedDoc._docRangeFilters = new List(); - (this.selectedDoc.currentFilter as Doc)._docRangeFiltersList = currentDocRangeFilters; - this.selectedDoc.currentFilter = doc; - doc._docRangeFiltersList = new List(); - this.selectedDoc._docRangeFilters = savedDocRangeFilters; + if (this.selectedDoc) { + if (doc === this.selectedDoc.currentFilter) return; // causes problems if you try to reapply the same doc + const savedDocFilters = doc._docFiltersList; + const currentDocFilters = this.selectedDoc._docFilters; + this.selectedDoc._docFilters = new List(); + (this.selectedDoc.currentFilter as Doc)._docFiltersList = currentDocFilters; + this.selectedDoc.currentFilter = doc; + doc._docFiltersList = new List(); + this.selectedDoc._docFilters = savedDocFilters; + + const savedDocRangeFilters = doc._docRangeFiltersList; + const currentDocRangeFilters = this.selectedDoc._docRangeFilters; + this.selectedDoc._docRangeFilters = new List(); + (this.selectedDoc.currentFilter as Doc)._docRangeFiltersList = currentDocRangeFilters; + this.selectedDoc.currentFilter = doc; + doc._docRangeFiltersList = new List(); + this.selectedDoc._docRangeFilters = savedDocRangeFilters; + } } @computed get filtersSubMenu() { @@ -1059,13 +1063,13 @@ export class PropertiesView extends React.Component {
- {!Doc.UserDoc().noviceMode && this.openFields ?
+ {!Doc.noviceMode && this.openFields ?
{this.fieldsCheckbox}
Layout
: null} {!this.openFields ? (null) :
- {Doc.UserDoc().noviceMode ? this.noviceFields : this.expandedField} + {Doc.noviceMode ? this.noviceFields : this.expandedField}
}
; } @@ -1122,7 +1126,7 @@ export class PropertiesView extends React.Component { @undoBatch handleDescriptionChange = action((value: string) => { - if (LinkManager.currentLink) { + if (LinkManager.currentLink && this.selectedDoc) { this.selectedDoc.description = value; this.description = value; return true; @@ -1131,7 +1135,7 @@ export class PropertiesView extends React.Component { @undoBatch handleLinkRelationshipChange = action((value: string) => { - if (LinkManager.currentLink) { + if (LinkManager.currentLink && this.selectedDoc) { this.selectedDoc.linkRelationship = value; this.relationship = value; return true; @@ -1188,7 +1192,7 @@ export class PropertiesView extends React.Component { @undoBatch changeFollowBehavior = action((follow: string) => { - if (LinkManager.currentLink) { + if (LinkManager.currentLink && this.selectedDoc) { this.selectedDoc.followLinkLocation = follow; return true; } @@ -1219,18 +1223,18 @@ export class PropertiesView extends React.Component { } toggleAnchor = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc.linkAutoMove = !this.selectedDoc.linkAutoMove))); + setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (this.selectedDoc.linkAutoMove = !this.selectedDoc.linkAutoMove)))); } toggleArrow = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc.displayArrow = !this.selectedDoc.displayArrow))); + setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (this.selectedDoc.displayArrow = !this.selectedDoc.displayArrow)))); } toggleZoomToTarget1 = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => Cast(this.selectedDoc.anchor1, Doc, null).followLinkZoom = !Cast(this.selectedDoc.anchor1, Doc, null).followLinkZoom))); + setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (DocCast(this.selectedDoc.anchor1).followLinkZoom = !DocCast(this.selectedDoc.anchor1).followLinkZoom)))); } toggleZoomToTarget2 = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => Cast(this.selectedDoc.anchor2, Doc, null).followLinkZoom = !Cast(this.selectedDoc.anchor2, Doc, null).followLinkZoom))); + setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (DocCast(this.selectedDoc.anchor2).followLinkZoom = !DocCast(this.selectedDoc.anchor2).followLinkZoom)))); } @computed @@ -1238,7 +1242,7 @@ export class PropertiesView extends React.Component { return this.handleLinkRelationshipChange(e.currentTarget.value)} @@ -1252,7 +1256,7 @@ export class PropertiesView extends React.Component { return this.handleDescriptionChange(e.currentTarget.value)} @@ -1273,7 +1277,7 @@ export class PropertiesView extends React.Component { // } render() { - const isNovice = BoolCast(Doc.UserDoc().noviceMode); + const isNovice = Doc.noviceMode; if (!this.selectedDoc && !this.isPres) { return
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 636f7042f..689ee4fc1 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -15,6 +15,7 @@ import { DocumentView } from "./nodes/DocumentView"; import { DefaultStyleProvider } from "./StyleProvider"; import './TemplateMenu.scss'; import React = require("react"); +import { CurrentUserUtils } from "../util/CurrentUserUtils"; @observer class TemplateToggle extends React.Component<{ template: string, checked: boolean, toggle: (event: React.ChangeEvent, template: string) => void }> { @@ -111,22 +112,22 @@ export class TemplateMenu extends React.Component { const firstDoc = this.props.docViews[0].props.Document; const templateName = StrCast(firstDoc.layoutKey, "layout").replace("layout_", ""); const noteTypes = DocListCast(Cast(Doc.UserDoc()["template-notes"], Doc, null)?.data); - const addedTypes = Doc.UserDoc().noviceMode ? [] : DocListCast(Cast(Doc.UserDoc()["template-buttons"], Doc, null)?.data); + const addedTypes = Doc.noviceMode ? [] : DocListCast(Cast(Doc.UserDoc()["template-buttons"], Doc, null)?.data); const layout = Doc.Layout(firstDoc); const templateMenu: Array = []; this.props.templates?.forEach((checked, template) => templateMenu.push()); templateMenu.push(); templateMenu.push(); - !Doc.UserDoc().noviceMode && templateMenu.push(); + !Doc.noviceMode && templateMenu.push(); addedTypes.concat(noteTypes).map(template => template.treeViewChecked = this.templateIsUsed(firstDoc, template)); this._addedKeys && Array.from(this._addedKeys).filter(key => !noteTypes.some(nt => nt.title === key)).forEach(template => templateMenu.push( this.toggleLayout(e, template)} />)); return
    - {Doc.UserDoc().noviceMode ? (null) : } + {Doc.noviceMode ? (null) : } {templateMenu} - {Doc.UserDoc().noviceMode ? (null) : { stack.header?.element.on('mousedown', (e: any) => { - if (e.target === stack.header?.element[0] && e.button === 2) { - const dashboard= CurrentUserUtils.ActiveDashboard; + const dashboard = CurrentUserUtils.ActiveDashboard; + if (dashboard && e.target === stack.header?.element[0] && e.button === 2) { dashboard["pane-count"] = NumCast(dashboard["pane-count"]) + 1; const docToAdd = Docs.Create.FreeformDocument([], { _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _backgroundGridShow: true, _fitWidth: true, title: `Untitled Tab ${NumCast(dashboard["pane-count"])}`, @@ -462,12 +462,14 @@ export class CollectionDockingView extends CollectionSubView() { .click(action(() => { // stack.config.fixed = !stack.config.fixed; // force the stack to have a fixed size const dashboard = CurrentUserUtils.ActiveDashboard; - dashboard["pane-count"] = NumCast(dashboard["pane-count"]) + 1; - const docToAdd = Docs.Create.FreeformDocument([], { - _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _fitWidth: true, _backgroundGridShow: true, title: `Untitled Tab ${NumCast(dashboard["pane-count"])}` - }); - this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd); - CollectionDockingView.AddSplit(docToAdd, "", stack); + if (dashboard) { + dashboard["pane-count"] = NumCast(dashboard["pane-count"]) + 1; + const docToAdd = Docs.Create.FreeformDocument([], { + _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _fitWidth: true, _backgroundGridShow: true, title: `Untitled Tab ${NumCast(dashboard["pane-count"])}` + }); + this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd); + CollectionDockingView.AddSplit(docToAdd, "", stack); + } })); } @@ -480,6 +482,6 @@ ScriptingGlobals.add(function openInLightbox(doc: any) { LightboxView.AddDocTab( "opens up document in a lightbox", "(doc: any)"); ScriptingGlobals.add(function openOnRight(doc: any) { return CollectionDockingView.AddSplit(doc, "right"); }, "opens up document in tab on right side of the screen", "(doc: any)"); -ScriptingGlobals.add(function openInOverlay(doc: any) { return Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc); }, +ScriptingGlobals.add(function openInOverlay(doc: any) { return Doc.AddDocToList(CurrentUserUtils.MyOverlayDocs, undefined, doc); }, "opens up document in screen overlay layer", "(doc: any)"); ScriptingGlobals.add(function useRightSplit(doc: any, shiftKey?: boolean) { CollectionDockingView.ReplaceTab(doc, "right", undefined, shiftKey); }); \ No newline at end of file diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 1c25421f5..9b1bb5b97 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -268,17 +268,20 @@ export class CollectionViewBaseChrome extends React.Component { this.target._docFilters = undefined; this.target._searchFilterDocs = undefined; }), initialize: (button: Doc) => { - button['target-docFilters'] = (CurrentUserUtils.MySearcher._docFilters || CurrentUserUtils.ActiveDashboard._docFilters) instanceof ObjectField ? - ObjectField.MakeCopy((CurrentUserUtils.MySearcher._docFilters || CurrentUserUtils.ActiveDashboard._docFilters) as any as ObjectField) : undefined; - button['target-searchFilterDocs'] = CurrentUserUtils.ActiveDashboard._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(CurrentUserUtils.ActiveDashboard._searchFilterDocs as any as ObjectField) : undefined; + const activeDash = CurrentUserUtils.ActiveDashboard; + if (activeDash) { + button['target-docFilters'] = (CurrentUserUtils.MySearcher._docFilters || activeDash._docFilters) instanceof ObjectField ? + ObjectField.MakeCopy((CurrentUserUtils.MySearcher._docFilters || activeDash._docFilters) as any as ObjectField) : undefined; + button['target-searchFilterDocs'] = activeDash._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(activeDash._searchFilterDocs as any as ObjectField) : undefined; + } }, }; - @computed get _freeform_commands() { return Doc.UserDoc().noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; } - @computed get _stacking_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._contentCommand, this._templateCommand]; } - @computed get _masonry_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._contentCommand, this._templateCommand]; } - @computed get _schema_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._templateCommand, this._narrativeCommand]; } - @computed get _doc_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._openLinkInCommand, this._onClickCommand]; } + @computed get _freeform_commands() { return Doc.noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; } + @computed get _stacking_commands() { return Doc.noviceMode ? undefined : [this._contentCommand, this._templateCommand]; } + @computed get _masonry_commands() { return Doc.noviceMode ? undefined : [this._contentCommand, this._templateCommand]; } + @computed get _schema_commands() { return Doc.noviceMode ? undefined : [this._templateCommand, this._narrativeCommand]; } + @computed get _doc_commands() { return Doc.noviceMode ? undefined : [this._openLinkInCommand, this._onClickCommand]; } @computed get _tree_commands() { return undefined; } private get _buttonizableCommands() { switch (this.props.type) { @@ -467,7 +470,7 @@ export class CollectionViewBaseChrome extends React.Component { const doc = Docs.Create.ScreenshotDocument({ title: "screen recording", _fitWidth: true, _width: 400, _height: 200, mediaState: "pendingRecording" }); - //Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc); + //Doc.AddDocToList(CurrentUserUtils.MyOverlayDocs, undefined, doc); CollectionDockingView.AddSplit(doc, "right"); } @@ -691,8 +694,8 @@ export class CollectionFreeFormViewChrome extends React.Component Back Frame
} placement="bottom">
@@ -879,7 +882,7 @@ export class CollectionStackingViewChrome extends React.Component key.indexOf("title") >= 0 || key.indexOf("author") >= 0 || key.indexOf("creationDate") >= 0 || key.indexOf("lastModified") >= 0 || diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index dddae4a34..277fcd59c 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -598,7 +598,7 @@ export class CollectionStackingView extends CollectionSubView {buttonMenu || noviceExplainer ?
{buttonMenu ? this.buttonMenu : null} - {Doc.UserDoc().noviceMode && noviceExplainer ? + {Doc.noviceMode && noviceExplainer ?
{noviceExplainer}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 7f96217b8..f3a798143 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -224,8 +224,8 @@ export class CollectionStackingViewFieldColumn extends React.Component { Doc.GetProto(this.props.Document)[name] = ""; const created = Docs.Create.TextDocument("", { title: name, _width: 250, _autoHeight: true }); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index e809bfbce..ba72fb7b9 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -67,7 +67,7 @@ export class CollectionTreeView extends CollectionSubView this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive)); - isContentActive = (outsideReaction?: boolean) => (CurrentUserUtils.SelectedTool !== InkTool.None || + isContentActive = (outsideReaction?: boolean) => (CurrentUserUtils.ActiveTool !== InkTool.None || (this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.rootSelected(outsideReaction)) ? true : false) @@ -164,7 +164,7 @@ export class CollectionTreeView extends CollectionSubView { // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout - if (!Doc.UserDoc().noviceMode) { + if (!Doc.noviceMode) { const layoutItems: ContextMenuProps[] = []; layoutItems.push({ description: "Make tree state " + (this.doc.treeViewOpenIsTransient ? "persistent" : "transient"), event: () => this.doc.treeViewOpenIsTransient = !this.doc.treeViewOpenIsTransient, icon: "paint-brush" }); layoutItems.push({ description: (this.doc.treeViewHideHeaderFields ? "Show" : "Hide") + " Header Fields", event: () => this.doc.treeViewHideHeaderFields = !this.doc.treeViewHideHeaderFields, icon: "paint-brush" }); @@ -286,7 +286,7 @@ export class CollectionTreeView extends CollectionSubView {this.rootDoc.explainer}
; } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 965f0a352..4b5c5e3fb 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -160,8 +160,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent func(CollectionViewType.Masonry), icon: "columns" }); subItems.push({ description: "Carousel", event: () => func(CollectionViewType.Carousel), icon: "columns" }); subItems.push({ description: "3D Carousel", event: () => func(CollectionViewType.Carousel3D), icon: "columns" }); - !Doc.UserDoc().noviceMode && subItems.push({ description: "Pivot/Time", event: () => func(CollectionViewType.Time), icon: "columns" }); - !Doc.UserDoc().noviceMode && subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" }); + !Doc.noviceMode && subItems.push({ description: "Pivot/Time", event: () => func(CollectionViewType.Time), icon: "columns" }); + !Doc.noviceMode && subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" }); subItems.push({ description: "Grid", event: () => func(CollectionViewType.Grid), icon: "th-list" }); if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.isGroup && !this.rootDoc.annotationOn) { @@ -184,16 +184,16 @@ export class CollectionView extends ViewBoxAnnotatableComponent this.rootDoc.forceActive = !this.rootDoc.forceActive, icon: "project-diagram" }) : null; + !Doc.noviceMode ? optionItems.splice(0, 0, { description: `${this.rootDoc.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.rootDoc.forceActive = !this.rootDoc.forceActive, icon: "project-diagram" }) : null; if (this.rootDoc.childLayout instanceof Doc) { optionItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.rootDoc.childLayout as Doc, "add:right"), icon: "project-diagram" }); } if (this.rootDoc.childClickedOpenTemplateView instanceof Doc) { optionItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.rootDoc.childClickedOpenTemplateView as Doc, "add:right"), icon: "project-diagram" }); } - !Doc.UserDoc().noviceMode && optionItems.push({ description: `${this.rootDoc.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.rootDoc.isInPlaceContainer = !this.rootDoc.isInPlaceContainer, icon: "project-diagram" }); + !Doc.noviceMode && optionItems.push({ description: `${this.rootDoc.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.rootDoc.isInPlaceContainer = !this.rootDoc.isInPlaceContainer, icon: "project-diagram" }); - if (!Doc.UserDoc().noviceMode) { + if (!Doc.noviceMode) { optionItems.push({ description: "Create Branch", event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), "add:right"), icon: "project-diagram" }); @@ -210,7 +210,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent ImageUtils.ExportHierarchyToFileSystem(this.rootDoc) }); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 022b9fa24..70db121d1 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -277,7 +277,7 @@ export class TabDocView extends React.Component { pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Update selected array }); if (!Array.from(CollectionDockingView.Instance.tabMap).map(d => d.DashDoc).includes(curPres)) { - const docs = Cast(Cast(Doc.UserDoc().myOverlayDocs, Doc, null).data, listSpec(Doc), []); + const docs = Cast(CurrentUserUtils.MyOverlayDocs.data, listSpec(Doc), []); if (docs.includes(curPres)) docs.splice(docs.indexOf(curPres), 1); CollectionDockingView.AddSplit(curPres, "right"); setTimeout(() => DocumentManager.Instance.jumpToDocument(docList.lastElement(), false, undefined, []), 100); // keeps the pinned doc in view since the sidebar shifts things diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 59dc5671b..704b8989a 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -114,7 +114,7 @@ export class TreeView extends React.Component { return this.doc.viewType === CollectionViewType.Docking ? this.fieldKey : this.props.treeView.dashboardMode ? this.fieldKey : this.props.treeView.fileSysMode ? (this.doc.isFolder ? this.fieldKey : "aliases") : // for displaying - this.props.treeView.outlineMode || this.childDocs ? this.fieldKey : Doc.UserDoc().noviceMode ? "layout" : StrCast(this.props.treeView.doc.treeViewExpandedView, "fields"); + this.props.treeView.outlineMode || this.childDocs ? this.fieldKey : Doc.noviceMode ? "layout" : StrCast(this.props.treeView.doc.treeViewExpandedView, "fields"); } @computed get doc() { return this.props.document; } @@ -560,8 +560,8 @@ export class TreeView extends React.Component { const links = () => DocListCast(this.doc.links).length && !this.props.treeView.dashboardMode ? "links" : ""; const data = () => this.childDocs || this.props.treeView.dashboardMode ? this.fieldKey : ""; const aliases = () => this.props.treeView.dashboardMode ? "" : "aliases"; - const fields = () => Doc.UserDoc().noviceMode ? "" : "fields"; - const layout = (Doc.UserDoc().noviceMode) || this.doc.viewType === CollectionViewType.Docking ? [] : ["layout"]; + const fields = () => Doc.noviceMode ? "" : "fields"; + const layout = (Doc.noviceMode) || this.doc.viewType === CollectionViewType.Docking ? [] : ["layout"]; return [data(), ...layout, ...(this.props.treeView.fileSysMode ? [aliases(), links(), annos()] : []), fields()].filter(m => m); } @action diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c07e44fcc..ffe146ae4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -458,7 +458,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) return; if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) { - Doc.UserDoc().activeInkTool = InkTool.None; + CurrentUserUtils.ActiveTool = InkTool.None; if (this.props.isContentActive(true)) e.stopPropagation(); } else if (!e.cancelBubble) { if (this.tryDragCluster(e, this._hitCluster)) { @@ -834,7 +834,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || CurrentUserUtils.MyOverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; + if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming e.stopPropagation(); } @@ -1031,7 +1031,7 @@ export class CollectionFreeFormView extends CollectionSubView { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: "compress-arrows-alt" }); - !Doc.UserDoc().noviceMode && Doc.UserDoc().defaultTextLayout && appearanceItems.push({ description: "Reset default note style", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); + !Doc.noviceMode && Doc.UserDoc().defaultTextLayout && appearanceItems.push({ description: "Reset default note style", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); appearanceItems.push({ description: `${this.fitContentsToBox ? "Make Zoomable" : "Scale to Window"}`, event: () => this.Document._fitContentsToBox = !this.fitContentsToBox, icon: !this.fitContentsToBox ? "expand-arrows-alt" : "compress-arrows-alt" }); appearanceItems.push({ description: `Pin View`, event: () => TabDocView.PinDoc(this.rootDoc, {pinDocView:true, panelWidth: this.props.PanelWidth(), panelHeight:this.props.PanelHeight()}), icon: "map-pin" }); //appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: "compress-arrows-alt" }); @@ -1640,27 +1640,27 @@ export class CollectionFreeFormView extends CollectionSubView s.type === DocumentType.INK).length > 0 && appearanceItems.push({ description: "Ink to math", event: () => this.transcribeStrokes(true), icon: "square-root-alt" }); - !Doc.UserDoc().noviceMode ? appearanceItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }) : null; + !Doc.noviceMode ? appearanceItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }) : null; !appearance && ContextMenu.Instance.addItem({ description: "Appearance...", subitems: appearanceItems, icon: "eye" }); const viewctrls = ContextMenu.Instance.findByDescription("UI Controls..."); const viewCtrlItems = viewctrls && "subitems" in viewctrls ? viewctrls.subitems : []; - !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " Snap Lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }) : null; - !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (this.Document._useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document._useClusters), icon: "braille" }) : null; + !Doc.noviceMode ? viewCtrlItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " Snap Lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }) : null; + !Doc.noviceMode ? viewCtrlItems.push({ description: (this.Document._useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document._useClusters), icon: "braille" }) : null; !viewctrls && ContextMenu.Instance.addItem({ description: "UI Controls...", subitems: viewCtrlItems, icon: "eye" }); const options = ContextMenu.Instance.findByDescription("Options..."); const optionItems = options && "subitems" in options ? options.subitems : []; - !this.props.isAnnotationOverlay && !Doc.UserDoc().noviceMode && + !this.props.isAnnotationOverlay && !Doc.noviceMode && optionItems.push({ description: (this._showAnimTimeline ? "Close" : "Open") + " Animation Timeline", event: action(() => this._showAnimTimeline = !this._showAnimTimeline), icon: "eye" }); this.props.renderDepth && optionItems.push({ description: "Use Background Color as Default", event: () => Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor), icon: "palette" }); - if (!Doc.UserDoc().noviceMode) { + if (!Doc.noviceMode) { optionItems.push({ description: (!Doc.NativeWidth(this.layoutDoc) || !Doc.NativeHeight(this.layoutDoc) ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" }); } !options && ContextMenu.Instance.addItem({ description: "Options...", subitems: optionItems, icon: "eye" }); const mores = ContextMenu.Instance.findByDescription("More..."); const moreItems = mores && "subitems" in mores ? mores.subitems : []; - if (!Doc.UserDoc().noviceMode) { + if (!Doc.noviceMode) { moreItems.push({ description: "Export collection", icon: "download", event: async () => Doc.Zip(this.props.Document) }); moreItems.push({ description: "Import exported collection", icon: "upload", event: ({ x, y }) => this.importDocument(x, y) }); } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 051da795f..b62020a04 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -330,7 +330,7 @@ export class MarqueeView extends React.Component { if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) { - if (CurrentUserUtils.SelectedTool === InkTool.None) { + if (CurrentUserUtils.ActiveTool === InkTool.None) { if (!(e.nativeEvent as any).marqueeHit) { (e.nativeEvent as any).marqueeHit = true; if (!this.props.trySelectCluster(e.shiftKey)) { @@ -367,7 +367,7 @@ export class MarqueeView extends React.Component { Doc.GetProto(doc).data = new List(selected); Doc.GetProto(doc).title = makeGroup ? "grouping" : "nested freeform"; - !this.props.isAnnotationOverlay && Doc.AddDocToList(Cast(Doc.UserDoc().myFileOrphans, Doc, null), "data", Doc.GetProto(doc)); + !this.props.isAnnotationOverlay && Doc.AddDocToList(CurrentUserUtils.MyFileOrphans, undefined, Doc.GetProto(doc)); doc._panX = doc._panY = 0; return doc; })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true)); @@ -643,7 +643,7 @@ export class MarqueeView extends React.Component e.preventDefault()} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx index 0875c80b3..9653f2808 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx @@ -321,7 +321,7 @@ export class KeysDropdown extends React.Component { const whitelistKeys = ["context", "author", "*lastModified", "text", "data", "tags", "creationDate"]; const keyOptions = this._searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1); const showKeys = new Set(); - [...keyOptions, ...whitelistKeys].forEach(key => (!Doc.UserDoc().noviceMode || + [...keyOptions, ...whitelistKeys].forEach(key => (!Doc.noviceMode || whitelistKeys.includes(key) || ((!key.startsWith("_") && key[0] === key[0].toUpperCase()) || key[0] === "#")) ? showKeys.add(key) : null); return Array.from(showKeys.keys()).filter(key => !this._searchTerm || key.includes(this._searchTerm)); diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 669622455..8e24fce11 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -348,11 +348,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent() { @undoBatch @action static switchColor(color: ColorState) { - // Doc.UserDoc().backgroundColor = Utils.colorString(color); // bcz: this can't go here ... needs a proper home in the settings panel SetActiveInkColor(color.hex); SelectionManager.Views().map(view => { @@ -49,7 +48,7 @@ export class ColorBox extends ViewBoxBaseComponent() { style={{ transform: `scale(${scaling})`, width: `${100 * scaling}%`, height: `${100 * scaling}%` }} > CurrentUserUtils.SelectedTool === InkTool.None && ColorBox.switchColor(c)} + onChange={c => CurrentUserUtils.ActiveTool === InkTool.None && ColorBox.switchColor(c)} color={StrCast(SelectionManager.Views()?.[0]?.rootDoc?._backgroundColor, ActiveInkColor())} presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e2b37d2b4..4d84a8ad2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -327,7 +327,7 @@ export class DocumentViewInternal extends DocComponent 3 || Math.abs(this._downY - touch.clientY) > 3)) { if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler)) { @@ -543,9 +543,9 @@ export class DocumentViewInternal extends DocComponent { - if (this.rootDoc.type === DocumentType.INK && CurrentUserUtils.SelectedTool === InkTool.Eraser) return; + if (this.rootDoc.type === DocumentType.INK && CurrentUserUtils.ActiveTool === InkTool.Eraser) return; // continue if the event hasn't been canceled AND we are using a mouse or this has an onClick or onDragStart function (meaning it is a button document) - if (!(InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool))) { + if (!(InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool))) { if (!InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { e.stopPropagation(); if (SelectionManager.IsSelected(this.props.DocumentView(), true) && this.props.Document._viewType !== CollectionViewType.Docking) e.preventDefault(); // goldenlayout needs to be able to move its tabs, so can't preventDefault for it @@ -563,7 +563,7 @@ export class DocumentViewInternal extends DocComponent { if (e.cancelBubble) return; - if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool))) return; + if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool))) return; - if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.MyOverlayDocs.includes(this.layoutDoc)) { + if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.layoutDoc)) { if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) { document.removeEventListener("pointermove", this.onPointerMove); @@ -697,7 +697,7 @@ export class DocumentViewInternal extends DocComponent { - if (e && this.rootDoc._hideContextMenu && Doc.UserDoc().noviceMode) { + if (e && this.rootDoc._hideContextMenu && Doc.noviceMode) { e.preventDefault(); e.stopPropagation(); //!this.props.isSelected(true) && SelectionManager.SelectView(this.props.DocumentView(), false); @@ -747,8 +747,8 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(templateDoc, "add:right"), icon: "eye" }); - !Doc.UserDoc().noviceMode && appearanceItems.push({ + !Doc.noviceMode && templateDoc && appearanceItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, "add:right"), icon: "eye" }); + !Doc.noviceMode && appearanceItems.push({ description: "Add a Field", event: () => { const alias = Doc.MakeAlias(this.rootDoc); alias.layout = FormattedTextBox.LayoutString("newfield"); @@ -765,7 +765,7 @@ export class DocumentViewInternal extends DocComponent this.layoutDoc._showAudio = !this.layoutDoc._showAudio), icon: "microphone" }); + !Doc.noviceMode && appearanceItems.splice(0, 0, { description: `${!this.layoutDoc._showAudio ? "Show" : "Hide"} Audio Button`, event: action(() => this.layoutDoc._showAudio = !this.layoutDoc._showAudio), icon: "microphone" }); const existingOnClick = cm.findByDescription("OnClick..."); const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; @@ -778,8 +778,8 @@ export class DocumentViewInternal extends DocComponent this.Document.followLinkZoom = !this.Document.followLinkZoom, icon: this.Document.ignoreClick ? "unlock" : "lock" }); if (!this.Document.annotationOn) { @@ -803,7 +803,7 @@ export class DocumentViewInternal extends DocComponent this.Document.dragFactory && (this.layoutDoc.onDragStart = ScriptField.MakeFunction('getAlias(this.dragFactory)')) }); funcs.push({ description: "Drag a Copy", icon: "edit", event: () => this.Document.dragFactory && (this.layoutDoc.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)')) }); funcs.push({ description: "Drag Document", icon: "edit", event: () => this.layoutDoc.onDragStart = undefined }); @@ -813,8 +813,8 @@ export class DocumentViewInternal extends DocComponent SharingManager.Instance.open(this.props.DocumentView()), icon: "users" }); - if (!Doc.UserDoc().noviceMode) { + (this.rootDoc._viewType !== CollectionViewType.Docking || !Doc.noviceMode) && moreItems.push({ description: "Share", event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: "users" }); + if (!Doc.noviceMode) { moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" }); moreItems.push({ description: `${this.Document._chromeHidden ? "Show" : "Hide"} Chrome`, event: () => this.Document._chromeHidden = !this.Document._chromeHidden, icon: "project-diagram" }); @@ -835,9 +835,9 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "add:right"), icon: "layer-group" }); - !Doc.UserDoc().noviceMode && helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument("/assets/cheat-sheet.pdf", { _width: 300, _height: 300 }), "add:right"), icon: "keyboard" }); - !Doc.UserDoc().noviceMode && helpItems.push({ description: "Print Document in Console", event: () => console.log(this.props.Document), icon: "hand-point-right" }); - !Doc.UserDoc().noviceMode && helpItems.push({ description: "Print DataDoc in Console", event: () => console.log(this.props.Document[DataSym]), icon: "hand-point-right" }); + !Doc.noviceMode && helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument("/assets/cheat-sheet.pdf", { _width: 300, _height: 300 }), "add:right"), icon: "keyboard" }); + !Doc.noviceMode && helpItems.push({ description: "Print Document in Console", event: () => console.log(this.props.Document), icon: "hand-point-right" }); + !Doc.noviceMode && helpItems.push({ description: "Print DataDoc in Console", event: () => console.log(this.props.Document[DataSym]), icon: "hand-point-right" }); cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" }); } @@ -860,7 +860,7 @@ export class DocumentViewInternal extends DocComponent Doc, forward?: () => boolean, back?: () => boolean }) => this._componentView = view); isContentActive = (outsideReaction?: boolean) => { return this.props.isContentActive() === false ? false : ( - CurrentUserUtils.SelectedTool !== InkTool.None || + CurrentUserUtils.ActiveTool !== InkTool.None || SnappingManager.GetIsDragging() || this.rootSelected() || this.props.Document.forceActive || diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx index 5add09653..17b57cb3b 100644 --- a/src/client/views/nodes/FilterBox.tsx +++ b/src/client/views/nodes/FilterBox.tsx @@ -8,7 +8,7 @@ import { List } from "../../../fields/List"; import { RichTextField } from "../../../fields/RichTextField"; import { listSpec } from "../../../fields/Schema"; import { ComputedField, ScriptField } from "../../../fields/ScriptField"; -import { Cast, NumCast, StrCast } from "../../../fields/Types"; +import { Cast, NumCast, StrCast, DocCast } from "../../../fields/Types"; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from "../../../Utils"; import { Docs } from "../../documents/Documents"; import { DocumentType } from "../../documents/DocumentTypes"; @@ -84,7 +84,7 @@ export class FilterBox extends ViewBoxBaseComponent() { return "data"; } @computed static get targetDocChildren() { - return DocListCast(FilterBox.targetDoc?.[FilterBox.targetDocChildKey] || CurrentUserUtils.ActiveDashboard.data); + return DocListCast(FilterBox.targetDoc?.[FilterBox.targetDocChildKey] || CurrentUserUtils.ActiveDashboard?.data); } @observable _loaded = false; @@ -115,7 +115,7 @@ export class FilterBox extends ViewBoxBaseComponent() { const keys = new Set(noviceFields); this.allDocs.forEach(doc => SearchBox.documentKeys(doc).filter(key => keys.add(key))); - return Array.from(keys.keys()).filter(key => key[0]).filter(key => key[0] === "#" || key.indexOf("lastModified") !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith("_")) || noviceFields.includes(key) || !Doc.UserDoc().noviceMode).sort(); + return Array.from(keys.keys()).filter(key => key[0]).filter(key => key[0] === "#" || key.indexOf("lastModified") !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith("_")) || noviceFields.includes(key) || !Doc.noviceMode).sort(); } @@ -167,23 +167,25 @@ export class FilterBox extends ViewBoxBaseComponent() { removeFilterDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).map(doc => this.removeFilter(StrCast(doc.title))).length ? true : false; public removeFilter = (filterName: string) => { const targetDoc = FilterBox.targetDoc; - const filterDoc = targetDoc.currentFilter as Doc; - const attributes = DocListCast(filterDoc.data); - const found = attributes.findIndex(doc => doc.title === filterName); - if (found !== -1) { - (filterDoc.data as List).splice(found, 1); - const docFilter = Cast(targetDoc._docFilters, listSpec("string")); - if (docFilter) { - let index: number; - while ((index = docFilter.findIndex(item => item.split(":")[0] === filterName)) !== -1) { - docFilter.splice(index, 1); + if (targetDoc) { + const filterDoc = targetDoc.currentFilter as Doc; + const attributes = DocListCast(filterDoc.data); + const found = attributes.findIndex(doc => doc.title === filterName); + if (found !== -1) { + (filterDoc.data as List).splice(found, 1); + const docFilter = Cast(targetDoc._docFilters, listSpec("string")); + if (docFilter) { + let index: number; + while ((index = docFilter.findIndex(item => item.split(":")[0] === filterName)) !== -1) { + docFilter.splice(index, 1); + } } - } - const docRangeFilters = Cast(targetDoc._docRangeFilters, listSpec("string")); - if (docRangeFilters) { - let index: number; - while ((index = docRangeFilters.findIndex(item => item.split(":")[0] === filterName)) !== -1) { - docRangeFilters.splice(index, 3); + const docRangeFilters = Cast(targetDoc._docRangeFilters, listSpec("string")); + if (docRangeFilters) { + let index: number; + while ((index = docRangeFilters.findIndex(item => item.split(":")[0] === filterName)) !== -1) { + docRangeFilters.splice(index, 3); + } } } } @@ -194,6 +196,7 @@ export class FilterBox extends ViewBoxBaseComponent() { */ facetClick = (facetHeader: string) => { const { targetDoc, targetDocChildren } = FilterBox; + if (!targetDoc) return; const found = this.activeAttributes.findIndex(doc => doc.title === facetHeader); if (found !== -1) { this.removeFilter(facetHeader); @@ -267,7 +270,7 @@ export class FilterBox extends ViewBoxBaseComponent() { */ @action changeBool = (e: any) => { - (FilterBox.targetDoc.currentFilter as Doc).filterBoolean = e.currentTarget.value; + FilterBox.targetDoc && (DocCast(FilterBox.targetDoc.currentFilter).filterBoolean = e.currentTarget.value); } /** @@ -322,7 +325,7 @@ export class FilterBox extends ViewBoxBaseComponent() { * Changes the title of the filterDoc */ onTitleValueChange = (val: string) => { - this.props.Document.title = val || `FilterDoc for ${FilterBox.targetDoc.title}`; + this.props.Document.title = val || `FilterDoc for ${FilterBox.targetDoc?.title}`; return true; } @@ -373,7 +376,7 @@ export class FilterBox extends ViewBoxBaseComponent() {
- diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 8c27b3508..60eb48114 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -179,7 +179,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent Utils.CopyText(this.choosePath(field.url)), icon: "expand-arrows-alt" }); - if (!Doc.UserDoc().noviceMode) { + if (!Doc.noviceMode) { funcs.push({ description: "Export to Google Photos", event: () => GooglePhotos.Transactions.UploadImages([this.props.Document]), icon: "caret-square-right" }); const existingAnalyze = ContextMenu.Instance?.findByDescription("Analyzers..."); @@ -357,7 +357,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent; } marqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && NumCast(this.rootDoc._viewScale,1) <= NumCast(this.rootDoc.viewScaleMin,1) && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && NumCast(this.rootDoc._viewScale,1) <= NumCast(this.rootDoc.viewScaleMin,1) && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index b0b050cea..b58a9affb 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -52,7 +52,7 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro get paramsDoc() { return Doc.AreProtosEqual(this.layoutDoc, this.dataDoc) ? this.dataDoc : this.layoutDoc; } specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; - !Doc.UserDoc().noviceMode && funcs.push({ + !Doc.noviceMode && funcs.push({ description: "Clear Script Params", event: () => { const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []); params?.map(p => this.paramsDoc[p] = undefined); diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 5f4c17ee6..0b7264d79 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -471,7 +471,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { - if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; @@ -570,7 +570,7 @@ export class MapBox extends ViewBoxAnnotatableComponent; + // pointerEvents={CurrentUserUtils.ActiveTool !== InkTool.None || this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none"} />; return
{/*console.log(apiKey)*/} {/* Loading
:
@@ -484,7 +484,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent this.layoutDoc._currentTimecode, () => !this._playing && this.Seek(NumCast(this.layoutDoc._currentTimecode))); this._disposers.youtubeReactionDisposer = reaction( - () => CurrentUserUtils.SelectedTool === InkTool.None && this.props.isSelected(true) && !SnappingManager.GetIsDragging() && !DocumentDecorations.Instance.Interacting, + () => CurrentUserUtils.ActiveTool === InkTool.None && this.props.isSelected(true) && !SnappingManager.GetIsDragging() && !DocumentDecorations.Instance.Interacting, (interactive) => iframe.style.pointerEvents = interactive ? "all" : "none", { fireImmediately: true }); }; if (typeof (YT) === undefined) setTimeout(() => this.loadYouTube(iframe), 100); @@ -707,7 +707,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent { - if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.ActiveTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 967158cbf..d14af49ea 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -536,7 +536,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.layoutDoc.useCors = !this.layoutDoc.useCors, icon: "snowflake" }); + !Doc.noviceMode && funcs.push({ description: (this.layoutDoc.useCors ? "Don't Use" : "Use") + " Cors", event: () => this.layoutDoc.useCors = !this.layoutDoc.useCors, icon: "snowflake" }); funcs.push({ description: (this.layoutDoc.allowScripts ? "Prevent" : "Allow") + " Scripts", event: () => { this.layoutDoc.allowScripts = !this.layoutDoc.allowScripts; @@ -561,7 +561,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { - if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; @@ -678,7 +678,7 @@ export class WebBox extends ViewBoxAnnotatableComponent e.stopPropagation()} style={{ width: !this.layoutDoc.forceReflow ? NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]) || `100%` : "100%", }}> diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index f29dfe489..3af6a3d51 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -1,6 +1,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; +import { StringIterator } from 'lodash'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -70,7 +71,7 @@ export class FontIconBox extends DocComponent() { useAsPrototype = (): void => { this.layoutDoc.onDragStart = ScriptField.MakeFunction('makeDelegate(this.dragFactory, true)'); }; specificContextMenu = (): void => { - if (!Doc.UserDoc().noviceMode) { + if (!Doc.noviceMode) { const cm = ContextMenu.Instance; cm.addItem({ description: "Show Template", event: this.showTemplate, icon: "tag" }); cm.addItem({ description: "Use as Render Template", event: this.dragAsTemplate, icon: "tag" }); @@ -269,7 +270,7 @@ export class FontIconBox extends DocComponent() { // Get items to place into the list const list = this.buttonList.map((value) => { - if (Doc.UserDoc().noviceMode && !noviceList.includes(value)) { + if (Doc.noviceMode && !noviceList.includes(value)) { return; } return
= 1) return Colors.MEDIUM_BLUE; + if (checkResult) { + if (NumCast(selected?.Document.z) >= 1) return Colors.MEDIUM_BLUE; return "transparent"; } selected ? selected.props.CollectionFreeFormDocumentView?.().float() : console.log("[FontIconBox.tsx] toggleOverlay failed"); @@ -710,7 +711,7 @@ ScriptingGlobals.add(function toggleItalic(checkResult?: boolean) { export function checkInksToGroup() { // console.log("getting here to inks group"); - if (CurrentUserUtils.SelectedTool === InkTool.Write) { + if (CurrentUserUtils.ActiveTool === InkTool.Write) { CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => { // TODO: nda - will probably want to go through ffView unprocessed docs and then see if any of the inksToGroup docs are in it and only use those // find all inkDocs in ffView.unprocessedDocs that are within 200 pixels of each other @@ -723,7 +724,7 @@ export function checkInksToGroup() { export function createInkGroup(inksToGroup?: Doc[], isSubGroup?: boolean) { // TODO nda - if document being added to is a inkGrouping then we can just add to that group - if (CurrentUserUtils.SelectedTool === InkTool.Write) { + if (CurrentUserUtils.ActiveTool === InkTool.Write) { CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => { // TODO: nda - will probably want to go through ffView unprocessed docs and then see if any of the inksToGroup docs are in it and only use those const selected = ffView.unprocessedDocs; @@ -785,38 +786,38 @@ export function createInkGroup(inksToGroup?: Doc[], isSubGroup?: boolean) { /** INK - * setActiveInkTool + * setActiveTool * setStrokeWidth * setStrokeColor **/ -ScriptingGlobals.add(function setActiveInkTool(tool: string, checkResult?: boolean) { +ScriptingGlobals.add(function setActiveTool(tool: string, checkResult?: boolean) { InkTranscription.Instance?.createInkGroup(); if (checkResult) { - return ((Doc.UserDoc().activeInkTool === tool && !GestureOverlay.Instance?.InkShape) || GestureOverlay.Instance?.InkShape === tool) ? + return ((CurrentUserUtils.ActiveTool === tool && !GestureOverlay.Instance?.InkShape) || GestureOverlay.Instance?.InkShape === tool) ? Colors.MEDIUM_BLUE : "transparent"; } if (["circle", "square", "line"].includes(tool)) { if (GestureOverlay.Instance.InkShape === tool) { - Doc.UserDoc().activeInkTool = InkTool.None; + CurrentUserUtils.ActiveTool = InkTool.None; GestureOverlay.Instance.InkShape = InkTool.None; } else { - Doc.UserDoc().activeInkTool = InkTool.Pen; + CurrentUserUtils.ActiveTool = InkTool.Pen; GestureOverlay.Instance.InkShape = tool; } } else if (tool) { // pen or eraser - if (Doc.UserDoc().activeInkTool === tool && !GestureOverlay.Instance.InkShape) { - Doc.UserDoc().activeInkTool = InkTool.None; - } else if (tool == "write") { + if (CurrentUserUtils.ActiveTool === tool && !GestureOverlay.Instance.InkShape) { + CurrentUserUtils.ActiveTool = InkTool.None; + } else if (tool == InkTool.Write) { // console.log("write mode selected - create groupDoc here!", tool) - Doc.UserDoc().activeInkTool = tool; + CurrentUserUtils.ActiveTool = tool; GestureOverlay.Instance.InkShape = ""; } else { - Doc.UserDoc().activeInkTool = tool; + CurrentUserUtils.ActiveTool = tool as any; GestureOverlay.Instance.InkShape = ""; } } else { - Doc.UserDoc().activeInkTool = InkTool.None; + CurrentUserUtils.ActiveTool = InkTool.None; } }); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 16a523b40..90199618b 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -648,7 +648,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const highlighting: ContextMenuProps[] = []; const noviceHighlighting = ["Audio Tags", "My Text", "Text from Others", "Bold Text"]; const expertHighlighting = [...noviceHighlighting, "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"]; - (Doc.UserDoc().noviceMode ? noviceHighlighting : expertHighlighting).forEach(option => + (Doc.noviceMode ? noviceHighlighting : expertHighlighting).forEach(option => highlighting.push({ description: (FormattedTextBox._globalHighlights.indexOf(option) === -1 ? "Highlight " : "Unhighlight ") + option, event: () => { e.stopPropagation(); @@ -663,11 +663,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp })); const uicontrols: ContextMenuProps[] = []; - !Doc.UserDoc().noviceMode && uicontrols.push({ description: `${FormattedTextBox._canAnnotate ? "Don't" : ""} Show Menu on Selections`, event: () => FormattedTextBox._canAnnotate = !FormattedTextBox._canAnnotate, icon: "expand-arrows-alt" }); + !Doc.noviceMode && uicontrols.push({ description: `${FormattedTextBox._canAnnotate ? "Don't" : ""} Show Menu on Selections`, event: () => FormattedTextBox._canAnnotate = !FormattedTextBox._canAnnotate, icon: "expand-arrows-alt" }); uicontrols.push({ description: !this.Document._noSidebar ? "Hide Sidebar Handle" : "Show Sidebar Handle", event: () => this.layoutDoc._noSidebar = !this.layoutDoc._noSidebar, icon: "expand-arrows-alt" }); uicontrols.push({ description: `${this.layoutDoc._showAudio ? "Hide" : "Show"} Dictation Icon`, event: () => this.layoutDoc._showAudio = !this.layoutDoc._showAudio, icon: "expand-arrows-alt" }); uicontrols.push({ description: "Show Highlights...", noexpand: true, subitems: highlighting, icon: "hand-point-right" }); - !Doc.UserDoc().noviceMode && uicontrols.push({ + !Doc.noviceMode && uicontrols.push({ description: "Broadcast Message", event: () => DocServer.GetRefField("rtfProto").then(proto => proto instanceof Doc && (proto.BROADCAST_MESSAGE = Cast(this.rootDoc[this.fieldKey], RichTextField)?.Text)), icon: "expand-arrows-alt" }); @@ -677,7 +677,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const appearanceItems = appearance && "subitems" in appearance ? appearance.subitems : []; appearanceItems.push({ description: "Change Perspective...", noexpand: true, subitems: changeItems, icon: "external-link-alt" }); // this.rootDoc.isTemplateDoc && appearanceItems.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.rootDoc), icon: "eye" }); - !Doc.UserDoc().noviceMode && appearanceItems.push({ + !Doc.noviceMode && appearanceItems.push({ description: "Make Default Layout", event: () => { if (!this.layoutDoc.isTemplateDoc) { const title = StrCast(this.rootDoc.title); @@ -1636,7 +1636,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp noSidebar={true} fieldKey={this.layoutDoc.sidebarViewType === "translation" ? `${this.fieldKey}-translation` : `${this.fieldKey}-annotations`} />; }; - return
{renderComponent(StrCast(this.layoutDoc.sidebarViewType))}
; @@ -1647,7 +1647,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const active = this.props.isContentActive(); const scale = (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : ""; - const interactive = (CurrentUserUtils.SelectedTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || !this.layoutDoc._lockedPosition); + const interactive = (CurrentUserUtils.ActiveTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || !this.layoutDoc._lockedPosition); if (!selected && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide); const minimal = this.props.ignoreAutoHeight; const paddingX = NumCast(this.layoutDoc._xMargin, this.props.xPadding || 0); diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 9bc2e5628..98343a261 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -67,7 +67,6 @@ export class RichTextMenu extends AntimodeMenu { runInAction(() => { RichTextMenu.Instance = this; this._canFade = false; - //this.Pinned = BoolCast(Doc.UserDoc()["menuRichText-pinned"]); this.Pinned = true; }); } diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 52b03b0a5..0d2cffc2c 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -134,7 +134,7 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get presElement() { return Cast(Doc.UserDoc().presElement, Doc, null); } constructor(props: any) { super(props); - if (Doc.UserDoc().activePresentation = this.rootDoc) runInAction(() => PresBox.Instance = this); + if (CurrentUserUtils.ActivePresentation = this.rootDoc) runInAction(() => PresBox.Instance = this); if (!this.presElement) { // create exactly one presElmentBox template to use by any and all presentations. Doc.UserDoc().presElement = new PrefetchProxy(Docs.Create.PresElementBoxDocument({ title: "pres element template", type: DocumentType.PRESELEMENT, _fitWidth: true, _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data" @@ -178,16 +178,16 @@ export class PresBox extends ViewBoxBaseComponent() { this.layoutDoc._gridGap = 0; this.layoutDoc._yMargin = 0; this.turnOffEdit(true); - DocListCastAsync((Doc.UserDoc().myTrails as Doc).data).then(pres => - !pres?.includes(this.rootDoc) && Doc.AddDocToList(Doc.UserDoc().myTrails as Doc, "data", this.rootDoc)); + DocListCastAsync(CurrentUserUtils.MyTrails.data).then(pres => + !pres?.includes(this.rootDoc) && Doc.AddDocToList(CurrentUserUtils.MyTrails, "data", this.rootDoc)); this._disposers.selection = reaction(() => SelectionManager.Views(), views => views.some(view => view.props.Document === this.rootDoc) && this.updateCurrentPresentation()); } @action updateCurrentPresentation = (pres?: Doc) => { - if (pres) Doc.UserDoc().activePresentation = pres; - else Doc.UserDoc().activePresentation = this.rootDoc; + if (pres) CurrentUserUtils.ActivePresentation = pres; + else CurrentUserUtils.ActivePresentation = this.rootDoc; document.removeEventListener("keydown", PresBox.keyEventsWrapper, true); document.addEventListener("keydown", PresBox.keyEventsWrapper, true); this._presKeyEventsActive = true; @@ -623,9 +623,9 @@ export class PresBox extends ViewBoxBaseComponent() { */ @action updateMinimize = async () => { - if (CurrentUserUtils.MyOverlayDocs.includes(this.layoutDoc)) { + if (DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.layoutDoc)) { this.layoutDoc.presStatus = PresStatus.Edit; - Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc); + Doc.RemoveDocFromList(CurrentUserUtils.MyOverlayDocs, undefined, this.rootDoc); CollectionDockingView.AddSplit(this.rootDoc, "right"); } else { this.layoutDoc.presStatus = PresStatus.Edit; @@ -635,7 +635,7 @@ export class PresBox extends ViewBoxBaseComponent() { this.rootDoc.y = pt[1] + 10; this.rootDoc._height = 30; this.rootDoc._width = 248; - Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc); + Doc.AddDocToList(CurrentUserUtils.MyOverlayDocs, undefined, this.rootDoc); this.props.removeDocument?.(this.layoutDoc); } } @@ -732,7 +732,7 @@ export class PresBox extends ViewBoxBaseComponent() { removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.rootDoc, this.fieldKey, doc); getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight panelHeight = () => this.props.PanelHeight() - 40; - isContentActive = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && !this.layoutDoc._lockedPosition) && + isContentActive = (outsideReaction?: boolean) => ((CurrentUserUtils.ActiveTool === InkTool.None && !this.layoutDoc._lockedPosition) && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) /** @@ -868,7 +868,7 @@ export class PresBox extends ViewBoxBaseComponent() { } break; case "Escape": - if (CurrentUserUtils.MyOverlayDocs.includes(this.layoutDoc)) { this.updateMinimize(); } + if (DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.layoutDoc)) { this.updateMinimize(); } else if (this.layoutDoc.presStatus === "edit") { this._selectedArray.clear(); this._eleArray.length = this._dragArray.length = 0; } else this.layoutDoc.presStatus = "edit"; if (this._presTimer) clearTimeout(this._presTimer); @@ -2247,7 +2247,7 @@ export class PresBox extends ViewBoxBaseComponent() { const propTitle = CurrentUserUtils.propertiesWidth > 0 ? "Close Presentation Panel" : "Open Presentation Panel"; const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; const isMini: boolean = this.toolbarWidth <= 100; - const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === Doc.UserDoc().activePresentation); + const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === CurrentUserUtils.ActivePresentation); const activeColor = Colors.LIGHT_BLUE; const inactiveColor = Colors.WHITE; return (mode === CollectionViewType.Carousel3D) ? (null) : ( @@ -2305,7 +2305,7 @@ export class PresBox extends ViewBoxBaseComponent() { value={mode}> - {Doc.UserDoc().noviceMode ? (null) : } + {Doc.noviceMode ? (null) : } }
@@ -2508,10 +2508,10 @@ export class PresBox extends ViewBoxBaseComponent() { // needed to ensure that the childDocs are loaded for looking up fields this.childDocs.slice(); const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; - const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === Doc.UserDoc().activePresentation); + const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === CurrentUserUtils.ActivePresentation); const presEnd: boolean = !this.layoutDoc.presLoop && (this.itemIndex === this.childDocs.length - 1); const presStart: boolean = !this.layoutDoc.presLoop && (this.itemIndex === 0); - return CurrentUserUtils.MyOverlayDocs.includes(this.rootDoc) ? + return DocListCast(CurrentUserUtils.MyOverlayDocs?.data).includes(this.rootDoc) ?
e.stopPropagation()}>
{"Loop"}
}>
() {
: -
+
{this.topPanel} {this.toolbar} {this.newDocumentToolbarDropdown} diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 50df00612..1a2f4b93f 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -309,7 +309,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { @computed get recordingIsInOverlay() { let isInOverlay = false - DocListCast((Doc.UserDoc().myOverlayDocs as Doc).data).forEach((doc) => { + DocListCast(CurrentUserUtils.MyOverlayDocs.data).forEach((doc) => { if (doc.slides === this.rootDoc) { isInOverlay = true return @@ -319,9 +319,9 @@ export class PresElementBox extends ViewBoxBaseComponent() { } removeAllRecordingInOverlay = () => { - DocListCast((Doc.UserDoc().myOverlayDocs as Doc).data).forEach((doc) => { + DocListCast(CurrentUserUtils.MyOverlayDocs.data).forEach((doc) => { if (doc.slides === this.rootDoc) { - Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc); + Doc.RemoveDocFromList(CurrentUserUtils.MyOverlayDocs, undefined, doc); } }) } @@ -339,7 +339,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { this.removeAllRecordingInOverlay() if (activeItem.recording) { // if we already have an existing recording - Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, Cast(activeItem.recording, Doc, null)); + Doc.AddDocToList(CurrentUserUtils.MyOverlayDocs, undefined, Cast(activeItem.recording, Doc, null)); } } @@ -348,15 +348,15 @@ export class PresElementBox extends ViewBoxBaseComponent() { @action startRecording = (activeItem: Doc) => { // Remove every recording that already exists in overlay view - DocListCast((Doc.UserDoc().myOverlayDocs as Doc).data).forEach((doc) => { + DocListCast(CurrentUserUtils.MyOverlayDocs.data).forEach((doc) => { if (doc.slides !== null) { - Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc); + Doc.RemoveDocFromList(CurrentUserUtils.MyOverlayDocs, undefined, doc); } }) if (activeItem.recording) { // if we already have an existing recording - Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, Cast(activeItem.recording, Doc, null)); + Doc.AddDocToList(CurrentUserUtils.MyOverlayDocs, undefined, Cast(activeItem.recording, Doc, null)); } else { // if we dont have any recording @@ -376,7 +376,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { // make recording box appear in the bottom right corner of the screen recording.x = window.innerWidth - recording[WidthSym]() - 20; recording.y = window.innerHeight - recording[HeightSym]() - 20; - Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, recording); + Doc.AddDocToList(CurrentUserUtils.MyOverlayDocs, undefined, recording); } } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 0ded1bb3c..2869d4f2d 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -340,7 +340,7 @@ export class PDFViewer extends React.Component { if ((e.button !== 0 || e.altKey) && this.props.isContentActive(true)) { this._setPreviewCursor?.(e.clientX, e.clientY, true, false); } - if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool)) { this.props.select(false); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index 0db3950a2..1de0c0b10 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -27,12 +27,12 @@ import "./TopBar.scss"; export class TopBar extends React.Component { navigateToHome = () => { CurrentUserUtils.CaptureDashboardThumbnail()?.then(() => { - Doc.UserDoc().activePage = "home"; + CurrentUserUtils.ActivePage = "home"; CurrentUserUtils.closeActiveDashboard(); // bcz: if we do this, we need some other way to keep track, for user convenience, of the last dashboard in use }); } render() { - const activeDashboard = Cast(Doc.UserDoc().activeDashboard, Doc, null) + const activeDashboard = CurrentUserUtils.ActiveDashboard; return ( //TODO:glr Add support for light / dark mode
@@ -44,11 +44,11 @@ export class TopBar extends React.Component { }}>{Doc.CurrentUserEmail}
: (null)}
-
SelectionManager.SelectView(DocumentManager.Instance.getDocumentView(activeDashboard)!, false)}> +
activeDashboard && SelectionManager.SelectView(DocumentManager.Instance.getDocumentView(activeDashboard)!, false)}> {activeDashboard ? StrCast(activeDashboard.title) : "Dash"}
{ - const dashView = DocumentManager.Instance.getDocumentView(activeDashboard); + const dashView = activeDashboard && DocumentManager.Instance.getDocumentView(activeDashboard); ContextMenu.Instance.addItem({ description: "Open Dashboard View", event: this.navigateToHome, icon: "edit" }); ContextMenu.Instance.addItem({ description: "Snapshot Dashboard", event: async () => { const batch = UndoManager.StartBatch("snapshot"); @@ -69,7 +69,7 @@ export class TopBar extends React.Component {
{SharingManager.Instance.open(undefined, activeDashboard)}}> {/* TODO: if this is my dashboard, display share if this is a shared dashboard, display "view original or view annotated" */} - { Doc.GetProto(CurrentUserUtils.ActiveDashboard)?.author === Doc.CurrentUserEmail ? "Share": "view original" } + { CurrentUserUtils.ActiveDashboard && (Doc.GetProto(CurrentUserUtils.ActiveDashboard)?.author === Doc.CurrentUserEmail ? "Share": "view original") }
window.open( "https://brown-dash.github.io/Dash-Documentation/", "_blank")}> diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx index e0d328c89..6c0c9b301 100644 --- a/src/client/views/webcam/DashWebRTCVideo.tsx +++ b/src/client/views/webcam/DashWebRTCVideo.tsx @@ -71,7 +71,7 @@ export class DashWebRTCVideo extends React.Component; const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting; - const classname = "webBox-cont" + (this.props.isSelected() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? "-interactive" : ""); + const classname = "webBox-cont" + (this.props.isSelected() && CurrentUserUtils.ActiveTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? "-interactive" : ""); return ( <> diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 94be286f5..74213652b 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -21,7 +21,7 @@ import { FieldId, RefField } from "./RefField"; import { RichTextField } from "./RichTextField"; import { listSpec } from "./Schema"; import { ComputedField, ScriptField } from "./ScriptField"; -import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types"; +import { BoolCast, Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types"; import { AudioField, ImageField, MapField, PdfField, VideoField, WebField } from "./URLField"; import { deleteProperty, GetEffectiveAcl, getField, getter, inheritParentAcls, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions, updateFunction } from "./util"; import JSZip = require("jszip"); @@ -233,6 +233,10 @@ export class Doc extends RefField { } private [CachedUpdates]: { [key: string]: () => void | Promise } = {}; + public static get noviceMode() { return BoolCast(Doc.UserDoc().noviceMode); } + public static set noviceMode(val) { Doc.UserDoc().noviceMode = val; } + public static get defaultAclPrivate() { return Doc.UserDoc().defaultAclPrivate; } + public static set defaultAclPrivate(val) { Doc.UserDoc().defaultAclPrivate = val; } public static CurrentUserEmail: string = ""; public static get CurrentUserEmailNormalized() { return normalizeEmail(Doc.CurrentUserEmail); } public async [HandleUpdate](diff: any) { @@ -805,7 +809,7 @@ export namespace Doc { Doc.AddDocToList(Doc.GetProto(copy)[DataSym], "aliases", copy); } copy.context = undefined; - Doc.UserDoc().defaultAclPrivate && (copy["acl-Public"] = "Not Shared"); + Doc.defaultAclPrivate && (copy["acl-Public"] = "Not Shared"); if (retitle) { copy.title = incrementTitleCopy(StrCast(copy.title)); } @@ -861,7 +865,7 @@ export namespace Doc { const applied = ApplyTemplateTo(templateDoc, target, targetKey, templateDoc.title + "(..." + _applyCount++ + ")"); target.layoutKey = targetKey; applied && (Doc.GetProto(applied).type = templateDoc.type); - Doc.UserDoc().defaultAclPrivate && (applied["acl-Public"] = "Not Shared"); + Doc.defaultAclPrivate && (applied["acl-Public"] = "Not Shared"); return applied; } return undefined; @@ -1234,19 +1238,19 @@ export namespace Doc { export function isDocPinned(doc: Doc) { //add this new doc to props.Document - const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc; + const curPres = CurrentUserUtils.ActivePresentation; return !curPres ? false : DocListCast(curPres.data).findIndex((val) => Doc.AreProtosEqual(val, doc)) !== -1; } export function copyDragFactory(dragFactory: Doc) { const ndoc = dragFactory.isTemplateDoc ? Doc.ApplyTemplate(dragFactory) : Doc.MakeCopy(dragFactory, true); - ndoc && Doc.AddDocToList(Cast(Doc.UserDoc().myFileOrphans, Doc, null), "data", Doc.GetProto(ndoc)); + ndoc && Doc.AddDocToList(CurrentUserUtils.MyFileOrphans, "data", Doc.GetProto(ndoc)); if (ndoc && dragFactory["dragFactory-count"] !== undefined) { dragFactory["dragFactory-count"] = NumCast(dragFactory["dragFactory-count"]) + 1; Doc.SetInPlace(ndoc, "title", ndoc.title + " " + NumCast(dragFactory["dragFactory-count"]).toString(), true); } - if (ndoc) inheritParentAcls(CurrentUserUtils.ActiveDashboard, ndoc); + if (ndoc && CurrentUserUtils.ActiveDashboard) inheritParentAcls(CurrentUserUtils.ActiveDashboard, ndoc); return ndoc; } @@ -1448,7 +1452,7 @@ ScriptingGlobals.add(function DOC(id: string) { console.log("Can't parse a docum ScriptingGlobals.add(function assignDoc(doc: Doc, field: string, id: string) { return Doc.assignDocToField(doc, field, id); }); ScriptingGlobals.add(function docCast(doc: FieldResult): any { return DocCastAsync(doc); }); ScriptingGlobals.add(function activePresentationItem() { - const curPres = Doc.UserDoc().activePresentation as Doc; + const curPres = CurrentUserUtils.ActivePresentation; return curPres && DocListCast(curPres[Doc.LayoutFieldKey(curPres)])[NumCast(curPres._itemIndex)]; }); ScriptingGlobals.add(function selectedDocs(container: Doc, excludeCollections: boolean, prevValue: any) { diff --git a/src/fields/util.ts b/src/fields/util.ts index 37b9be31b..8fb35981b 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -145,7 +145,7 @@ export function inheritParentAcls(parent: Doc, child: Doc) { const dataDoc = parent[DataSym]; for (const key of Object.keys(dataDoc)) { // if the default acl mode is private, then don't inherit the acl-Public permission, but set it to private. - const permission = (key === "acl-Public" && Doc.UserDoc().defaultAclPrivate) ? AclPrivate : dataDoc[key]; + const permission = (key === "acl-Public" && Doc.defaultAclPrivate) ? AclPrivate : dataDoc[key]; key.startsWith("acl") && distributeAcls(key, permission, child); } } diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index c5c6fb688..fe8100997 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -51,7 +51,7 @@ library.add(...[faTasks, faReply, faQuoteLeft, faHandPointLeft, faFolderOpen, fa @observer export class MobileInterface extends React.Component { static Instance: MobileInterface; - private _library: Promise; + private _library: Doc; private _mainDoc: any = CurrentUserUtils.setupActiveMobileMenu(Doc.UserDoc()); @observable private _sidebarActive: boolean = false; //to toggle sidebar display @observable private _imageUploadActive: boolean = false; //to toggle image upload @@ -68,7 +68,7 @@ export class MobileInterface extends React.Component { constructor(props: Readonly<{}>) { super(props); - this._library = CurrentUserUtils.setupDashboards(Doc.UserDoc()); // to access documents in Dash Web + this._library = CurrentUserUtils.setupDashboards(Doc.UserDoc(), "myDashboards"); // to access documents in Dash Web MobileInterface.Instance = this; } @@ -76,7 +76,7 @@ export class MobileInterface extends React.Component { componentDidMount = () => { // if the home menu is in list view -> adjust the menu toggle appropriately this._menuListView = this._homeDoc._viewType === "stacking" ? true : false; - CurrentUserUtils.SelectedTool = InkTool.None; // ink should intially be set to none + CurrentUserUtils.ActiveTool = InkTool.None; // ink should intially be set to none Doc.UserDoc().activeMobile = this._homeDoc; // active mobile set to home AudioBox.Enabled = true; @@ -125,7 +125,7 @@ export class MobileInterface extends React.Component { * Method called when 'Library' button is pressed on the home screen */ switchToLibrary = async () => { - this._library.then(library => this.switchCurrentView(library)); + this.switchCurrentView(this._library); runInAction(() => this._homeMenu = false); this.toggleSidebar(); } @@ -140,7 +140,7 @@ export class MobileInterface extends React.Component { // Case 1: Parent document is 'dashboards' if (doc === Cast(this._library, Doc) as Doc) { this.dashboards = null; - this._library.then(library => this.switchCurrentView(library)); + this.switchCurrentView(this._library); // Case 2: Parent document is the 'home' menu (root node) } else if (doc === Cast(this._homeDoc, Doc) as Doc) { this._homeMenu = true; @@ -179,7 +179,7 @@ export class MobileInterface extends React.Component { @action returnMain = () => { this._parents = [this._homeDoc]; - this._library.then(library => this.switchCurrentView(library)); + this.switchCurrentView(this._library); this._homeMenu = false; this.dashboards = null; } @@ -419,10 +419,10 @@ export class MobileInterface extends React.Component { button.style.color = this._ink ? "black" : "white"; if (!this._ink) { - CurrentUserUtils.SelectedTool = InkTool.Pen; + CurrentUserUtils.ActiveTool = InkTool.Pen; this._ink = true; } else { - CurrentUserUtils.SelectedTool = InkTool.None; + CurrentUserUtils.ActiveTool = InkTool.None; this._ink = false; } } @@ -514,7 +514,7 @@ export class MobileInterface extends React.Component { return
TabDocView.PinDoc(this._activeDoc, { unpin: isPinned })}> + onClick={e => TabDocView.PinDoc(this._activeDoc)}>
; } else return (null); @@ -573,7 +573,7 @@ export class MobileInterface extends React.Component { // For setting up the presentation document for the home menu @action setupDefaultPresentation = () => { - const presentation = Cast(Doc.UserDoc().activePresentation, Doc) as Doc; + const presentation = CurrentUserUtils.ActivePresentation; if (presentation) { this.switchCurrentView(presentation); -- cgit v1.2.3-70-g09d2 From 3e22a44461095d95062e3b809b525a0a87342ac3 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 20 Jun 2022 22:18:42 -0400 Subject: more cleanup to get rid of unecessary references to Doc.UserDoc(). --- src/client/documents/Documents.ts | 4 +- src/client/util/CurrentUserUtils.ts | 48 +++++++++++++--------- src/client/util/DragManager.ts | 4 +- src/client/util/History.ts | 2 +- src/client/util/SettingsManager.tsx | 19 ++++----- src/client/util/SnappingManager.ts | 4 ++ src/client/views/DashboardView.tsx | 2 +- src/client/views/DocumentDecorations.tsx | 4 +- src/client/views/MainView.tsx | 21 ++++------ .../views/collections/CollectionDockingView.tsx | 4 +- src/client/views/collections/CollectionMenu.tsx | 4 +- src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- .../collections/collectionFreeForm/MarqueeView.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/button/FontIconBox.tsx | 30 +++++++------- .../nodes/button/colorDropdown/ColorDropdown.tsx | 3 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 +- src/client/views/nodes/trails/PresBox.tsx | 11 +---- src/client/views/topbar/TopBar.tsx | 2 +- src/mobile/MobileInterface.tsx | 2 +- 22 files changed, 93 insertions(+), 89 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index e36103938..73b756a8d 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -662,7 +662,7 @@ export namespace Docs { const { omit: dataProps, extract: viewProps } = OmitKeys(options, viewKeys, "^_"); dataProps["acl-Override"] = "None"; - dataProps["acl-Public"] = options["acl-Public"] ? options["acl-Public"] : Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; + dataProps["acl-Public"] = options["acl-Public"] ? options["acl-Public"] : Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; dataProps.system = viewProps.system; dataProps.isPrototype = true; @@ -679,7 +679,7 @@ export namespace Docs { const dataDoc = Doc.assign(Doc.MakeDelegate(proto, protoId), dataProps, undefined, true); const viewFirstProps: { [id: string]: any } = {}; - viewFirstProps["acl-Public"] = options["_acl-Public"] ? options["_acl-Public"] : Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; + viewFirstProps["acl-Public"] = options["_acl-Public"] ? options["_acl-Public"] : Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; viewFirstProps["acl-Override"] = "None"; viewFirstProps.author = Doc.CurrentUserEmail; const viewDoc = Doc.assign(Doc.MakeDelegate(dataDoc, delegId), viewFirstProps, true, true); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 1d5a9fa09..9b5fc5b98 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -181,7 +181,12 @@ export class CurrentUserUtils { /// Initializes collection of templates for notes and click functions static setupDocTemplates(doc: Doc, field="myTemplates") { + const preEleOpts:DocumentOptions = { + title: "pres element template", type: DocumentType.PRESELEMENT, _fitWidth: true, _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data" + }; + this.AssignOpts(DocCast(doc.presElement), preEleOpts) ?? (doc.presElement= Docs.Create.PresElementBoxDocument(preEleOpts)); const templates = [ + DocCast(doc.presElement), CurrentUserUtils.setupNoteTemplates(doc), CurrentUserUtils.setupClickEditorTemplates(doc) ]; @@ -323,8 +328,7 @@ export class CurrentUserUtils { { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs: { hidden: 'IsNoviceMode()'}}, { toolTip: "Tap or drag to create a mobile view", title: "Phone", icon: "mobile", dragFactory: doc.activeMobileMenu as Doc, scripts: {onClick: 'openOnRight(Doc.UserDoc().activeMobileMenu)', onDragStart: 'this.dragFactory'}, funcs: {hidden: 'IsNoviceMode()'} }, { toolTip: "Toggle a Calculator REPL", title: "repl", icon: "calculator", scripts: {onClick: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' } }, - // { toolTip: "Tap or drag to create a presentation", title: "Trails", icon: "pres-trail", dragFactory: doc.emptyPresentation as Doc,scripts: {onClick: 'openOnRight(Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory))', onDragStart: `Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory)`}, funcs: {hidden: 'IsNoviceMode()'} }, - ]; + ]; } /// Initalizes the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools @@ -533,7 +537,7 @@ export class CurrentUserUtils { static setupDashboards(doc: Doc, field:string) { var myDashboards = DocCast(doc[field]); - const newDashboard = `createNewDashboard(Doc.UserDoc())`; + const newDashboard = `createNewDashboard()`; const reqdBtnOpts:DocumentOptions = { _forceActive: true, _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, title: "new dashboard", btnType: ButtonType.ClickButton, toolTip: "Create new dashboard", buttonText: "New trail", icon: "plus", system: true }; const reqdBtnScript = {onClick: newDashboard,} @@ -830,6 +834,11 @@ export class CurrentUserUtils { const reqdOpts = { title: "overlay documents", backgroundColor: "#aca3a6", system: true }; return this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.FreeformDocument([], reqdOpts)); } + + static setupPublished(doc:Doc, field = "myPublishedDocs") { + const reqdOpts = { title: "published docs", backgroundColor: "#aca3a6", system: true }; + return this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([], reqdOpts)); + } /// The database of all links on all documents static async setupLinkDocs(doc: Doc, linkDatabaseId: string) { @@ -958,7 +967,6 @@ export class CurrentUserUtils { Doc.noviceMode ?? (Doc.noviceMode = true); doc._raiseWhenDragged ?? (doc._raiseWhenDragged = true); doc._showLabel ?? (doc._showLabel = true); - doc._showMenuLabel ?? (doc._showMenuLabel = true); doc.textAlign ?? (doc.textAlign = "left"); doc.activeInkColor ?? (doc.activeInkColor = "rgb(0, 0, 0)");; doc.activeInkWidth ?? (doc.activeInkWidth = 1); @@ -975,17 +983,17 @@ export class CurrentUserUtils { doc.savedFilters ?? (doc.savedFilters = new List()); doc.filterDocCount = 0; doc.freezeChildren = "remove|add"; - doc.myPublishedDocs ?? (doc.myPublishedDocs = new List()); doc.myHeaderBar ?? (doc.myHeaderBar = Docs.Create.MulticolumnDocument([], { title: "header bar", system: true })); // drop down panel at top of dashboard for stashing documents await this.setupLinkDocs(doc, linkDatabaseId); await this.setupSharedDocs(doc, sharingDocumentId); // sets up the right sidebar collection for mobile upload documents and sharing this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon - this.setupDocTemplates(doc); // sets up the template menu of templates this.setupActiveMobileMenu(doc); // sets up the current mobile menu for Dash Mobile this.setupOverlays(doc); // sets up the overlay panel where documents and other widgets can be added to float over the rest of the dashboard + this.setupPublished(doc); // sets up the list doc of all docs that have been published (meaning that they can be auto-linked by typing their title into another text box) this.setupContextMenuButtons(doc); // set up the row of buttons at the top of the dashboard that change depending on what is selected this.setupDockedButtons(doc); // the bottom bar of font icons this.setupLeftSidebarMenu(doc); // the left-side column of buttons that open their contents in a flyout panel on the left + this.setupDocTemplates(doc); // sets up the template menu of templates doc.globalScriptDatabase ?? ( doc.globalScriptDatabase = Docs.Prototypes.MainScriptDocument()); setTimeout(() => DocServer.UPDATE_SERVER_CACHE(), 2500); @@ -1037,7 +1045,8 @@ export class CurrentUserUtils { public static _urlState: HistoryUtil.DocUrl; - public static openDashboard = (userDoc: Doc, doc: Doc, fromHistory = false) => { + public static openDashboard = (doc: Doc, fromHistory = false) => { + const userDoc = Doc.UserDoc(); CurrentUserUtils.MainDocId = doc[Id]; if (!DocListCast(CurrentUserUtils.MyDashboards.data).includes(doc)) { Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", doc); @@ -1045,7 +1054,7 @@ export class CurrentUserUtils { if (doc) { // this has the side-effect of setting the main container since we're assigning the active/guest dashboard !("presentationView" in doc) && (doc.presentationView = new List([Docs.Create.TreeDocument([], { title: "Presentation" })])); - userDoc ? (userDoc.activeDashboard = doc) : (CurrentUserUtils.GuestDashboard = doc); + userDoc ? (CurrentUserUtils.ActiveDashboard = doc) : (CurrentUserUtils.GuestDashboard = doc); } const state = CurrentUserUtils._urlState; if (state.sharing === true && !userDoc) { @@ -1138,11 +1147,11 @@ export class CurrentUserUtils { } - public static async snapshotDashboard(userDoc: Doc) { + public static async snapshotDashboard() { if (CurrentUserUtils.ActiveDashboard) { const copy = await CollectionDockingView.Copy(CurrentUserUtils.ActiveDashboard); Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", copy); - CurrentUserUtils.openDashboard(userDoc, copy); + CurrentUserUtils.openDashboard(copy); } } @@ -1150,9 +1159,9 @@ export class CurrentUserUtils { CurrentUserUtils.ActiveDashboard = undefined; } - public static createNewDashboard = async (userDoc: Doc, id?: string) => { - const presentation = Doc.MakeCopy(userDoc.emptyPresentation as Doc, true); - const dashboards = await Cast(userDoc.myDashboards, Doc) as Doc; + public static createNewDashboard = (id?: string) => { + const presentation = Doc.MakeCopy(Doc.UserDoc().emptyPresentation as Doc, true); + const dashboards = CurrentUserUtils.MyDashboards; const dashboardCount = DocListCast(dashboards.data).length + 1; const freeformOptions: DocumentOptions = { x: 0, @@ -1172,10 +1181,10 @@ export class CurrentUserUtils { dashboardDoc.data = new List(dashboardTabs); dashboardDoc["pane-count"] = 1; - userDoc.activePresentation = presentation; + CurrentUserUtils.ActivePresentation = presentation; Doc.AddDocToList(dashboards, "data", dashboardDoc); - // CurrentUserUtils.openDashboard(userDoc, dashboardDoc); + // CurrentUserUtils.openDashboard(dashboardDoc); } public static GetNewTextDoc(title: string, x: number, y: number, width?: number, height?: number, noMargins?: boolean, annotationOn?: Doc, maxHeight?: number, backgroundColor?: string) { @@ -1209,6 +1218,7 @@ export class CurrentUserUtils { public static get MyContextMenuBtns() { return DocCast(Doc.UserDoc().myContextMenuBtns); } public static get MyRecentlyClosed() { return DocCast(Doc.UserDoc().myRecentlyClosed); } public static get MyOverlayDocs() { return DocCast(Doc.UserDoc().myOverlayDocs); } + public static get MyPublishedDocs() { return DocCast(Doc.UserDoc().myPublishedDocs); } public static get ActiveDashboard() { return DocCast(Doc.UserDoc().activeDashboard); } public static set ActiveDashboard(val:Doc|undefined) { Doc.UserDoc().activeDashboard = val; } public static get ActivePresentation() { return DocCast(Doc.UserDoc().activePresentation); } @@ -1230,8 +1240,8 @@ ScriptingGlobals.add(function openDragFactory(dragFactory: Doc) { ScriptingGlobals.add(function MySharedDocs() { return CurrentUserUtils.MySharedDocs; }, "document containing all shared Docs"); ScriptingGlobals.add(function IsNoviceMode() { return Doc.noviceMode; }, "is Dash in novice mode"); ScriptingGlobals.add(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }, "switches between comic and normal document rendering"); -ScriptingGlobals.add(function snapshotDashboard() { CurrentUserUtils.snapshotDashboard(Doc.UserDoc()); }, "creates a snapshot copy of a dashboard"); -ScriptingGlobals.add(function createNewDashboard() { return CurrentUserUtils.createNewDashboard(Doc.UserDoc()); }, "creates a new dashboard when called"); +ScriptingGlobals.add(function snapshotDashboard() { CurrentUserUtils.snapshotDashboard(); }, "creates a snapshot copy of a dashboard"); +ScriptingGlobals.add(function createNewDashboard() { return CurrentUserUtils.createNewDashboard(); }, "creates a new dashboard when called"); ScriptingGlobals.add(function createNewPresentation() { return MainView.Instance.createNewPresentation(); }, "creates a new presentation when called"); ScriptingGlobals.add(function createNewFolder() { return MainView.Instance.createNewFolder(); }, "creates a new folder in myFiles when called"); ScriptingGlobals.add(function links(doc: any) { return new List(LinkManager.Instance.getAllRelatedLinks(doc)); }, "returns all the links to the document or its annotations", "(doc: any)"); @@ -1240,7 +1250,7 @@ ScriptingGlobals.add(function shareDashboard(dashboard: Doc) { SharingManager.In ScriptingGlobals.add(async function removeDashboard(dashboard: Doc) { const dashboards = await DocListCastAsync(CurrentUserUtils.MyDashboards.data); if (dashboards && dashboards.length > 1) { - if (dashboard === CurrentUserUtils.ActiveDashboard) CurrentUserUtils.openDashboard(Doc.UserDoc(), dashboards.find(doc => doc !== dashboard)!); + if (dashboard === CurrentUserUtils.ActiveDashboard) CurrentUserUtils.openDashboard(dashboards.find(doc => doc !== dashboard)!); Doc.RemoveDocFromList(CurrentUserUtils.MyDashboards, "data", dashboard); } }, @@ -1248,7 +1258,7 @@ ScriptingGlobals.add(async function removeDashboard(dashboard: Doc) { ScriptingGlobals.add(function addToDashboards(dashboard: Doc) { const dashboardAlias = Doc.MakeAlias(dashboard); Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", dashboardAlias); - CurrentUserUtils.openDashboard(Doc.UserDoc(), dashboardAlias); + CurrentUserUtils.openDashboard(dashboardAlias); }, "adds Dashboard to set of Dashboards"); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index dbfba8992..2b62945af 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -6,7 +6,7 @@ import { PrefetchProxy } from "../../fields/Proxy"; import { listSpec } from "../../fields/Schema"; import { SchemaHeaderField } from "../../fields/SchemaHeaderField"; import { ScriptField } from "../../fields/ScriptField"; -import { Cast, NumCast, ScriptCast, StrCast } from "../../fields/Types"; +import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../fields/Types"; import { emptyFunction, Utils } from "../../Utils"; import { Docs, DocUtils } from "../documents/Documents"; import * as globalCssVariables from "../views/global/globalCssVariables.scss"; @@ -72,6 +72,8 @@ export namespace DragManager { export let StartWindowDrag: Opt<((e: { pageX: number, pageY: number }, dragDocs: Doc[], finishDrag?: (aborted: boolean) => void) => void)>; export let CompleteWindowDrag: Opt<(aborted: boolean) => void>; + export function GetRaiseWhenDragged() { return BoolCast(Doc.UserDoc()._raiseWhenDragged); } + export function SetRaiseWhenDragged(val:boolean) { Doc.UserDoc()._raiseWhenDragged = val } export function Root() { const root = document.getElementById("root"); if (!root) { diff --git a/src/client/util/History.ts b/src/client/util/History.ts index 632348306..7dcff9c56 100644 --- a/src/client/util/History.ts +++ b/src/client/util/History.ts @@ -197,7 +197,7 @@ export namespace HistoryUtil { await Promise.all(Object.keys(init).map(id => initDoc(id, init[id]))); } if (field instanceof Doc) { - CurrentUserUtils.openDashboard(Doc.UserDoc(), field, true); + CurrentUserUtils.openDashboard(field, true); } } diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index 382274462..22e33ab1e 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -10,7 +10,9 @@ import { GoogleAuthenticationManager } from "../apis/GoogleAuthenticationManager import { DocServer } from "../DocServer"; import { Networking } from "../Network"; import { MainViewModal } from "../views/MainViewModal"; +import { FontIconBox } from "../views/nodes/button/FontIconBox"; import { CurrentUserUtils } from "./CurrentUserUtils"; +import { DragManager } from "./DragManager"; import { GroupManager } from "./GroupManager"; import "./SettingsManager.scss"; import { undoBatch } from "./UndoManager"; @@ -155,19 +157,14 @@ export class SettingsManager extends React.Component<{}> {
Show full toolbar
- Doc.UserDoc()._raiseWhenDragged = !Doc.UserDoc()._raiseWhenDragged} - checked={BoolCast(Doc.UserDoc()._raiseWhenDragged)} /> + DragManager.SetRaiseWhenDragged(!DragManager.GetRaiseWhenDragged())} + checked={DragManager.GetRaiseWhenDragged()} />
Raise on drag
- Doc.UserDoc()._showLabel = !Doc.UserDoc()._showLabel} - checked={BoolCast(Doc.UserDoc()._showLabel)} /> -
Show tool button labels
-
-
- Doc.UserDoc()._showMenuLabel = !Doc.UserDoc()._showMenuLabel} - checked={BoolCast(Doc.UserDoc()._showMenuLabel)} /> -
Show menu button labels
+ FontIconBox.SetShowLabels(!FontIconBox.GetShowLabels())} + checked={FontIconBox.GetShowLabels()} /> +
Show button labels
; } @@ -271,7 +268,7 @@ export class SettingsManager extends React.Component<{}> {
- Doc.defaultAclPrivate = !Doc.defaultAclPrivate)} />
Default access private
diff --git a/src/client/util/SnappingManager.ts b/src/client/util/SnappingManager.ts index 069f81d38..057843c68 100644 --- a/src/client/util/SnappingManager.ts +++ b/src/client/util/SnappingManager.ts @@ -1,5 +1,6 @@ import { observable, action, runInAction } from "mobx"; import { computedFn } from "mobx-utils"; +import { Doc } from "../../fields/Doc"; export namespace SnappingManager { @@ -30,6 +31,9 @@ export namespace SnappingManager { export function SetIsDragging(dragging: boolean) { runInAction(() => manager.IsDragging = dragging); } export function GetIsDragging() { return manager.IsDragging; } + export function SetShowSnapLines(show: boolean) { runInAction(() => Doc.UserDoc().showSnapLines = show); } + export function GetShowSnapLines() { return Doc.UserDoc().showSnapLines; } + /// bcz; argh!! TODO; These do not belong here, but there were include order problems with leaving them in util.ts // need to investigate further what caused the mobx update problems and move to a better location. const getCachedGroupByNameCache = computedFn(function (name: string) { return manager.cachedGroups.includes(name); }, true); diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 9a0f25fe3..a126218c4 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -28,7 +28,7 @@ export class DashboardView extends React.Component { newDashboard = async () => { const batch = UndoManager.StartBatch("new dash"); - await CurrentUserUtils.createNewDashboard(Doc.UserDoc()); + await CurrentUserUtils.createNewDashboard(); batch.end(); } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 18cf785b9..4247501bb 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -87,10 +87,10 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P if (titleFieldKey === "title") { d.dataDoc["title-custom"] = !this._accumulatedTitle.startsWith("-"); if (StrCast(d.rootDoc.title).startsWith("@") && !this._accumulatedTitle.startsWith("@")) { - Doc.RemoveDocFromList(Doc.UserDoc(), "myPublishedDocs", d.rootDoc); + Doc.RemoveDocFromList(CurrentUserUtils.MyPublishedDocs, undefined, d.rootDoc); } if (!StrCast(d.rootDoc.title).startsWith("@") && this._accumulatedTitle.startsWith("@")) { - Doc.AddDocToList(Doc.UserDoc(), "myPublishedDocs", d.rootDoc); + Doc.AddDocToList(CurrentUserUtils.MyPublishedDocs, undefined, d.rootDoc); } } //@ts-ignore diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 61cca0421..6ee8065f5 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -225,26 +225,21 @@ export class MainView extends React.Component { // Load the user's active dashboard, or create a new one if initial session after signup const received = CurrentUserUtils.MainDocId; if (received && !this.userDoc) { - reaction(() => CurrentUserUtils.GuestTarget, target => target && CurrentUserUtils.createNewDashboard(Doc.UserDoc()), { fireImmediately: true }); + reaction(() => CurrentUserUtils.GuestTarget, target => target && CurrentUserUtils.createNewDashboard(), { fireImmediately: true }); } else { PromiseValue(this.userDoc.activeDashboard).then(dash => { - if (dash instanceof Doc) CurrentUserUtils.openDashboard(this.userDoc, dash); - else CurrentUserUtils.createNewDashboard(this.userDoc); + if (dash instanceof Doc) CurrentUserUtils.openDashboard(dash); + else CurrentUserUtils.createNewDashboard(); }); } } @action createNewPresentation = async () => { - if (!await this.userDoc.myTrails) { - this.userDoc.myTrails = new PrefetchProxy(Docs.Create.TreeDocument([], { - title: "TRAILS", childDontRegisterViews: true, _height: 100, _forceActive: true, boxShadow: "0 0", _lockedPosition: true, treeViewOpen: true, system: true - })); - } const pres = Docs.Create.PresDocument({ title: "Untitled Trail", _viewType: CollectionViewType.Stacking, _fitWidth: true, _width: 400, _height: 500, targetDropAction: "alias", _chromeHidden: true, boxShadow: "0 0" }); CollectionDockingView.AddSplit(pres, "left"); - this.userDoc.activePresentation = pres; - Doc.AddDocToList(this.userDoc.myTrails as Doc, "data", pres); + CurrentUserUtils.ActivePresentation = pres; + Doc.AddDocToList(CurrentUserUtils.MyTrails, "data", pres); } @action @@ -353,9 +348,9 @@ export class MainView extends React.Component { addDocTabFunc = (doc: Doc, location: string): boolean => { const locationFields = doc._viewType === CollectionViewType.Docking ? ["dashboard"] : location.split(":"); const locationParams = locationFields.length > 1 ? locationFields[1] : ""; - if (doc.dockingConfig) return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc); + if (doc.dockingConfig) return CurrentUserUtils.openDashboard(doc); switch (locationFields[0]) { - case "dashboard": return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc); + case "dashboard": return CurrentUserUtils.openDashboard(doc); case "close": return CollectionDockingView.CloseSplit(doc, locationParams); case "fullScreen": return CollectionDockingView.OpenFullScreen(doc); case "lightbox": return LightboxView.AddDocTab(doc, location); @@ -563,7 +558,7 @@ export class MainView extends React.Component {
; } @computed get snapLines() { - return !this.userDoc.showSnapLines ? (null) :
+ return !SnappingManager.GetShowSnapLines() ? (null) :
{SnappingManager.horizSnapLines().map(l => )} {SnappingManager.vertSnapLines().map(l => )} diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 5f36a7a51..19355b8e1 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -121,7 +121,7 @@ export class CollectionDockingView extends CollectionSubView() { SelectionManager.DeselectAll(); const instance = CollectionDockingView.Instance; if (doc._viewType === CollectionViewType.Docking && doc.layoutKey === "layout") { - return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc); + return CurrentUserUtils.openDashboard(doc); } const newItemStackConfig = { type: 'stack', @@ -172,7 +172,7 @@ export class CollectionDockingView extends CollectionSubView() { @undoBatch @action public static AddSplit(document: Doc, pullSide: string, stack?: any, panelName?: string) { - if (document._viewType === CollectionViewType.Docking) return CurrentUserUtils.openDashboard(Doc.UserDoc(), document); + if (document._viewType === CollectionViewType.Docking) return CurrentUserUtils.openDashboard(document); const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document); if (tab) { diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 9b1bb5b97..668d82387 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -164,7 +164,7 @@ export class CollectionMenu extends AntimodeMenu{ // // ; - // OLD BUTTONS + // //OLD BUTTONS // return this.getElement(!this.SelectedCollection ? [/*button*/] : // [ { - const target = this.document !== Doc.UserDoc().sidebar ? this.document : this.document.proto as Doc; + const target = this.document !== CurrentUserUtils.MyLeftSidebarPanel ? this.document : this.document.proto as Doc; //@ts-ignore target._viewType = e.target.selectedOptions[0].value; } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 4b5c5e3fb..63616263e 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -205,7 +205,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent CurrentUserUtils.createNewDashboard(Doc.UserDoc()), icon: "project-diagram" }); + optionItems.push({ description: "Create Dashboard", event: () => CurrentUserUtils.createNewDashboard(), icon: "project-diagram" }); } !options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "hand-point-right" }); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 70db121d1..62d07b0e4 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -329,7 +329,7 @@ export class TabDocView extends React.Component { const locationFields = doc._viewType === CollectionViewType.Docking ? ["dashboard"] : location.split(":"); const locationParams = locationFields.length > 1 ? locationFields[1] : ""; switch (locationFields[0]) { - case "dashboard": return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc); + case "dashboard": return CurrentUserUtils.openDashboard(doc); case "close": return CollectionDockingView.CloseSplit(doc, locationParams); case "fullScreen": return CollectionDockingView.OpenFullScreen(doc); case "replace": return CollectionDockingView.ReplaceTab(doc, locationParams, this.stack); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ffe146ae4..99eec7892 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -253,7 +253,7 @@ export class CollectionFreeFormView extends CollectionSubView Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }) : null; + !Doc.noviceMode ? viewCtrlItems.push({ description: (SnappingManager.GetShowSnapLines() ? "Hide" : "Show") + " Snap Lines", event: () => SnappingManager.SetShowSnapLines(!SnappingManager.GetShowSnapLines()), icon: "compress-arrows-alt" }) : null; !Doc.noviceMode ? viewCtrlItems.push({ description: (this.Document._useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document._useClusters), icon: "braille" }) : null; !viewctrls && ContextMenu.Instance.addItem({ description: "UI Controls...", subitems: viewCtrlItems, icon: "eye" }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index b62020a04..081a1a924 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -6,7 +6,7 @@ import { InkData, InkField, InkTool } from "../../../../fields/InkField"; import { List } from "../../../../fields/List"; import { RichTextField } from "../../../../fields/RichTextField"; import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField"; -import { Cast, FieldValue, NumCast, StrCast } from "../../../../fields/Types"; +import { Cast, DocCast, FieldValue, NumCast, StrCast } from "../../../../fields/Types"; import { ImageField } from "../../../../fields/URLField"; import { GetEffectiveAcl } from "../../../../fields/util"; import { intersectRect, returnFalse, Utils } from "../../../../Utils"; @@ -156,7 +156,7 @@ export class MarqueeView extends React.Component StrCast(Doc.LayoutField(this.layoutDoc))?.includes(ScriptingBox.name); - (this.rootDoc._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc); + (this.rootDoc._raiseWhenDragged === undefined ? DragManager.GetRaiseWhenDragged() : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc); if (this._doubleTap && (this.props.Document.type !== DocumentType.FONTICON || this.onDoubleClickHandler)) {// && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click if (this._timeout) { clearTimeout(this._timeout); diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index 3af6a3d51..1b37e729b 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -79,6 +79,9 @@ export class FontIconBox extends DocComponent() { } } + static GetShowLabels() { return BoolCast(Doc.UserDoc()._showLabel); } + static SetShowLabels(show:boolean) { Doc.UserDoc()._showLabel = show; } + // Determining UI Specs @observable private label = StrCast(this.rootDoc.label, StrCast(this.rootDoc.title)); @observable private icon = StrCast(this.dataDoc.icon, "user") as any; @@ -111,7 +114,7 @@ export class FontIconBox extends DocComponent() { // Script for checking the outcome of the toggle const checkResult: number = numScript?.script.run({ value: 0, _readOnly_: true }).result || 0; - const label = !Doc.UserDoc()._showLabel ? (null) : + const label = !FontIconBox.GetShowLabels() ? (null) :
{this.label}
; @@ -212,7 +215,7 @@ export class FontIconBox extends DocComponent() { style={{ color: color, backgroundColor: backgroundColor, borderBottomLeftRadius: this.dropdown ? 0 : undefined }} onClick={action(() => this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen)}> - {!this.label || !Doc.UserDoc()._showLabel ? (null) :
{this.label}
} + {!this.label || !FontIconBox.GetShowLabels() ? (null) :
{this.label}
}
@@ -283,7 +286,7 @@ export class FontIconBox extends DocComponent() {
; }); - const label = !this.label || !Doc.UserDoc()._showLabel ? (null) : + const label = !this.label || !FontIconBox.GetShowLabels() ? (null) :
{this.label}
; @@ -337,7 +340,7 @@ export class FontIconBox extends DocComponent() { const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); const curColor = this.colorScript?.script.run({ value: undefined, _readOnly_: true }).result ?? "transparent"; - const label = !this.label || !Doc.UserDoc()._showLabel ? (null) : + const label = !this.label || !FontIconBox.GetShowLabels() ? (null) :
{this.label}
; @@ -349,7 +352,7 @@ export class FontIconBox extends DocComponent() {
; setTimeout(() => this.colorPicker(curColor)); // cause an update to the color picker rendered in MainView return ( -
this.colorPickerClosed = !this.colorPickerClosed)} onPointerDown={e => e.stopPropagation()}> @@ -381,7 +384,7 @@ export class FontIconBox extends DocComponent() { const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); // Button label - const label = !this.label || !Doc.UserDoc()._showLabel ? (null) : + const label = !this.label || !FontIconBox.GetShowLabels() ? (null) :
{this.label}
; @@ -400,7 +403,7 @@ export class FontIconBox extends DocComponent() { ); } else { return ( -
{label} @@ -423,7 +426,7 @@ export class FontIconBox extends DocComponent() { style={{ backgroundColor: "transparent", borderBottomLeftRadius: this.dropdown ? 0 : undefined }}>
- {!this.label || !Doc.UserDoc()._showLabel ? (null) : + {!this.label || !FontIconBox.GetShowLabels() ? (null) :
{this.label}
}
@@ -450,12 +453,12 @@ export class FontIconBox extends DocComponent() { render() { const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); - const label = !this.label || !Doc.UserDoc()._showLabel ? (null) : + const label = !this.label || !FontIconBox.GetShowLabels() ? (null) :
{this.label}
; - const menuLabel = !this.label || !Doc.UserDoc()._showMenuLabel ? (null) : + const menuLabel = !this.label || !FontIconBox.GetShowLabels() ? (null) :
{this.label}
; @@ -497,7 +500,7 @@ export class FontIconBox extends DocComponent() { break; case ButtonType.ToolButton: button = ( -
+
{label}
@@ -509,7 +512,7 @@ export class FontIconBox extends DocComponent() { break; case ButtonType.ClickButton: button = ( -
+
{label}
@@ -675,10 +678,9 @@ ScriptingGlobals.add(function setFontSize(size: string | number, checkResult?: b ScriptingGlobals.add(function toggleNoAutoLinkAnchor(checkResult?: boolean) { const editorView = RichTextMenu.Instance?.TextView?.EditorView; if (checkResult) { - return (editorView ? RichTextMenu.Instance.noAutoLink : Doc.UserDoc().noAutoLink) ? Colors.MEDIUM_BLUE : "transparent"; + return (editorView ? RichTextMenu.Instance.noAutoLink : false) ? Colors.MEDIUM_BLUE : "transparent"; } if (editorView) RichTextMenu.Instance?.toggleNoAutoLinkAnchor(); - else Doc.UserDoc().noAutoLink = Doc.UserDoc().noAutoLink ? true : false; }); ScriptingGlobals.add(function toggleBold(checkResult?: boolean) { diff --git a/src/client/views/nodes/button/colorDropdown/ColorDropdown.tsx b/src/client/views/nodes/button/colorDropdown/ColorDropdown.tsx index 235495250..7f414ddbb 100644 --- a/src/client/views/nodes/button/colorDropdown/ColorDropdown.tsx +++ b/src/client/views/nodes/button/colorDropdown/ColorDropdown.tsx @@ -5,6 +5,7 @@ import { IButtonProps } from '../ButtonInterface'; import { ColorState, SketchPicker } from 'react-color'; import { ScriptField } from '../../../../../fields/ScriptField'; import { Doc } from '../../../../../fields/Doc'; +import { FontIconBox } from '../FontIconBox'; export class ColorDropdown extends Component { render() { @@ -31,7 +32,7 @@ export class ColorDropdown extends Component { disableAlpha={!stroke} onChange={func} color={boolResult ? boolResult : "#FFFFFF"} presetColors={colorOptions} />; - const label = !this.props.label || !Doc.UserDoc()._showLabel ? (null) : + const label = !this.props.label || !FontIconBox.GetShowLabels() ? (null) :
{this.props.label}
; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 90199618b..600730d87 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -355,7 +355,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp var tr = this._editorView.state.tr as any; const autoAnch = this._editorView.state.schema.marks.autoLinkAnchor; tr = tr.removeMark(0, tr.doc.content.size, autoAnch); - DocListCast(Doc.UserDoc().myPublishedDocs).forEach(term => tr = this.hyperlinkTerm(tr, term, newAutoLinks)); + DocListCast(CurrentUserUtils.MyPublishedDocs.data).forEach(term => tr = this.hyperlinkTerm(tr, term, newAutoLinks)); tr = tr.setSelection(new TextSelection(tr.doc.resolve(f), tr.doc.resolve(t))); this._editorView?.dispatch(tr); oldAutoLinks.filter(oldLink => !newAutoLinks.has(oldLink) && oldLink.anchor2 !== this.rootDoc).forEach(LinkManager.Instance.deleteLink); @@ -376,7 +376,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if (!(cfield instanceof ComputedField)) { this.dataDoc.title = prefix + str.substring(0, Math.min(40, str.length)) + (str.length > 40 ? "..." : ""); if (str.startsWith("@") && str.length > 1) { - Doc.AddDocToList(Doc.UserDoc(), "myPublishedDocs", this.rootDoc); + Doc.AddDocToList(CurrentUserUtils.MyPublishedDocs, undefined, this.rootDoc); } } } diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 0d2cffc2c..9f858539f 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -10,7 +10,7 @@ import { InkTool } from "../../../../fields/InkField"; import { List } from "../../../../fields/List"; import { PrefetchProxy } from "../../../../fields/Proxy"; import { listSpec } from "../../../../fields/Schema"; -import { BoolCast, Cast, NumCast, StrCast } from "../../../../fields/Types"; +import { BoolCast, Cast, DocCast, NumCast, StrCast } from "../../../../fields/Types"; import { emptyFunction, returnFalse, returnOne, returnTrue, setupMoveUpEvents } from '../../../../Utils'; import { Docs } from "../../../documents/Documents"; import { DocumentType } from "../../../documents/DocumentTypes"; @@ -131,17 +131,10 @@ export class PresBox extends ViewBoxBaseComponent() { if ((this.targetDoc.type === DocumentType.COL && this.targetDoc._viewType === CollectionViewType.Freeform) || this.targetDoc.type === DocumentType.IMG) return true; else return false; } - @computed get presElement() { return Cast(Doc.UserDoc().presElement, Doc, null); } constructor(props: any) { super(props); if (CurrentUserUtils.ActivePresentation = this.rootDoc) runInAction(() => PresBox.Instance = this); - if (!this.presElement) { // create exactly one presElmentBox template to use by any and all presentations. - Doc.UserDoc().presElement = new PrefetchProxy(Docs.Create.PresElementBoxDocument({ - title: "pres element template", type: DocumentType.PRESELEMENT, _fitWidth: true, _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data" - })); - } this.props.Document.presentationFieldKey = this.fieldKey; // provide info to the presElement script so that it can look up rendering information about the presBox - } @computed get selectedDocumentView() { if (SelectionManager.Views().length) return SelectionManager.Views()[0]; @@ -728,7 +721,7 @@ export class PresBox extends ViewBoxBaseComponent() { }); return true; } - childLayoutTemplate = () => !this.isTreeOrStack ? undefined : this.presElement; + childLayoutTemplate = () => !this.isTreeOrStack ? undefined : DocCast(Doc.UserDoc().presElement); removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.rootDoc, this.fieldKey, doc); getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight panelHeight = () => this.props.PanelHeight() - 40; diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index 1de0c0b10..6a4deca38 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -52,7 +52,7 @@ export class TopBar extends React.Component { ContextMenu.Instance.addItem({ description: "Open Dashboard View", event: this.navigateToHome, icon: "edit" }); ContextMenu.Instance.addItem({ description: "Snapshot Dashboard", event: async () => { const batch = UndoManager.StartBatch("snapshot"); - await CurrentUserUtils.snapshotDashboard(Doc.UserDoc()); + await CurrentUserUtils.snapshotDashboard(); batch.end(); }, icon: "edit" }); dashView?.showContextMenu(e.clientX+20, e.clientY+30); diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index fe8100997..bf06faeb9 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -391,7 +391,7 @@ export class MobileInterface extends React.Component { * Handles the 'Create New Dashboard' button in the menu (taken from MainView.tsx) */ @action - createNewDashboard = async (id?: string) => { + createNewDashboard = (id?: string) => { const scens = CurrentUserUtils.MyDashboards; const dashboardCount = DocListCast(scens.data).length + 1; const freeformOptions: DocumentOptions = { -- cgit v1.2.3-70-g09d2 From 5c582ee52f3af9515d3397fa7661d068fe1babe8 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 21 Jun 2022 14:44:48 -0400 Subject: from last and keep keyvalue tabs out of topbar --- src/client/views/collections/CollectionDockingView.tsx | 6 ++++-- src/client/views/nodes/DocumentView.tsx | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 19355b8e1..07fcd6a7d 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -416,8 +416,10 @@ export class CollectionDockingView extends CollectionSubView() { } tabDestroyed = (tab: any) => { - Doc.AddDocToList(CurrentUserUtils.MyHeaderBar, "data", tab.DashDoc); - Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", tab.DashDoc, undefined, true, true); + if(tab.DashDoc?.type !== DocumentType.KVP) { + Doc.AddDocToList(CurrentUserUtils.MyHeaderBar, "data", tab.DashDoc); + Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", tab.DashDoc, undefined, true, true); + } const dview = CollectionDockingView.Instance.props.Document; const fieldKey = CollectionDockingView.Instance.props.fieldKey; Doc.RemoveDocFromList(dview, fieldKey, tab.DashDoc); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 263e1dc4c..5d2adc321 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1310,9 +1310,7 @@ export class DocumentView extends React.Component { PanelHeight = () => this.panelHeight; ContentScale = () => this.nativeScaling; selfView = () => this; - screenToLocalTransform = () => { - return this.props.ScreenToLocalTransform().translate(-this.centeringX, -this.centeringY).translate(0, shift).scale(1 / this.nativeScaling); - } + screenToLocalTransform = () =>this.props.ScreenToLocalTransform().translate(-this.centeringX, -this.centeringY).scale(1 / this.nativeScaling); componentDidMount() { this._disposers.reactionScript = reaction( () => ScriptCast(this.rootDoc.reactionScript)?.script?.run({ this: this.props.Document, self: Cast(this.rootDoc, Doc, null) || this.props.Document }).result, -- cgit v1.2.3-70-g09d2 From b1eb13fc6264b1272daba824ff0e4cd2bca8a6fa Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 28 Jun 2022 12:23:44 -0400 Subject: cleaned up some more currentUserUtils - fixed some issues with prev/next key frame appearing. --- src/client/documents/Documents.ts | 29 +++++- src/client/util/CurrentUserUtils.ts | 111 ++++----------------- .../views/collections/CollectionDockingView.tsx | 37 +++++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 19 +++- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- src/client/views/topbar/TopBar.tsx | 3 +- src/fields/Doc.ts | 25 +---- 7 files changed, 97 insertions(+), 129 deletions(-) (limited to 'src/client/views/collections/CollectionDockingView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 3780df5b9..4690d856d 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -13,7 +13,7 @@ import { SchemaHeaderField } from "../../fields/SchemaHeaderField"; import { ComputedField, ScriptField } from "../../fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../fields/Types"; import { AudioField, ImageField, MapField, PdfField, RecordingField, VideoField, WebField, YoutubeField } from "../../fields/URLField"; -import { SharingPermissions } from "../../fields/util"; +import { inheritParentAcls, SharingPermissions } from "../../fields/util"; import { Upload } from "../../server/SharedMediaTypes"; import { aggregateBounds, OmitKeys, Utils } from "../../Utils"; import { YoutubeBox } from "../apis/youtube/YoutubeBox"; @@ -1266,7 +1266,7 @@ export namespace DocUtils { const documentList: ContextMenuProps[] = DocListCast(DocListCast(CurrentUserUtils.MyTools?.data)[0]?.data).filter(btnDoc => !btnDoc.hidden).map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)).filter(doc => doc && doc !== Doc.UserDoc().emptyPresentation).map((dragDoc, i) => ({ description: ":" + StrCast(dragDoc.title).replace("Untitled ",""), event: undoBatch((args: { x: number, y: number }) => { - const newDoc = Doc.copyDragFactory(dragDoc); + const newDoc = DocUtils.copyDragFactory(dragDoc); if (newDoc) { newDoc.author = Doc.CurrentUserEmail; newDoc.x = x; @@ -1479,9 +1479,34 @@ export namespace DocUtils { } return generatedDocuments; } + + // copies the specified drag factory document + export function copyDragFactory(dragFactory: Doc) { + if (!dragFactory) return undefined; + const ndoc = dragFactory.isTemplateDoc ? Doc.ApplyTemplate(dragFactory) : Doc.MakeCopy(dragFactory, true); + ndoc && Doc.AddDocToList(CurrentUserUtils.MyFileOrphans, "data", Doc.GetProto(ndoc)); + if (ndoc && dragFactory["dragFactory-count"] !== undefined) { + dragFactory["dragFactory-count"] = NumCast(dragFactory["dragFactory-count"]) + 1; + Doc.SetInPlace(ndoc, "title", ndoc.title + " " + NumCast(dragFactory["dragFactory-count"]).toString(), true); + } + + if (ndoc && CurrentUserUtils.ActiveDashboard) inheritParentAcls(CurrentUserUtils.ActiveDashboard, ndoc); + + return ndoc; + } + export function delegateDragFactory(dragFactory: Doc) { + const ndoc = Doc.MakeDelegateWithProto(dragFactory); + if (ndoc && dragFactory["dragFactory-count"] !== undefined) { + dragFactory["dragFactory-count"] = NumCast(dragFactory["dragFactory-count"]) + 1; + Doc.GetProto(ndoc).title = ndoc.title + " " + NumCast(dragFactory["dragFactory-count"]).toString(); + } + return ndoc; + } } ScriptingGlobals.add("Docs", Docs); +ScriptingGlobals.add(function copyDragFactory(dragFactory: Doc) { return DocUtils.copyDragFactory(dragFactory); }); +ScriptingGlobals.add(function delegateDragFactory(dragFactory: Doc) { return DocUtils.delegateDragFactory(dragFactory); }); ScriptingGlobals.add(function makeDelegate(proto: any) { const d = Docs.Create.DelegateDocument(proto, { title: "child of " + proto.title }); return d; }); ScriptingGlobals.add(function generateLinkTitle(self: Doc) { const anchor1title = self.anchor1 && self.anchor1 !== self ? Cast(self.anchor1, Doc, null).title : ""; diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 6e115ea3c..2a0702a58 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -755,8 +755,8 @@ export class CurrentUserUtils { CollectionViewType.Carousel3D, CollectionViewType.Linear, CollectionViewType.Map, CollectionViewType.Grid]), title: "Perspective", toolTip: "View", width: 100,btnType: ButtonType.DropdownList,ignoreClick: true, scripts: { script: 'setView(value, _readOnly_)'}}, - { title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", width: 20, btnType: ButtonType.ClickButton, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}, funcs: {hidden: 'IsNoviceMode()'}}, - { title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", width: 20, btnType: ButtonType.ClickButton, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}, funcs: {hidden: 'IsNoviceMode()'}}, + { title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", width: 20, btnType: ButtonType.ClickButton, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}, funcs: {hidden: 'IsNoviceMode() || !selectedDocumentType(undefined, "freeform")'}}, + { title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", width: 20, btnType: ButtonType.ClickButton, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}, funcs: {hidden: 'IsNoviceMode() || !selectedDocumentType(undefined, "freeform")'}}, { title: "Fill", icon: "fill-drip", toolTip: "Background Fill Color",width: 20, btnType: ButtonType.ColorButton, ignoreClick: true, scripts: { script: 'setBackgroundColor(value, _readOnly_)'},funcs: {hidden: '!selectedDocumentType()'}}, // Only when a document is selected { title: "Header", icon: "heading", toolTip: "Header Color", btnType: ButtonType.ColorButton, ignoreClick: true, scripts: { script: 'setHeaderColor(value, _readOnly_)'}, funcs: {hidden: '!selectedDocumentType()'}}, { title: "Overlay", icon: "layer-group", toolTip: "Overlay", btnType: ButtonType.ToggleButton, scripts: { onClick: 'toggleOverlay(_readOnly_)'}, funcs: {hidden: '!selectedDocumentType(undefined, "freeform", true)'}}, // Only when floating document is selected in freeform @@ -1028,8 +1028,10 @@ export class CurrentUserUtils { public static _urlState: HistoryUtil.DocUrl; - public static openDashboard = (doc: Doc, fromHistory = false) => { - if (!doc) return; + /// opens a dashboard as the ActiveDashboard (and adds the dashboard to the users list of dashboards if it's not already there). + /// this also sets the readonly state of the dashboard based on the current mode of dash (from its url) + public static openDashboard = (doc: Doc|undefined, fromHistory = false) => { + if (!doc) return false; CurrentUserUtils.MainDocId = doc[Id]; Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", doc); @@ -1097,46 +1099,15 @@ export class CurrentUserUtils { }; input.click(); } + + public static snapshotDashboard() { return CollectionDockingView.TakeSnapshot(CurrentUserUtils.ActiveDashboard); } - public static CaptureDashboardThumbnail() { - const activeDashboard = CurrentUserUtils.ActiveDashboard; - const docView = CollectionDockingView.Instance.props.DocumentView?.(); - const content = docView?.ContentDiv; - if (docView && content && activeDashboard) { - const _width = Number(getComputedStyle(content).width.replace("px","")); - const _height = Number(getComputedStyle(content).height.replace("px","")); - return CollectionFreeFormView.UpdateIcon( - docView.layoutDoc[Id] + "-icon" + (new Date()).getTime(), - content, - _width, _height, - _width, _height, 0, 1, true, docView.layoutDoc[Id] + "-icon", - (iconFile, _nativeWidth, _nativeHeight) => { - const img = Docs.Create.ImageDocument(new ImageField(iconFile), { title: docView.rootDoc.title+"-icon", _width, _height, _nativeWidth, _nativeHeight}); - const proto = Cast(img.proto, Doc, null)!; - proto["data-nativeWidth"] = _width; - proto["data-nativeHeight"] = _height; - Doc.GetProto(activeDashboard).thumb = img; - }); - } - - } - - public static async snapshotDashboard() { - if (CurrentUserUtils.ActiveDashboard) { - const copy = await CollectionDockingView.Copy(CurrentUserUtils.ActiveDashboard); - Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", copy); - CurrentUserUtils.openDashboard(copy); - } - } - - public static closeActiveDashboard = () => { - CurrentUserUtils.ActiveDashboard = undefined; - } + public static closeActiveDashboard = () => { CurrentUserUtils.ActiveDashboard = undefined; } public static removeDashboard = async (dashboard:Doc) => { const dashboards = await DocListCastAsync(CurrentUserUtils.MyDashboards.data); if (dashboards?.length) { - if (dashboard === CurrentUserUtils.ActiveDashboard) CurrentUserUtils.openDashboard(dashboards.find(doc => doc !== dashboard)!); + if (dashboard === CurrentUserUtils.ActiveDashboard) CurrentUserUtils.openDashboard(dashboards.find(doc => doc !== dashboard)); Doc.RemoveDocFromList(CurrentUserUtils.MyDashboards, "data", dashboard); if (!dashboards.length) CurrentUserUtils.ActivePage = "home"; } @@ -1214,14 +1185,6 @@ export class CurrentUserUtils { public static get ActiveTool(): InkTool { return StrCast(Doc.UserDoc().activeTool, InkTool.None) as InkTool; } } -ScriptingGlobals.add(function openDragFactory(dragFactory: Doc) { - const copy = Doc.copyDragFactory(dragFactory); - if (copy) { - CollectionDockingView.AddSplit(copy, "right"); - const view = DocumentManager.Instance.getFirstDocumentView(copy); - view && SelectionManager.SelectView(view, false); - } -}); ScriptingGlobals.add(function MySharedDocs() { return CurrentUserUtils.MySharedDocs; }, "document containing all shared Docs"); ScriptingGlobals.add(function IsNoviceMode() { return Doc.noviceMode; }, "is Dash in novice mode"); ScriptingGlobals.add(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }, "switches between comic and normal document rendering"); @@ -1232,52 +1195,14 @@ ScriptingGlobals.add(function createNewFolder() { return MainView.Instance.creat ScriptingGlobals.add(function links(doc: any) { return new List(LinkManager.Instance.getAllRelatedLinks(doc)); }, "returns all the links to the document or its annotations", "(doc: any)"); ScriptingGlobals.add(function importDocument() { return CurrentUserUtils.importDocument(); }, "imports files from device directly into the import sidebar"); ScriptingGlobals.add(function shareDashboard(dashboard: Doc) { SharingManager.Instance.open(undefined, dashboard); }, "opens sharing dialog for Dashboard"); -ScriptingGlobals.add(async function removeDashboard(dashboard: Doc) { CurrentUserUtils.removeDashboard(dashboard); }, "Remove Dashboard from Dashboards"); -ScriptingGlobals.add(function addToDashboards(dashboard: Doc) { - const dashboardAlias = Doc.MakeAlias(dashboard); - Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", dashboardAlias); - CurrentUserUtils.openDashboard(dashboardAlias); -}, - "adds Dashboard to set of Dashboards"); - -ScriptingGlobals.add(function selectedDocumentType(docType?: DocumentType, colType?: CollectionViewType, checkParent?: boolean) { - let selected = SelectionManager.Docs().length ? SelectionManager.Docs()[0] : undefined; - if (selected && checkParent) { - const parentDoc: Doc = Cast(selected.context, Doc, null); - selected = parentDoc; - } - if (selected && docType && selected.type === docType) return true; - else if (selected && colType && selected.viewType === colType) return true; - else if (selected && !colType && !docType) return true; - else return false; +ScriptingGlobals.add(function removeDashboard(dashboard: Doc) { CurrentUserUtils.removeDashboard(dashboard); }, "Remove Dashboard from Dashboards"); +ScriptingGlobals.add(function addToDashboards(dashboard: Doc) { CurrentUserUtils.openDashboard( Doc.MakeAlias(dashboard)); }, "adds Dashboard to set of Dashboards"); +ScriptingGlobals.add(function selectedDocumentType(docType?: DocumentType, colType?: CollectionViewType, checkContext?: boolean) { + let selected = (sel => checkContext ? DocCast(sel?.context) : sel)(SelectionManager.SelectedSchemaDoc() ?? SelectionManager.Docs().lastElement()); + return docType ? selected?.type === docType : colType ? selected?.viewType === colType : true; }); ScriptingGlobals.add(function makeTopLevelFolder() { - const folder = Docs.Create.TreeDocument([], { title: "Untitled folder", _stayInCollection: true, isFolder: true }); - TreeView._editTitleOnLoad = { id: folder[Id], parent: undefined }; - return Doc.AddDocToList(CurrentUserUtils.MyFilesystem, "data", folder); -}); -ScriptingGlobals.add(function nextKeyFrame(readOnly: boolean) { - if (readOnly) return; - const sel = SelectionManager.Views()[0]; - const col = (sel.ComponentView as CollectionFreeFormView); - const currentFrame = Cast(sel.props.Document._currentFrame, "number", null); - if (currentFrame === undefined) { - sel.props.Document._currentFrame = 0; - CollectionFreeFormDocumentView.setupKeyframes(col.childDocs, 0); - } - CollectionFreeFormDocumentView.updateKeyframe(col.childDocs, currentFrame || 0); - sel.rootDoc._currentFrame = Math.max(0, (currentFrame || 0) + 1); - sel.rootDoc.lastFrame = Math.max(NumCast(sel.rootDoc._currentFrame), NumCast(sel.rootDoc.lastFrame)); -}); -ScriptingGlobals.add(function prevKeyFrame(readOnly: boolean) { - if (readOnly) return; - const sel = SelectionManager.Views()[0]; - const col = (sel.ComponentView as CollectionFreeFormView); - const currentFrame = Cast(sel.props.Document._currentFrame, "number", null); - if (currentFrame === undefined) { - sel.props.Document._currentFrame = 0; - CollectionFreeFormDocumentView.setupKeyframes(col.childDocs, 0); - } - CollectionFreeFormDocumentView.gotoKeyframe(col.childDocs.slice()); - sel.rootDoc._currentFrame = Math.max(0, (currentFrame || 0) - 1); + TreeView._editTitleOnLoad = { id: Utils.GenerateGuid(), parent: undefined }; + const opts = { title: "Untitled folder", _stayInCollection: true, isFolder: true }; + return Doc.AddDocToList(CurrentUserUtils.MyFilesystem, "data", Docs.Create.TreeDocument([], opts, TreeView._editTitleOnLoad.id)); }); \ No newline at end of file diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 07fcd6a7d..0830b6fdf 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -4,12 +4,12 @@ import { action, IReactionDisposer, observable, reaction, runInAction } from "mo import { observer } from "mobx-react"; import * as ReactDOM from 'react-dom'; import * as GoldenLayout from "../../../client/goldenLayout"; -import { DataSym, Doc, DocListCast, DocListCastAsync, Opt } from "../../../fields/Doc"; +import { Doc, DocListCast, Opt } from "../../../fields/Doc"; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; -import { listSpec } from '../../../fields/Schema'; import { Cast, NumCast, StrCast } from "../../../fields/Types"; +import { ImageField } from '../../../fields/URLField'; import { inheritParentAcls } from '../../../fields/util'; import { emptyFunction, incrementTitleCopy } from '../../../Utils'; import { DocServer } from "../../DocServer"; @@ -19,14 +19,15 @@ import { CurrentUserUtils } from '../../util/CurrentUserUtils'; import { DragManager } from "../../util/DragManager"; import { InteractionUtils } from '../../util/InteractionUtils'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; +import { SelectionManager } from '../../util/SelectionManager'; import { undoBatch, UndoManager } from "../../util/UndoManager"; import { LightboxView } from '../LightboxView'; import "./CollectionDockingView.scss"; +import { CollectionFreeFormView } from './collectionFreeForm'; import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView"; import { CollectionViewType } from './CollectionView'; import { TabDocView } from './TabDocView'; import React = require("react"); -import { SelectionManager } from '../../util/SelectionManager'; const _global = (window /* browser */ || global /* node */) as any; @observer @@ -373,13 +374,34 @@ export class CollectionDockingView extends CollectionSubView() { } } - public static async Copy(doc: Doc, clone = false) { + public CaptureThumbnail() { + const content = this.props.DocumentView?.()?.ContentDiv; + if (content) { + const _width = Number(getComputedStyle(content).width.replace("px","")); + const _height = Number(getComputedStyle(content).height.replace("px","")); + return CollectionFreeFormView.UpdateIcon( + this.layoutDoc[Id] + "-icon" + (new Date()).getTime(), + content, + _width, _height, + _width, _height, 0, 1, true, this.layoutDoc[Id] + "-icon", + (iconFile, _nativeWidth, _nativeHeight) => { + const img = Docs.Create.ImageDocument(new ImageField(iconFile), { title: this.rootDoc.title+"-icon", _width, _height, _nativeWidth, _nativeHeight}); + const proto = Cast(img.proto, Doc, null)!; + proto["data-nativeWidth"] = _width; + proto["data-nativeHeight"] = _height; + this.dataDoc.thumb = img; + }); + } + + } + public static async TakeSnapshot(doc: Doc|undefined, clone = false) { + if (!doc) return undefined; let json = StrCast(doc.dockingConfig); if (clone) { - const cloned = (await Doc.MakeClone(doc)); + const cloned = await Doc.MakeClone(doc); Array.from(cloned.map.entries()).map(entry => json = json.replace(entry[0], entry[1][Id])); Doc.GetProto(cloned.clone).dockingConfig = json; - return cloned.clone; + return CurrentUserUtils.openDashboard(cloned.clone); } const matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g); const origtabids = matches?.map(m => m.replace("\"documentId\":\"", "").replace("\"", "")) || []; @@ -395,7 +417,8 @@ export class CollectionDockingView extends CollectionSubView() { json = json.replace(origtab[Id], newtab[Id]); return newtab; }); - return Docs.Create.DockDocument(newtabs, json, { title: incrementTitleCopy(StrCast(doc.title)) }); + const copy = Docs.Create.DockDocument(newtabs, json, { title: incrementTitleCopy(StrCast(doc.title)) }); + return CurrentUserUtils.openDashboard(await copy); } @action diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3c2047db7..b9da4faa4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -153,6 +153,21 @@ export class CollectionFreeFormView extends CollectionSubView { + const currentFrame = Cast(this.Document._currentFrame, "number", null); + if (currentFrame === undefined) { + this.Document._currentFrame = 0; + CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0); + } + if (back) { + CollectionFreeFormDocumentView.gotoKeyframe(this.childDocs.slice()); + this.Document._currentFrame = Math.max(0, (currentFrame || 0) - 1); + } else { + CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, currentFrame || 0); + this.Document._currentFrame = Math.max(0, (currentFrame || 0) + 1); + this.Document.lastFrame = Math.max(NumCast(this.Document._currentFrame), NumCast(this.Document.lastFrame)); + } + } @action setKeyFrameEditing = (set: boolean) => this._keyframeEditing = set; getKeyFrameEditing = () => this._keyframeEditing; onBrowseClickHandler = () => this.props.onBrowseClick?.() || ScriptCast(this.layoutDoc.onBrowseClick); @@ -2086,4 +2101,6 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY }); Doc.linkFollowHighlight(dv?.props.Document, false); } -ScriptingGlobals.add(CollectionBrowseClick); \ No newline at end of file +ScriptingGlobals.add(CollectionBrowseClick); +ScriptingGlobals.add(function nextKeyFrame(readOnly: boolean) { !readOnly && (SelectionManager.Views()[0].ComponentView as CollectionFreeFormView)?.changeKeyFrame(); }); +ScriptingGlobals.add(function prevKeyFrame(readOnly: boolean) { !readOnly && (SelectionManager.Views()[0].ComponentView as CollectionFreeFormView)?.changeKeyFrame(true); }); \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 17f1106d0..ab8a34d5a 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -156,7 +156,7 @@ export class MarqueeView extends React.Component { - CurrentUserUtils.CaptureDashboardThumbnail()?.then(() => { + CollectionDockingView.Instance.CaptureThumbnail()?.then(() => { CurrentUserUtils.ActivePage = "home"; CurrentUserUtils.closeActiveDashboard(); // bcz: if we do this, we need some other way to keep track, for user convenience, of the last dashboard in use }); diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index a5d952176..b30ca644d 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -23,7 +23,7 @@ import { listSpec } from "./Schema"; import { ComputedField, ScriptField } from "./ScriptField"; import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types"; import { AudioField, ImageField, MapField, PdfField, VideoField, WebField } from "./URLField"; -import { deleteProperty, GetEffectiveAcl, getField, getter, inheritParentAcls, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions, updateFunction } from "./util"; +import { deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions, updateFunction } from "./util"; import JSZip = require("jszip"); export namespace Field { @@ -1242,27 +1242,6 @@ export namespace Doc { return !curPres ? false : DocListCast(curPres.data).findIndex((val) => Doc.AreProtosEqual(val, doc)) !== -1; } - export function copyDragFactory(dragFactory: Doc) { - const ndoc = dragFactory.isTemplateDoc ? Doc.ApplyTemplate(dragFactory) : Doc.MakeCopy(dragFactory, true); - ndoc && Doc.AddDocToList(CurrentUserUtils.MyFileOrphans, "data", Doc.GetProto(ndoc)); - if (ndoc && dragFactory["dragFactory-count"] !== undefined) { - dragFactory["dragFactory-count"] = NumCast(dragFactory["dragFactory-count"]) + 1; - Doc.SetInPlace(ndoc, "title", ndoc.title + " " + NumCast(dragFactory["dragFactory-count"]).toString(), true); - } - - if (ndoc && CurrentUserUtils.ActiveDashboard) inheritParentAcls(CurrentUserUtils.ActiveDashboard, ndoc); - - return ndoc; - } - export function delegateDragFactory(dragFactory: Doc) { - const ndoc = Doc.MakeDelegateWithProto(dragFactory); - if (ndoc && dragFactory["dragFactory-count"] !== undefined) { - dragFactory["dragFactory-count"] = NumCast(dragFactory["dragFactory-count"]) + 1; - Doc.GetProto(ndoc).title = ndoc.title + " " + NumCast(dragFactory["dragFactory-count"]).toString(); - } - return ndoc; - } - export function toIcon(doc?: Doc, isOpen?: boolean) { switch (StrCast(doc?.type)) { case DocumentType.IMG: return "image"; @@ -1454,8 +1433,6 @@ ScriptingGlobals.add(function getProto(doc: any) { return Doc.GetProto(doc); }); ScriptingGlobals.add(function getDocTemplate(doc?: any) { return Doc.getDocTemplate(doc); }); ScriptingGlobals.add(function getAlias(doc: any) { return Doc.MakeAlias(doc); }); ScriptingGlobals.add(function getCopy(doc: any, copyProto: any) { return doc.isTemplateDoc ? Doc.ApplyTemplate(doc) : Doc.MakeCopy(doc, copyProto); }); -ScriptingGlobals.add(function copyDragFactory(dragFactory: Doc) { return Doc.copyDragFactory(dragFactory); }); -ScriptingGlobals.add(function delegateDragFactory(dragFactory: Doc) { return Doc.delegateDragFactory(dragFactory); }); ScriptingGlobals.add(function copyField(field: any) { return Field.Copy(field); }); ScriptingGlobals.add(function docList(field: any) { return DocListCast(field); }); ScriptingGlobals.add(function addDocToList(doc: Doc, field: string, added:Doc) { return Doc.AddDocToList(doc,field, added); }); -- cgit v1.2.3-70-g09d2