diff options
| author | bobzel <zzzman@gmail.com> | 2024-05-02 00:39:31 -0400 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2024-05-02 00:39:31 -0400 |
| commit | dd08c20ec6df3fad6ecd6b16c787f10b0c23feb4 (patch) | |
| tree | 11f2b1b741369997af567983df0316923e08d780 /src/client/views/collections/TabDocView.tsx | |
| parent | 76838b7b3842c9b184e6459e29796dd14de37e8d (diff) | |
lots more dependency cycle unwinding.
Diffstat (limited to 'src/client/views/collections/TabDocView.tsx')
| -rw-r--r-- | src/client/views/collections/TabDocView.tsx | 216 |
1 files changed, 116 insertions, 100 deletions
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 2d900bb73..2d8b2564d 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -9,7 +9,7 @@ import * as ReactDOM from 'react-dom/client'; import { ClientUtils, DashColor, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick } from '../../../ClientUtils'; import { emptyFunction } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; -import { DocData } from '../../../fields/DocSymbols'; +import { DocData, DocViews } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { FieldId } from '../../../fields/RefField'; @@ -18,10 +18,8 @@ import { Cast, DocCast, NumCast, StrCast, toList } from '../../../fields/Types'; import { DocServer } from '../../DocServer'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { Docs } from '../../documents/Documents'; -import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; import { dropActionType } from '../../util/DropActionTypes'; -import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { UndoManager, undoable } from '../../util/UndoManager'; @@ -29,7 +27,8 @@ import { DashboardView } from '../DashboardView'; import { LightboxView } from '../LightboxView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { PinDocView, PinProps } from '../PinFuncs'; -import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; +import { StyleProp } from '../StyleProp'; +import { DefaultStyleProvider } from '../StyleProvider'; import { Colors } from '../global/globalEnums'; import { DocumentView, returnEmptyDocViewList } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; @@ -194,9 +193,101 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { _mainCont: HTMLDivElement | null = null; _tabReaction: IReactionDisposer | undefined; + /** + * Adds a document to the presentation view + * */ + @action + public static PinDoc(docIn: Doc | Doc[], pinProps: PinProps) { + const docs = toList(docIn); + + const batch = UndoManager.StartBatch('Pin doc to pres trail'); + const curPres = Doc.ActivePresentation ?? Doc.MakeCopy(Doc.UserDoc().emptyTrail as Doc, true); + + if (!Doc.ActivePresentation) { + Doc.AddDocToList(Doc.MyTrails, 'data', curPres); + Doc.ActivePresentation = curPres; + } + + docs.forEach(doc => { + // Edge Case 1: Cannot pin document to itself + if (doc === curPres) { + alert('Cannot pin presentation document to itself'); + return; + } + const anchorDoc = DocumentView.getDocumentView(doc)?.ComponentView?.getAnchor?.(false, pinProps); + const pinDoc = anchorDoc?.type === DocumentType.CONFIG ? anchorDoc : Docs.Create.ConfigDocument({}); + const targDoc = (pinDoc.presentation_targetDoc = anchorDoc ?? doc); + pinDoc.title = doc.title + ' - Slide'; + pinDoc.data = targDoc.type === DocumentType.PRES ? ComputedField.MakeFunction('copyField(this.presentation_targetDoc.data') : new List<Doc>(); // the children of the embedding's layout are the presentation slide children. the embedding's data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data + pinDoc.presentation_movement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom; + pinDoc.presentation_duration = pinDoc.presentation_duration ?? 1000; + pinDoc.presentation_groupWithUp = false; + Doc.SetContainer(pinDoc, curPres); + // these should potentially all be props passed down by the CollectionTreeView to the TreeView elements. That way the PresBox could configure all of its children at render time + pinDoc.treeView = ''; // not really needed, but makes key value pane look better + pinDoc.treeView_RenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area + pinDoc.treeView_HeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling. + pinDoc.treeView_FieldKey = 'data'; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field + pinDoc.treeView_ExpandedView = 'data'; // in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view + pinDoc.treeView_HideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header + const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], null); + + if (pinProps.pinViewport) PinDocView(pinDoc, pinProps, anchorDoc ?? doc); + if (!pinProps?.audioRange && duration !== undefined) { + pinDoc.presentation_mediaStart = 'manual'; + pinDoc.presentation_mediaStop = 'manual'; + } + if (pinProps?.activeFrame !== undefined) { + pinDoc.config_activeFrame = pinProps?.activeFrame; + pinDoc.title = doc.title + ' (move)'; + pinDoc.presentation_movement = PresMovement.Pan; + } + if (pinProps?.currentFrame !== undefined) { + pinDoc.config_currentFrame = pinProps?.currentFrame; + pinDoc.title = doc.title + ' (move)'; + pinDoc.presentation_movement = PresMovement.Pan; + } + if (pinDoc.stroke_isInkMask) { + pinDoc.presentation_hideAfter = true; + pinDoc.presentation_hideBefore = true; + pinDoc.presentation_movement = PresMovement.None; + } + if (curPres.expandBoolean) pinDoc.presentation_expandInlineButton = true; + Doc.AddDocToList(curPres, 'data', pinDoc, PresBox.Instance?.sortArray()?.lastElement()); + PresBox.Instance?.clearSelectedArray(); + pinDoc && PresBox.Instance?.addToSelectedArray(pinDoc); // Update selected array + }); + if ( + // open the presentation trail if it's not already opened + !Array.from(CollectionDockingView.Instance?.tabMap ?? []) + .map(d => d.DashDoc) + .includes(curPres) + ) { + if (Doc.IsInMyOverlay(curPres)) Doc.RemFromMyOverlay(curPres); + CollectionDockingView.AddSplit(curPres, OpenWhereMod.right); + setTimeout(() => DocumentView.showDocument(docs.lastElement(), { willPan: true }), 100); // keeps the pinned doc in view since the sidebar shifts things + } + setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs + } + + static Activate = (tabDoc: Doc) => { + const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(findTab => findTab.DashDoc === tabDoc && !findTab.contentItem.config.props.keyValue); + tab?.header.parent.setActiveContentItem(tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost) + return tab !== undefined; + }; + // static ActivateTabView(doc: Doc) { + // const tabView = Array.from(TabDocView._allTabs).find(view => view._document === doc); + // if (!tabView?._activated && tabView?._document) { + // TabDocView.Activate(tabView?._document); + // return tabView; + // } + // return undefined; + // } constructor(props: any) { super(props); makeObservable(this); + DocumentView.activateTabView = TabDocView.Activate; + DocumentView.PinDoc = TabDocView.PinDoc; } @observable _activated: boolean = false; @@ -205,8 +296,14 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { @observable _hovering = false; @observable _isActive: boolean = false; @observable _isAnyChildContentActive = false; + public static IsSelected = (doc?: Doc) => { + if (Array.from(doc?.[DocViews] ?? []).some(dv => dv?.IsSelected)) { + return true; + } + return false; + }; @computed get _isUserActivated() { - return SelectionManager.IsSelected(this._document) || this._isAnyChildContentActive; + return TabDocView.IsSelected(this._document) || this._isAnyChildContentActive; } get _isContentActive() { return this._isUserActivated || this._hovering; @@ -279,12 +376,12 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { returnFalse, action(clickEv => { if (this.view) { - SelectionManager.SelectView(this.view, false); + DocumentView.SelectView(this.view, false); const child = getChild(); simulateMouseClick(child, clickEv.clientX, clickEv.clientY + 30, clickEv.screenX, clickEv.screenY + 30); } else { this._activated = true; - setTimeout(() => this.view && SelectionManager.SelectView(this.view, false)); + setTimeout(() => this.view && DocumentView.SelectView(this.view, false)); } }) ); @@ -350,7 +447,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { // select the tab document when the tab is directly clicked and activate the tab whenver the tab document is selected titleEle.onpointerdown = action((e: any) => { if (e.target.className !== 'lm_iconWrap') { - if (this.view) SelectionManager.SelectView(this.view, false); + if (this.view) DocumentView.SelectView(this.view, false); else this._activated = true; if (Date.now() - titleEle.lastClick < 1000) titleEle.select(); titleEle.lastClick = Date.now(); @@ -358,7 +455,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { } }); tab._disposers.selectionDisposer = reaction( - () => SelectionManager.IsSelected(this._document), + () => TabDocView.IsSelected(this._document), action(selected => { if (selected) this._activated = true; if (selected && tab.contentItem !== tab.header.parent.getActiveContentItem()) { @@ -382,89 +479,12 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { .off('click') // unbind the current click handler .click(() => { Object.values(tab._disposers).forEach((disposer: any) => disposer?.()); - SelectionManager.DeselectAll(); + DocumentView.DeselectAll(); UndoManager.RunInBatch(() => tab.contentItem.remove(), 'delete tab'); }); } }; - /** - * Adds a document to the presentation view - * */ - @action - public static PinDoc(docIn: Doc | Doc[], pinProps: PinProps) { - const docs = toList(docIn); - - const batch = UndoManager.StartBatch('Pin doc to pres trail'); - const curPres = Doc.ActivePresentation ?? Doc.MakeCopy(Doc.UserDoc().emptyTrail as Doc, true); - - if (!Doc.ActivePresentation) { - Doc.AddDocToList(Doc.MyTrails, 'data', curPres); - Doc.ActivePresentation = curPres; - } - - docs.forEach(doc => { - // Edge Case 1: Cannot pin document to itself - if (doc === curPres) { - alert('Cannot pin presentation document to itself'); - return; - } - const anchorDoc = DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.getAnchor?.(false, pinProps); - const pinDoc = anchorDoc?.type === DocumentType.CONFIG ? anchorDoc : Docs.Create.ConfigDocument({}); - const targDoc = (pinDoc.presentation_targetDoc = anchorDoc ?? doc); - pinDoc.title = doc.title + ' - Slide'; - pinDoc.data = targDoc.type === DocumentType.PRES ? ComputedField.MakeFunction('copyField(this.presentation_targetDoc.data') : new List<Doc>(); // the children of the embedding's layout are the presentation slide children. the embedding's data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data - pinDoc.presentation_movement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom; - pinDoc.presentation_duration = pinDoc.presentation_duration ?? 1000; - pinDoc.presentation_groupWithUp = false; - Doc.SetContainer(pinDoc, curPres); - // these should potentially all be props passed down by the CollectionTreeView to the TreeView elements. That way the PresBox could configure all of its children at render time - pinDoc.treeView = ''; // not really needed, but makes key value pane look better - pinDoc.treeView_RenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area - pinDoc.treeView_HeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling. - pinDoc.treeView_FieldKey = 'data'; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field - pinDoc.treeView_ExpandedView = 'data'; // in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view - pinDoc.treeView_HideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header - const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], null); - - if (pinProps.pinViewport) PinDocView(pinDoc, pinProps, anchorDoc ?? doc); - if (!pinProps?.audioRange && duration !== undefined) { - pinDoc.presentation_mediaStart = 'manual'; - pinDoc.presentation_mediaStop = 'manual'; - } - if (pinProps?.activeFrame !== undefined) { - pinDoc.config_activeFrame = pinProps?.activeFrame; - pinDoc.title = doc.title + ' (move)'; - pinDoc.presentation_movement = PresMovement.Pan; - } - if (pinProps?.currentFrame !== undefined) { - pinDoc.config_currentFrame = pinProps?.currentFrame; - pinDoc.title = doc.title + ' (move)'; - pinDoc.presentation_movement = PresMovement.Pan; - } - if (pinDoc.stroke_isInkMask) { - pinDoc.presentation_hideAfter = true; - pinDoc.presentation_hideBefore = true; - pinDoc.presentation_movement = PresMovement.None; - } - if (curPres.expandBoolean) pinDoc.presentation_expandInlineButton = true; - Doc.AddDocToList(curPres, 'data', pinDoc, PresBox.Instance?.sortArray()?.lastElement()); - PresBox.Instance?.clearSelectedArray(); - pinDoc && PresBox.Instance?.addToSelectedArray(pinDoc); // Update selected array - }); - if ( - // open the presentation trail if it's not already opened - !Array.from(CollectionDockingView.Instance?.tabMap ?? []) - .map(d => d.DashDoc) - .includes(curPres) - ) { - if (Doc.IsInMyOverlay(curPres)) Doc.RemFromMyOverlay(curPres); - CollectionDockingView.AddSplit(curPres, OpenWhereMod.right); - setTimeout(() => DocumentManager.Instance.showDocument(docs.lastElement(), { willPan: true }), 100); // keeps the pinned doc in view since the sidebar shifts things - } - setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs - } - componentDidMount() { new _global.ResizeObserver( action((entries: any) => { @@ -484,12 +504,12 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { } componentDidUpdate(prevProps: Readonly<TabDocViewProps>) { super.componentDidUpdate(prevProps); - this._view && DocumentManager.Instance.AddView(this._view); + this._view && DocumentView.addView(this._view); } componentWillUnmount() { this._tabReaction?.(); - this._view && DocumentManager.Instance.RemoveView(this._view); + this._view && DocumentView.removeView(this._view); runInAction(() => TabDocView._allTabs.delete(this)); this._props.glContainer.layoutManager.off('activeContentItemChanged', this.onActiveContentItemChanged); @@ -503,7 +523,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { 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; - if (!this._view && this.tab?.contentItem?.config?.props?.panelName !== TabDocView.DontSelectOnActivate) setTimeout(() => SelectionManager.SelectView(this._view, false)); + if (!this._view && this.tab?.contentItem?.config?.props?.panelName !== TabDocView.DontSelectOnActivate) setTimeout(() => DocumentView.SelectView(this._view, false)); !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. } } @@ -517,7 +537,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { // lightbox - will add the document to any collection along the path from the document to the docking view that has a field isLightbox. if none is found, it adds to the full screen lightbox addDocTab = (docsIn: Doc | Doc[], location: OpenWhere) => { const docs = toList(docsIn); - SelectionManager.DeselectAll(); + DocumentView.DeselectAll(); const whereFields = location.split(':'); const keyValue = whereFields.includes(OpenWhereMod.keyvalue); const whereMods = whereFields.length > 1 ? (whereFields[1] as OpenWhereMod) : OpenWhereMod.none; @@ -527,7 +547,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { switch (whereFields[0]) { case undefined: case OpenWhere.lightbox: if (this.layoutDoc?._isLightbox) { - const lightboxView = !docs[0].annotationOn && DocCast(docs[0].embedContainer) ? DocumentManager.Instance.getFirstDocumentView(DocCast(docs[0].embedContainer)) : undefined; + const lightboxView = !docs[0].annotationOn && DocCast(docs[0].embedContainer) ? DocumentView.getFirstDocumentView(DocCast(docs[0].embedContainer)) : undefined; const data = lightboxView?.dataDoc[Doc.LayoutFieldKey(lightboxView.Document)]; if (lightboxView && (!data || data instanceof List)) { lightboxView.layoutDoc[Doc.LayoutFieldKey(lightboxView.Document)] = new List<Doc>(docs); @@ -543,7 +563,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { }; remDocTab = (doc: Doc | Doc[]) => { if (doc === this._document) { - SelectionManager.DeselectAll(); + DocumentView.DeselectAll(); CollectionDockingView.CloseSplit(this._document); return true; } @@ -551,11 +571,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { }; getCurrentFrame = () => NumCast(Cast(PresBox.Instance.activeItem.presentation_targetDoc, Doc, null)._currentFrame); - static Activate = (tabDoc: Doc) => { - const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(findTab => findTab.DashDoc === tabDoc && !findTab.contentItem.config.props.keyValue); - tab?.header.parent.setActiveContentItem(tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost) - return tab !== undefined; - }; + @action focusFunc = () => { if (!this.tab.header.parent._activeContentItem || this.tab.header.parent._activeContentItem !== this.tab.contentItem) { @@ -586,7 +602,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { <DocumentView key={this._document[Id]} ref={action((r: DocumentView) => { - this._lastView && DocumentManager.Instance.RemoveView(this._lastView); + this._lastView && DocumentView.removeView(this._lastView); this._view = r; this._lastView = this._view; })} @@ -635,7 +651,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { this._mainCont = ref; if (this._mainCont) { if (this._lastTab) { - this._view && DocumentManager.Instance.RemoveView(this._view); + this._view && DocumentView.removeView(this._view); } this._lastTab = this.tab; (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document); |
