diff options
Diffstat (limited to 'src/client/views/collections')
24 files changed, 270 insertions, 281 deletions
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index d8232c132..7617f2a52 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -11,8 +11,7 @@ import { Id } from '../../../fields/FieldSymbols'; import { DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; -import { SelectionManager } from '../../util/SelectionManager'; -import { StyleProp } from '../StyleProvider'; +import { StyleProp } from '../StyleProp'; import { DocumentView } from '../nodes/DocumentView'; import { FocusViewOptions } from '../nodes/FocusViewOptions'; import './CollectionCarousel3DView.scss'; @@ -101,7 +100,7 @@ export class CollectionCarousel3DView extends CollectionSubView() { } changeSlide = (direction: number) => { - SelectionManager.DeselectAll(); + DocumentView.DeselectAll(); this.layoutDoc._carousel_index = (NumCast(this.layoutDoc._carousel_index) + direction + this.carouselItems.length) % this.carouselItems.length; }; diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index fda320077..9d3657995 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -11,7 +11,7 @@ import { Doc, Opt } from '../../../fields/Doc'; import { DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; -import { StyleProp } from '../StyleProvider'; +import { StyleProp } from '../StyleProp'; import { DocumentView } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index b98aceb16..fc9e2e39b 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -16,27 +16,33 @@ import { DocServer } from '../../DocServer'; import { Docs } from '../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import * as GoldenLayout from '../../goldenLayout'; -import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; import { InteractionUtils } from '../../util/InteractionUtils'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; -import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; import { undoable, undoBatch, UndoManager } from '../../util/UndoManager'; import { DashboardView } from '../DashboardView'; import { LightboxView } from '../LightboxView'; +import { DocumentView } from '../nodes/DocumentView'; import { OpenWhere, OpenWhereMod } from '../nodes/OpenWhere'; import { OverlayView } from '../OverlayView'; import { ScriptingRepl } from '../ScriptingRepl'; import { UndoStack } from '../UndoStack'; import './CollectionDockingView.scss'; import { CollectionSubView } from './CollectionSubView'; -import { TabDocView } from './TabDocView'; const _global = (window /* browser */ || global) /* node */ as any; @observer export class CollectionDockingView extends CollectionSubView() { + static tabClass: JSX.Element | null = null; + /** + * Configure golden layout to render its documents using the specified React component + * @param ele - typically would be set to TabDocView + */ + static setTabJSXComponent(ele: any) { + this.tabClass = ele; + } // eslint-disable-next-line no-use-before-define @observable public static Instance: CollectionDockingView | undefined = undefined; @@ -295,7 +301,7 @@ export class CollectionDockingView extends CollectionSubView() { glay.on('tabCreated', this.tabCreated); glay.on('tabDestroyed', this.tabDestroyed); glay.on('stackCreated', this.stackCreated); - glay.registerComponent('DocumentFrameRenderer', TabDocView); + glay.registerComponent('DocumentFrameRenderer', CollectionDockingView.tabClass); glay.container = this._containerRef.current; glay.init(); glay.root.layoutManager.on('itemDropped', this.tabItemDropped); @@ -431,8 +437,8 @@ export class CollectionDockingView extends CollectionSubView() { } else { const tabTarget = (e.target as HTMLElement)?.parentElement?.className.includes('lm_tab') ? (e.target as HTMLElement).parentElement : (e.target as HTMLElement); const map = Array.from(this.tabMap).find(tab => tab.element[0] === tabTarget); - if (map?.DashDoc && DocumentManager.Instance.getFirstDocumentView(map.DashDoc)) { - SelectionManager.SelectView(DocumentManager.Instance.getFirstDocumentView(map.DashDoc), false); + if (map?.DashDoc && DocumentView.getFirstDocumentView(map.DashDoc)) { + DocumentView.SelectView(DocumentView.getFirstDocumentView(map.DashDoc), false); } } } diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index f945a7aa4..e53071584 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -21,13 +21,11 @@ import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; import { dropActionType } from '../../util/DropActionTypes'; -import { SelectionManager } from '../../util/SelectionManager'; -import { SettingsManager } from '../../util/SettingsManager'; +import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; import { AntimodeMenu } from '../AntimodeMenu'; import { EditableView } from '../EditableView'; -import { MainView } from '../MainView'; import { DefaultStyleProvider } from '../StyleProvider'; import { DocumentView, DocumentViewInternal, returnEmptyDocViewList } from '../nodes/DocumentView'; import './CollectionMenu.scss'; @@ -38,6 +36,7 @@ interface CollectionMenuProps { panelWidth: () => number; toggleTopBar: () => void; topBarHeight: () => number; + togglePropertiesFlyout: () => void; } @observer @@ -59,7 +58,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> { componentDidMount() { reaction( - () => SelectionManager.Views.lastElement(), + () => DocumentView.Selected().lastElement(), view => view && this.SetSelection(view) ); } @@ -77,15 +76,6 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> { } }; - @action - toggleProperties = () => { - if (MainView.Instance.propertiesWidth() > 0) { - SettingsManager.Instance.propertiesWidth = 0; - } else { - SettingsManager.Instance.propertiesWidth = 300; - } - }; - buttonBarXf = () => { if (!this._docBtnRef.current) return Transform.Identity(); const { scale, translateX, translateY } = ClientUtils.GetScreenTransform(this._docBtnRef.current); @@ -128,15 +118,15 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> { render() { const headerIcon = this.props.topBarHeight() > 0 ? 'angle-double-up' : 'angle-double-down'; const headerTitle = this.props.topBarHeight() > 0 ? 'Close Header Bar' : 'Open Header Bar'; - const propIcon = SettingsManager.Instance.propertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left'; - const propTitle = SettingsManager.Instance.propertiesWidth > 0 ? 'Close Properties' : 'Open Properties'; + const propIcon = SnappingManager.PropertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left'; + const propTitle = SnappingManager.PropertiesWidth > 0 ? 'Close Properties' : 'Open Properties'; const hardCodedButtons = ( <div className="hardCodedButtons"> <Toggle toggleType={ToggleType.BUTTON} type={Type.PRIM} - color={SettingsManager.userColor} + color={SnappingManager.userColor} onClick={this.props.toggleTopBar} toggleStatus={this.props.topBarHeight() > 0} icon={<FontAwesomeIcon icon={headerIcon} size="lg" />} @@ -145,9 +135,9 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> { <Toggle toggleType={ToggleType.BUTTON} type={Type.PRIM} - color={SettingsManager.userColor} - onClick={this.toggleProperties} - toggleStatus={SettingsManager.Instance.propertiesWidth > 0} + color={SnappingManager.userColor} + onClick={this._props.togglePropertiesFlyout} + toggleStatus={SnappingManager.PropertiesWidth > 0} icon={<FontAwesomeIcon icon={propIcon} size="lg" />} tooltip={propTitle} /> @@ -159,7 +149,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> { <div className="collectionMenu-container" style={{ - background: SettingsManager.userBackgroundColor, + background: SnappingManager.userBackgroundColor, // borderColor: SettingsManager.userColor }}> {this.contMenuButtons} @@ -245,7 +235,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu _viewCommand = { params: ['target'], title: 'bookmark view', - script: "this.target._freeform_panX = self['target-freeform_panX']; this.target._freeform_panY = this['target-freeform_panY']; this.target._freeform_scale = this['target_freeform_scale']; gotoFrame(this.target, this['target-currentFrame']);", + script: "this.target._freeform_panX = this.target_freeform_panX; this.target._freeform_panY = this['target-freeform_panY']; this.target._freeform_scale = this['target_freeform_scale']; gotoFrame(this.target, this['target-currentFrame']);", immediate: undoBatch(() => { this.target._freeform_panX = 0; this.target._freeform_panY = 0; diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index e940a1aef..3f9eed1d6 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -27,7 +27,7 @@ import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocum import { DocumentView } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { FocusViewOptions } from '../nodes/FocusViewOptions'; -import { StyleProp } from '../StyleProvider'; +import { StyleProp } from '../StyleProp'; import './CollectionNoteTakingView.scss'; import { CollectionNoteTakingViewColumn } from './CollectionNoteTakingViewColumn'; import { CollectionNoteTakingViewDivider } from './CollectionNoteTakingViewDivider'; diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index e02570d3e..5b3f625db 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -10,13 +10,13 @@ import { NumCast, StrCast, toList } from '../../../fields/Types'; import { emptyFunction } from '../../../Utils'; import { DocUtils } from '../../documents/DocUtils'; import { dropActionType } from '../../util/DropActionTypes'; -import { SelectionManager } from '../../util/SelectionManager'; import { undoBatch, UndoManager } from '../../util/UndoManager'; import { OpenWhere } from '../nodes/OpenWhere'; import { computePassLayout, computeStarburstLayout } from './collectionFreeForm'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import './CollectionPileView.scss'; import { CollectionSubView } from './CollectionSubView'; +import { DocumentView } from '../nodes/DocumentView'; @observer export class CollectionPileView extends CollectionSubView() { @@ -150,7 +150,7 @@ export class CollectionPileView extends CollectionSubView() { @undoBatch onClick = (e: React.MouseEvent) => { if (e.button === 0) { - SelectionManager.DeselectAll(); + DocumentView.DeselectAll(); this.toggleStarburst(); e.stopPropagation(); } diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 48d24c910..f9b123bb6 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -19,11 +19,8 @@ import { ImageField } from '../../../fields/URLField'; import { emptyFunction, formatTime } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; -import { FollowLinkScript } from '../../documents/DocUtils'; -import { DocumentManager } from '../../util/DocumentManager'; +import { FollowLinkScript, IsFollowLinkScript } from '../../documents/DocUtils'; import { DragManager } from '../../util/DragManager'; -import { IsFollowLinkScript, LinkFollower } from '../../util/LinkFollower'; -import { LinkManager } from '../../util/LinkManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; @@ -87,7 +84,6 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack private _timeline: HTMLDivElement | null = null; // ref to actual timeline div private _timelineWrapper: HTMLDivElement | null = null; // ref to timeline wrapper div for zooming and scrolling private _markerStart: number = 0; - @observable public static CurrentlyPlaying: DocumentView[] = []; @observable _selectingRegion = false; @observable _markerEnd: number | undefined = undefined; @observable _trimming: number = TrimScope.None; @@ -182,7 +178,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack getView = async (doc: Doc, options: FocusViewOptions): Promise<Opt<DocumentView>> => new Promise<Opt<DocumentView>>(res => { if (doc.hidden) options.didMove = !(doc.hidden = false); - const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv)); + const findDoc = (finish: (dv: DocumentView) => void) => DocumentView.addViewRenderedCb(doc, dv => finish(dv)); findDoc(dv => res(dv)); }); @@ -296,7 +292,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack } if (!isClick && Math.abs(movement[0]) > 15 && !this.IsTrimming) { const anchor = CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this._props.fieldKey, this._markerStart, this._markerEnd, undefined, true); - setTimeout(() => DocumentManager.Instance.getDocumentView(anchor)?.select(false)); + setTimeout(() => DocumentView.getDocumentView(anchor)?.select(false)); } (!isClick || !wasSelecting) && (this._markerEnd = undefined); this._timelineWrapper && (this._timelineWrapper.style.cursor = ''); @@ -481,7 +477,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack @action clickAnchor = (anchorDoc: Doc, clientX: number) => { if (IsFollowLinkScript(anchorDoc.onClick)) { - LinkFollower.FollowLink(undefined, anchorDoc, false); + DocumentView.FollowLink(undefined, anchorDoc, false); } const seekTimeInSeconds = this.anchorStart(anchorDoc) - 0.05; const endTime = this.anchorEnd(anchorDoc); @@ -761,12 +757,12 @@ class StackedTimelineAnchor extends ObservableReactComponent<StackedTimelineAnch // for now, we won't follow any links when the lightbox is oepn to avoid "losing" the video. /* (isDictation || !Doc.AreProtosEqual(LightboxView.LightboxDoc, this._props.layoutDoc)) */ !this._props.layoutDoc.dontAutoFollowLinks && - LinkManager.Links(this._props.mark).length && + Doc.Links(this._props.mark).length && time > NumCast(this._props.mark[this._props.startTag]) && time < NumCast(this._props.mark[this._props.endTag]) && this._lastTimecode < NumCast(this._props.mark[this._props.startTag]) - 1e-5 ) { - LinkFollower.FollowLink(undefined, this._props.mark, false); + DocumentView.FollowLink(undefined, this._props.mark, false); } this._lastTimecode = time; } diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 8ae0f2832..3f12a281e 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -31,7 +31,7 @@ import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocum import { DocumentView } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { FocusViewOptions } from '../nodes/FocusViewOptions'; -import { StyleProp } from '../StyleProvider'; +import { StyleProp } from '../StyleProp'; import { CollectionMasonryViewFieldRow } from './CollectionMasonryViewFieldRow'; import './CollectionStackingView.scss'; import { CollectionStackingViewFieldColumn } from './CollectionStackingViewFieldColumn'; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 7c08aedb1..a4708bed5 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -21,12 +21,11 @@ import { Docs, DocumentOptions } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { dropActionType } from '../../util/DropActionTypes'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; -import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; import { UndoManager, undoBatch } from '../../util/UndoManager'; import { ViewBoxBaseComponent } from '../DocComponent'; import { FieldViewProps } from '../nodes/FieldView'; -import { LoadingBox } from '../nodes/LoadingBox'; +import { DocumentView } from '../nodes/DocumentView'; export interface CollectionViewProps extends React.PropsWithChildren<FieldViewProps> { isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc) @@ -377,7 +376,7 @@ export function CollectionSubView<X>() { } }); } else { - const srcWeb = SelectionManager.Views.lastElement(); + const srcWeb = DocumentView.Selected().lastElement(); const srcUrl = (srcWeb?.Document.data as WebField)?.url?.href?.match(/https?:\/\/[^/]*/)?.[0]; const reg = new RegExp(ClientUtils.prepend(''), 'g'); const modHtml = srcUrl ? html.replace(reg, srcUrl) : html; @@ -386,7 +385,7 @@ export function CollectionSubView<X>() { Doc.GetProto(htmlDoc)['data-text'] = Doc.GetProto(htmlDoc).text = text; addDocument(htmlDoc); if (srcWeb) { - const iframe = SelectionManager.Views[0].ContentDiv?.getElementsByTagName('iframe')?.[0]; + const iframe = DocumentView.Selected()[0].ContentDiv?.getElementsByTagName('iframe')?.[0]; const focusNode = iframe?.contentDocument?.getSelection()?.focusNode as any; if (focusNode) { const anchor = srcWeb?.ComponentView?.getAnchor?.(true); @@ -496,13 +495,13 @@ export function CollectionSubView<X>() { if (typeof files === 'string') { const loading = Docs.Create.LoadingDocument(files, options); generatedDocuments.push(loading); - LoadingBox.addCurrentlyLoading(loading); + Doc.addCurrentlyLoading(loading); DocUtils.uploadYoutubeVideoLoading(files, {}, loading); } else { generatedDocuments.push( ...files.map(file => { const loading = Docs.Create.LoadingDocument(file, options); - LoadingBox.addCurrentlyLoading(loading); + Doc.addCurrentlyLoading(loading); DocUtils.uploadFileToDoc(file, {}, loading); return loading; }) diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index b3760d4af..0369e4a2a 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -12,7 +12,6 @@ import { listSpec } from '../../../fields/Schema'; import { ComputedField, ScriptField } from '../../../fields/ScriptField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { Docs } from '../../documents/Documents'; -import { DocumentManager } from '../../util/DocumentManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; @@ -257,7 +256,7 @@ ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBou action(() => { const filterVals = bounds.payload as string[]; filterVals.map(filterVal => Doc.setDocFilter(pivotDoc, pivotField, filterVal, 'check')); - const pivotView = DocumentManager.Instance.getDocumentView(pivotDoc); + const pivotView = DocumentView.getDocumentView(pivotDoc); if (pivotDoc && pivotView?.ComponentView instanceof CollectionTimeView && filterVals.length === 1) { if (pivotView?.ComponentView.childDocs.length && pivotView.ComponentView.childDocs[0][filterVals[0]]) { // eslint-disable-next-line prefer-destructuring diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index d015e73ad..c1247f5b0 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -14,11 +14,9 @@ import { TraceMobx } from '../../../fields/util'; import { emptyFunction, Utils } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { DocUtils } from '../../documents/DocUtils'; -import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; import { dropActionType } from '../../util/DropActionTypes'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; -import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { undoBatch, UndoManager } from '../../util/UndoManager'; @@ -27,10 +25,11 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from '../EditableView'; import { DocumentView } from '../nodes/DocumentView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; -import { StyleProp } from '../StyleProvider'; +import { StyleProp } from '../StyleProp'; import { CollectionFreeFormView } from './collectionFreeForm'; import { CollectionSubView } from './CollectionSubView'; import './CollectionTreeView.scss'; +import { TreeViewType } from './CollectionTreeViewType'; import { TreeView } from './TreeView'; const _global = (window /* browser */ || global) /* node */ as any; @@ -49,12 +48,6 @@ export type collectionTreeViewProps = { hierarchyIndex?: number[]; }; -export enum TreeViewType { - outline = 'outline', - fileSystem = 'fileSystem', - default = 'default', -} - @observer export class CollectionTreeView extends CollectionSubView<Partial<collectionTreeViewProps>>() { public static AddTreeFunc = 'addTreeFolder(this.embedContainer)'; @@ -183,7 +176,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree const targetDataDoc = this.Document[DocData]; const value = DocListCast(targetDataDoc[this._props.fieldKey]); const result = value.filter(v => !docs.includes(v)); - if (docs.some(doc => SelectionManager.Views.some(dv => Doc.AreProtosEqual(dv.Document, doc)))) SelectionManager.DeselectAll(); + if (docs.some(doc => DocumentView.Selected().some(dv => Doc.AreProtosEqual(dv.Document, doc)))) DocumentView.DeselectAll(); if (result.length !== value.length) { if (docIn instanceof Doc) { const ind = DocListCast(targetDataDoc[this._props.fieldKey]).indexOf(docIn); @@ -191,7 +184,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree this._props.removeDocument?.(docIn); if (ind > 0 && prev) { Doc.SetSelectOnLoad(prev); - DocumentManager.Instance.getDocumentView(prev, this.DocumentView?.())?.select(false); + DocumentView.getDocumentView(prev, this.DocumentView?.())?.select(false); } return true; } @@ -468,7 +461,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree minHeight: '100%', }} onWheel={e => e.stopPropagation()} - onClick={() => (!this.layoutDoc.forceActive ? this._props.select(false) : SelectionManager.DeselectAll())} + onClick={() => (!this.layoutDoc.forceActive ? this._props.select(false) : DocumentView.DeselectAll())} onDrop={this.onTreeDrop}> <ul className={`no-indent${this.outlineMode ? '-outline' : ''}`}>{this.treeViewElements}</ul> </div> diff --git a/src/client/views/collections/CollectionTreeViewType.ts b/src/client/views/collections/CollectionTreeViewType.ts new file mode 100644 index 000000000..53b88160e --- /dev/null +++ b/src/client/views/collections/CollectionTreeViewType.ts @@ -0,0 +1,5 @@ +export enum TreeViewType { + outline = 'outline', + fileSystem = 'fileSystem', + default = 'default', +} 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); diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 2f5af0564..969b98d91 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -21,24 +21,23 @@ import { TraceMobx } from '../../../fields/util'; import { DocUtils } from '../../documents/DocUtils'; 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 { LinkManager } from '../../util/LinkManager'; import { SettingsManager } from '../../util/SettingsManager'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { UndoManager, undoBatch, undoable } from '../../util/UndoManager'; import { EditableView } from '../EditableView'; import { ObservableReactComponent } from '../ObservableReactComponent'; -import { StyleProp } from '../StyleProvider'; +import { StyleProp } from '../StyleProp'; import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; import { FieldViewProps, StyleProviderFuncType } from '../nodes/FieldView'; import { KeyValueBox } from '../nodes/KeyValueBox'; import { OpenWhere } from '../nodes/OpenWhere'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; -import { CollectionTreeView, TreeViewType } from './CollectionTreeView'; +import { CollectionTreeView } from './CollectionTreeView'; +import { TreeViewType } from './CollectionTreeViewType'; import { CollectionView } from './CollectionView'; import { TreeSort } from './TreeSort'; import './TreeView.scss'; @@ -208,7 +207,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { const ind = DocListCast(this.dataDoc[key]).indexOf(docs.lastElement()); const res = docs.reduce((flg, doc) => flg && Doc.RemoveDocFromList(this.dataDoc, key, doc), true); - res && ind > 0 && DocumentManager.Instance.getDocumentView(DocListCast(this.dataDoc[key])[ind - 1], this.treeView.DocumentView?.())?.select(false); + res && ind > 0 && DocumentView.getDocumentView(DocListCast(this.dataDoc[key])[ind - 1], this.treeView.DocumentView?.())?.select(false); return res; }; @@ -379,7 +378,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { const bulletData = bullet[DocData]; bulletData.title = ComputedField.MakeFunction('this.text?.Text'); bulletData.data = new List<Doc>([]); - DocumentManager.Instance.AddViewRenderedCb(bullet, dv => dv.ComponentView?.setFocus?.()); + DocumentView.addViewRenderedCb(bullet, dv => dv.ComponentView?.setFocus?.()); return bullet; } @@ -823,7 +822,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { @computed get validExpandViewTypes() { const annos = () => (DocListCast(this.Document[this.fieldKey + '_annotations']).length && !this.treeView.dashboardMode ? 'annotations' : ''); - const links = () => (LinkManager.Links(this.Document).length && !this.treeView.dashboardMode ? 'links' : ''); + const links = () => (Doc.Links(this.Document).length && !this.treeView.dashboardMode ? 'links' : ''); const data = () => (this.childDocs || this.treeView.dashboardMode ? this.fieldKey : ''); const embeddings = () => (this.treeView.dashboardMode ? '' : 'embeddings'); const fields = () => (Doc.noviceMode ? '' : 'fields'); @@ -1210,7 +1209,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { className={`treeView-container${this._props.isContentActive() ? '-active' : ''}`} ref={this.createTreeDropTarget} onDrop={this.onTreeDrop} - // onPointerDown={e => this._props.isContentActive(true) && SelectionManager.DeselectAll()} // bcz: this breaks entering a text filter in a filterBox since it deselects the filter's target document + // onPointerDown={e => this._props.isContentActive(true) && DocumentView.DeselectAll()} // bcz: this breaks entering a text filter in a filterBox since it deselects the filter's target document // onKeyDown={this.onKeyDown} > <li className="collection-child"> diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormClusters.ts b/src/client/views/collections/collectionFreeForm/CollectionFreeFormClusters.ts index 6fc295e27..26a52cd2a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormClusters.ts +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormClusters.ts @@ -1,17 +1,16 @@ import { action, observable } from 'mobx'; +import { CollectionFreeFormView } from '.'; +import { intersectRect } from '../../../../Utils'; import { Doc, Opt } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { intersectRect } from '../../../../Utils'; import { DocumentType } from '../../../documents/DocumentTypes'; -import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { dropActionType } from '../../../util/DropActionTypes'; -import { SelectionManager } from '../../../util/SelectionManager'; +import { StyleProp } from '../../StyleProp'; import { CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDocumentView'; +import { DocumentView } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; -import { StyleProp } from '../../StyleProvider'; import './CollectionFreeFormView.scss'; -import { CollectionFreeFormView } from '.'; export class CollectionFreeFormClusters { private _view: CollectionFreeFormView; @@ -44,7 +43,7 @@ export class CollectionFreeFormClusters { const h = NumCast(doc1Layout._height) + clusterDistance; return doc1.z === doc2.z && intersectRect({ left: x, top: y, width: w, height: h }, { left: x2, top: y2, width: w2, height: h2 }); } - pickCluster(probe: number[]) { + handlePointerDown(probe: number[]) { this._hitCluster = this.childLayoutPairs .map(pair => pair.layout) .reduce((cluster, cd) => { @@ -62,13 +61,13 @@ export class CollectionFreeFormClusters { return this._hitCluster; } - tryDragCluster(e: PointerEvent) { + tryToDrag(e: PointerEvent) { const cluster = this._hitCluster; if (cluster !== -1) { const ptsParent = e; if (ptsParent) { const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === cluster); - const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.DocumentView)!); + const clusterDocs = eles.map(ele => DocumentView.getDocumentView(ele, this.DocumentView)!); const { left, top } = clusterDocs[0].getBounds || { left: 0, top: 0 }; const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? dropActionType.embed : undefined); de.moveDocument = this.viewMoveDocument; @@ -87,7 +86,7 @@ export class CollectionFreeFormClusters { return false; } - initClusters() { + initLayout() { if (this.Document._freeform_useClusters && !this._clusterSets.length && this.childDocs.length) { return this.updateClusters(true); } @@ -97,11 +96,11 @@ export class CollectionFreeFormClusters { updateClusters(useClusters: boolean) { this.Document._freeform_useClusters = useClusters; this._clusterSets.length = 0; - this.childLayoutPairs.map(pair => pair.layout).map(c => this.updateCluster(c)); + this.childLayoutPairs.map(pair => pair.layout).map(c => this.addDocument(c)); } @action - updateClusterDocs(docs: Doc[]) { + addDocuments(docs: Doc[]) { const childLayouts = this.childLayoutPairs.map(pair => pair.layout); if (this.Document._freeform_useClusters) { const docFirst = docs[0]; @@ -143,12 +142,12 @@ export class CollectionFreeFormClusters { this._clusterSets[(doc.layout_cluster = NumCast(docFirst.layout_cluster))].push(doc); }); } - childLayouts.map(child => !this._clusterSets.some((set, i) => Doc.IndexOf(child, set) !== -1 && child.layout_cluster === i) && this.updateCluster(child)); + childLayouts.map(child => !this._clusterSets.some((set, i) => Doc.IndexOf(child, set) !== -1 && child.layout_cluster === i) && this.addDocument(child)); } } @action - updateCluster = (doc: Doc) => { + addDocument = (doc: Doc) => { const childLayouts = this.childLayoutPairs.map(pair => pair.layout); if (this.Document._freeform_useClusters) { this._clusterSets.forEach(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1)); @@ -188,7 +187,7 @@ export class CollectionFreeFormClusters { const cluster = NumCast(doc?.layout_cluster); if (this.Document._freeform_useClusters && doc?.type !== DocumentType.IMG) { if (this._clusterSets.length <= cluster) { - setTimeout(() => doc && this.updateCluster(doc)); + setTimeout(() => doc && this.addDocument(doc)); } else { // choose a cluster color from a palette const colors = ['#da42429e', '#31ea318c', 'rgba(197, 87, 20, 0.55)', '#4a7ae2c4', 'rgba(216, 9, 255, 0.5)', '#ff7601', '#1dffff', 'yellow', 'rgba(27, 130, 49, 0.55)', 'rgba(0, 0, 0, 0.268)']; @@ -212,9 +211,9 @@ export class CollectionFreeFormClusters { return styleProp; }; - trySelectCluster = (addToSel: boolean) => { + tryToSelect = (addToSel: boolean) => { if (addToSel && this._hitCluster !== -1) { - !addToSel && SelectionManager.DeselectAll(); + !addToSel && DocumentView.DeselectAll(); const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === this._hitCluster); this.selectDocuments(eles); return true; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx index 65a529d62..5d8373fc7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx @@ -4,13 +4,13 @@ import * as React from 'react'; import { Doc, DocListCast, FieldType, FieldResult } from '../../../../fields/Doc'; import { InkTool } from '../../../../fields/InkField'; import { StrCast } from '../../../../fields/Types'; -import { LinkManager } from '../../../util/LinkManager'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DocButtonState, DocumentLinksButton } from '../../nodes/DocumentLinksButton'; import { TopBar } from '../../topbar/TopBar'; import { CollectionFreeFormInfoState, InfoState, StateEntryFunc, infoState } from './CollectionFreeFormInfoState'; import './CollectionFreeFormView.scss'; import { DocData } from '../../../../fields/DocSymbols'; +import { CollectionFreeFormView } from './CollectionFreeFormView'; export interface CollectionFreeFormInfoUIProps { Document: Doc; @@ -21,6 +21,12 @@ export interface CollectionFreeFormInfoUIProps { @observer export class CollectionFreeFormInfoUI extends ObservableReactComponent<CollectionFreeFormInfoUIProps> { + public static Init() { + CollectionFreeFormView.SetInfoUICreator((doc: Doc, layout: Doc, childDocs: () => Doc[], close: () => void) => ( + // + <CollectionFreeFormInfoUI Document={doc} LayoutDoc={layout} childDocs={childDocs} close={close} /> + )); + } _firstDocPos = { x: 0, y: 0 }; constructor(props: any) { @@ -63,7 +69,7 @@ export class CollectionFreeFormInfoUI extends ObservableReactComponent<Collectio const linkStart = () => DocumentLinksButton.StartLink; const linkUnstart = () => !DocumentLinksButton.StartLink; - const numDocLinks = () => LinkManager.Instance.getAllDirectLinks(firstDoc())?.length; + const numDocLinks = () => Doc.Links(firstDoc())?.length; const linkMenuOpen = () => DocButtonState.Instance.LinkEditorDocView; const activeTool = () => Doc.ActiveTool; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx index 90977d955..65a2fe0aa 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx @@ -3,9 +3,8 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { ScriptField } from '../../../../fields/ScriptField'; -import { PresBox } from '../../nodes/trails/PresBox'; -import './CollectionFreeFormView.scss'; import { ObservableReactComponent } from '../../ObservableReactComponent'; +import './CollectionFreeFormView.scss'; export interface CollectionFreeFormPannableContentsProps { Document: Doc; @@ -20,12 +19,16 @@ export interface CollectionFreeFormPannableContentsProps { @observer export class CollectionFreeFormPannableContents extends ObservableReactComponent<CollectionFreeFormPannableContentsProps> { + static _overlayPlugin: ((fform: Doc) => React.JSX.Element) | null = null; + public static SetOverlayPlugin(plugin: ((fform: Doc) => React.JSX.Element) | null) { + CollectionFreeFormPannableContents._overlayPlugin = plugin; + } constructor(props: CollectionFreeFormPannableContentsProps) { super(props); makeObservable(this); } @computed get presPaths() { - return this._props.showPresPaths() ? PresBox.Instance.pathLines(this._props.Document) : null; + return this._props.showPresPaths() ? CollectionFreeFormPannableContents._overlayPlugin?.(this._props.Document) : null; } // rectangle highlight used when following trail/link to a region of a collection that isn't a document showViewport = (viewport: { panX: number; panY: number; width: number; height: number } | undefined) => diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index f55d5a23f..6d901119e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -26,15 +26,12 @@ import { aggregateBounds, emptyFunction, intersectRect, Utils } from '../../../. import { Docs } from '../../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; import { DocUtils } from '../../../documents/DocUtils'; -import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { dropActionType } from '../../../util/DropActionTypes'; import { ReplayMovements } from '../../../util/ReplayMovements'; import { CompileScript } from '../../../util/Scripting'; import { ScriptingGlobals } from '../../../util/ScriptingGlobals'; -import { SelectionManager } from '../../../util/SelectionManager'; -import { freeformScrollMode } from '../../../util/SettingsManager'; -import { SnappingManager } from '../../../util/SnappingManager'; +import { freeformScrollMode, SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { undoable, undoBatch, UndoManager } from '../../../util/UndoManager'; import { Timeline } from '../../animationtimeline/Timeline'; @@ -50,12 +47,11 @@ import { FocusViewOptions } from '../../nodes/FocusViewOptions'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { OpenWhere } from '../../nodes/OpenWhere'; import { PinDocView, PinProps } from '../../PinFuncs'; -import { StyleProp } from '../../StyleProvider'; +import { StyleProp } from '../../StyleProp'; import { CollectionSubView } from '../CollectionSubView'; -import { TreeViewType } from '../CollectionTreeView'; +import { TreeViewType } from '../CollectionTreeViewType'; import { CollectionFreeFormBackgroundGrid } from './CollectionFreeFormBackgroundGrid'; import { CollectionFreeFormClusters } from './CollectionFreeFormClusters'; -import { CollectionFreeFormInfoUI } from './CollectionFreeFormInfoUI'; import { computePassLayout, computePivotLayout, computeStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from './CollectionFreeFormLayoutEngines'; import { CollectionFreeFormPannableContents } from './CollectionFreeFormPannableContents'; import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors'; @@ -87,8 +83,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } // this makes mobx trace() statements more descriptive public unprocessedDocs: Doc[] = []; public static collectionsWithUnprocessedInk = new Set<CollectionFreeFormView>(); - public static from(dv?: DocumentView) { - return CollectionFreeFormDocumentView.from(dv)?.CollectionFreeFormView; + public static from(dv?: DocumentView): CollectionFreeFormView | undefined { + const parent = CollectionFreeFormDocumentView.from(dv)?._props.parent; + return parent instanceof CollectionFreeFormView ? parent : undefined; } _oldWheel: any; @@ -227,25 +224,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection public static gotoKeyframe(timer: NodeJS.Timeout | undefined, docs: Doc[], duration: number) { return DocumentView.SetViewTransition(docs, 'all', duration, timer, undefined, true); } - public static updateKeyframe(timer: NodeJS.Timeout | undefined, docs: Doc[], time: number) { - const newTimer = DocumentView.SetViewTransition(docs, 'all', 1000, timer, undefined, true); - const timecode = Math.round(time); - docs.forEach(doc => { - CollectionFreeFormDocumentView.animFields.forEach(val => { - const findexed = Cast(doc[`${val.key}_indexed`], listSpec('number'), null); - findexed?.length <= timecode + 1 && findexed.push(undefined as any as number); - }); - CollectionFreeFormDocumentView.animStringFields.forEach(val => { - const findexed = Cast(doc[`${val}_indexed`], listSpec('string'), null); - findexed?.length <= timecode + 1 && findexed.push(undefined as any as string); - }); - CollectionFreeFormDocumentView.animDataFields(doc).forEach(val => { - const findexed = Cast(doc[`${val}_indexed`], listSpec(InkField), null); - findexed?.length <= timecode + 1 && findexed.push(undefined as any); - }); - }); - return newTimer; - } changeKeyFrame = (back = false) => { const currentFrame = Cast(this.Document._currentFrame, 'number', null); if (currentFrame === undefined) { @@ -256,7 +234,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this._keyTimer = CollectionFreeFormView.gotoKeyframe(this._keyTimer, [...this.childDocs, this.layoutDoc], 1000); this.Document._currentFrame = Math.max(0, (currentFrame || 0) - 1); } else { - this._keyTimer = CollectionFreeFormView.updateKeyframe(this._keyTimer, [...this.childDocs, this.layoutDoc], currentFrame || 0); + this._keyTimer = CollectionFreeFormDocumentView.updateKeyframe(this._keyTimer, [...this.childDocs, this.layoutDoc], currentFrame || 0); this.Document._currentFrame = Math.max(0, (currentFrame || 0) + 1); this.Document.lastFrame = Math.max(NumCast(this.Document._currentFrame), NumCast(this.Document.lastFrame)); } @@ -292,8 +270,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this.addDocument(newDoc); }; selectDocuments = (docs: Doc[]) => { - SelectionManager.DeselectAll(); - docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).forEach(dv => dv && SelectionManager.SelectView(dv, true)); + DocumentView.DeselectAll(); + docs.map(doc => DocumentView.getDocumentView(doc, this.DocumentView?.())).forEach(dv => dv && DocumentView.SelectView(dv, true)); }; addDocument = (newBox: Doc | Doc[]) => { let retVal = false; @@ -301,7 +279,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection retVal = this._props.addDocument?.(newBox) || false; if (retVal) { this.bringToFront(newBox); - this._clusters.updateCluster(newBox); + this._clusters.addDocument(newBox); } } else { retVal = this._props.addDocument?.(newBox) || false; @@ -416,7 +394,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection res(this.DocumentView?.()); return; } - const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv)); + const findDoc = (finish: (dv: DocumentView) => void) => DocumentView.addViewRenderedCb(doc, dv => finish(dv)); findDoc(dv => res(dv)); }); @@ -459,7 +437,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection !d._keepZWhenDragged && (d.zIndex = zsorted.length + 1 + i); // bringToFront } - (docDragData.droppedDocuments.length === 1 || de.shiftKey) && this._clusters.updateClusterDocs(docDragData.droppedDocuments); + (docDragData.droppedDocuments.length === 1 || de.shiftKey) && this._clusters.addDocuments(docDragData.droppedDocuments); return true; } @@ -528,7 +506,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection break; case InkTool.None: if (!(this._props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine))) { - const hit = this._clusters.pickCluster(this.screenToFreeformContentsXf.transformPoint(e.clientX, e.clientY)); + const hit = this._clusters.handlePointerDown(this.screenToFreeformContentsXf.transformPoint(e.clientX, e.clientY)); setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, emptyFunction, hit !== -1, false); } break; @@ -654,7 +632,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection }; onPointerMove = (e: PointerEvent) => { - if (this._clusters.tryDragCluster(e)) { + if (this._clusters.tryToDrag(e)) { e.stopPropagation(); // we're moving a cluster, so stop propagation and return true to end panning and let the document drag take over return true; } @@ -675,7 +653,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const eraserMax = { X: Math.max(lastPoint.X, currPoint.X), Y: Math.max(lastPoint.Y, currPoint.Y) }; // prettier-ignore return this.childDocs - .map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())) + .map(doc => DocumentView.getDocumentView(doc, this.DocumentView?.())) .filter(inkView => inkView?.ComponentView instanceof InkingStroke) .map(inkView => inkView!) .map(inkView => ({ inkViewBounds: inkView.getBounds, inkStroke: inkView.ComponentView as InkingStroke, inkView })) @@ -776,7 +754,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this.childDocs .filter(doc => doc.type === DocumentType.INK && !doc.dontIntersect) .forEach(doc => { - const otherInk = DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())?.ComponentView as InkingStroke; + const otherInk = DocumentView.getDocumentView(doc, this.DocumentView?.())?.ComponentView as InkingStroke; const { inkData: otherInkData } = otherInk?.inkScaledData() ?? { inkData: [] }; const otherScreenPts = otherInkData.map(point => otherInk.ptToScreen(point)); const otherCtrlPts = otherScreenPts.map(spt => (ink.ComponentView as InkingStroke).ptFromScreen(spt)); @@ -1078,17 +1056,18 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection {...OmitKeys(entry, ['replica', 'pair']).omit} key={childLayout[Id] + (entry.replica || '')} Document={childLayout} + parent={this} containerViewPath={this.DocumentView?.().docViewPath} styleProvider={this._clusters.styleProvider} TemplateDataDocument={childData} dragStarting={this.dragStarting} dragEnding={this.dragEnding} + isAnyChildContentActive={this.isAnyChildContentActive} isGroupActive={this._props.isGroupActive} renderDepth={this._props.renderDepth + 1} hideDecorations={BoolCast(childLayout._layout_isSvg && childLayout.type === DocumentType.LINK)} suppressSetHeight={!!this.layoutEngine} RenderCutoffProvider={this.renderCutoffProvider} - CollectionFreeFormView={this} LayoutTemplate={childLayout.z ? undefined : this._props.childLayoutTemplate} LayoutTemplateString={childLayout.z ? undefined : this._props.childLayoutString} rootSelected={childData ? this.rootSelected : returnFalse} @@ -1282,7 +1261,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection }) ); - this._clusters.initClusters(); + this._clusters.initLayout(); return elements; }; @@ -1308,7 +1287,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection childDocsFunc = () => this.childDocs; closeInfo = action(() => { Doc.IsInfoUIDisabled = true }); // prettier-ignore - infoUI = () => (Doc.IsInfoUIDisabled || this.Document.annotationOn || this._props.renderDepth ? null : <CollectionFreeFormInfoUI Document={this.Document} LayoutDoc={this.layoutDoc} childDocs={this.childDocsFunc} close={this.closeInfo} />); + static _infoUI: ((doc: Doc, layout: Doc, childDocs: () => Doc[], close: () => void) => JSX.Element) | null = null; + static SetInfoUICreator(func: (doc: Doc, layout: Doc, childDocs: () => Doc[], close: () => void) => JSX.Element) { + CollectionFreeFormView._infoUI = func; + } + infoUI = () => + Doc.IsInfoUIDisabled || this.Document.annotationOn || this._props.renderDepth + ? null // + : CollectionFreeFormView._infoUI?.(this.Document, this.layoutDoc, this.childDocsFunc, this.closeInfo) || null; componentDidMount() { this._props.setContentViewBox?.(this); @@ -1551,9 +1537,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const isDocInView = (doc: Doc, rect: { left: number; top: number; width: number; height: number }) => intersectRect(docDims(doc), rect); const snappableDocs = activeDocs.filter(doc => doc.z === undefined && isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to - activeDocs - .filter(doc => doc.isGroup && SnappingManager.IsResizing !== doc[Id] && !DragManager.docsBeingDragged.includes(doc)) - .forEach(doc => DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.dragStarting?.(snapToDraggedDoc, false, visited)); + activeDocs.filter(doc => doc.isGroup && SnappingManager.IsResizing !== doc[Id] && !DragManager.docsBeingDragged.includes(doc)).forEach(doc => DocumentView.getDocumentView(doc)?.ComponentView?.dragStarting?.(snapToDraggedDoc, false, visited)); const horizLines: number[] = []; const vertLines: number[] = []; @@ -1654,7 +1638,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection nudge={this.isAnnotationOverlay || this._props.renderDepth > 0 ? undefined : this.nudge} addDocTab={this.addDocTab} slowLoadDocuments={this.slowLoadDocuments} - trySelectCluster={this._clusters.trySelectCluster} + trySelectCluster={this._clusters.tryToSelect} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} addDocument={this.addDocument} @@ -1744,22 +1728,22 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function nextKeyFrame(readOnly: boolean) { - !readOnly && (SelectionManager.Views[0].ComponentView as CollectionFreeFormView)?.changeKeyFrame(); + !readOnly && (DocumentView.Selected()[0].ComponentView as CollectionFreeFormView)?.changeKeyFrame(); }); // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function prevKeyFrame(readOnly: boolean) { - !readOnly && (SelectionManager.Views[0].ComponentView as CollectionFreeFormView)?.changeKeyFrame(true); + !readOnly && (DocumentView.Selected()[0].ComponentView as CollectionFreeFormView)?.changeKeyFrame(true); }); // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function curKeyFrame(readOnly: boolean) { - const selView = SelectionManager.Views; + const selView = DocumentView.Selected(); if (readOnly) return selView[0].ComponentView?.getKeyFrameEditing?.() ? Colors.MEDIUM_BLUE : 'transparent'; runInAction(() => selView[0].ComponentView?.setKeyFrameEditing?.(!selView[0].ComponentView?.getKeyFrameEditing?.())); return undefined; }); // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function pinWithView(pinContent: boolean) { - SelectionManager.Views.forEach(view => + DocumentView.Selected().forEach(view => view._props.pinToPres(view.Document, { currentFrame: Cast(view.Document.currentFrame, 'number', null), pinData: { @@ -1772,16 +1756,16 @@ ScriptingGlobals.add(function pinWithView(pinContent: boolean) { }); // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function bringToFront() { - SelectionManager.Views.forEach(view => CollectionFreeFormView.from(view)?.bringToFront(view.Document)); + DocumentView.Selected().forEach(view => CollectionFreeFormView.from(view)?.bringToFront(view.Document)); }); // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function sendToBack() { - SelectionManager.Views.forEach(view => CollectionFreeFormView.from(view)?.bringToFront(view.Document, true)); + DocumentView.Selected().forEach(view => CollectionFreeFormView.from(view)?.bringToFront(view.Document, true)); }); // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function datavizFromSchema() { // creating a dataviz doc to represent the schema table - SelectionManager.Views.forEach(viewIn => { + DocumentView.Selected().forEach(viewIn => { const view = viewIn; if (!view.layoutDoc.schema_columnKeys) { view.layoutDoc.schema_columnKeys = new List<string>(['title', 'type', 'author', 'author_date']); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 3ab04f403..b96444024 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -17,15 +17,14 @@ import { CognitiveServices } from '../../../cognitive_services/CognitiveServices import { DocUtils } from '../../../documents/DocUtils'; import { DocumentType } from '../../../documents/DocumentTypes'; import { Docs, DocumentOptions } from '../../../documents/Documents'; -import { SelectionManager } from '../../../util/SelectionManager'; -import { freeformScrollMode } from '../../../util/SettingsManager'; -import { SnappingManager } from '../../../util/SnappingManager'; +import { SnappingManager, freeformScrollMode } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { UndoManager, undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { MarqueeViewBounds } from '../../PinFuncs'; import { PreviewCursor } from '../../PreviewCursor'; +import { DocumentView } from '../../nodes/DocumentView'; import { OpenWhere } from '../../nodes/OpenWhere'; import { pasteImageBitmap } from '../../nodes/WebBoxRenderer'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; @@ -175,7 +174,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps this.pasteTable(ns, x, y); })(); e.stopPropagation(); - } else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views.length < 2) { + } else if (!e.ctrlKey && !e.metaKey && DocumentView.Selected().length < 2) { FormattedTextBox.SelectOnLoadChar = Doc.UserDoc().defaultTextLayout && !this._props.childLayoutString ? e.key : ''; FormattedTextBox.LiveTextUndo = UndoManager.StartBatch('type new note'); this._props.addLiveTextDocument(DocUtils.GetNewTextDoc('-typed text-', x, y, 200, 100)); @@ -249,7 +248,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps if (this._visible) { const mselect = this.marqueeSelect(); if (!e.shiftKey) { - SelectionManager.DeselectAll(mselect.length ? undefined : this._props.Document); + DocumentView.DeselectAll(mselect.length ? undefined : this._props.Document); } const docs = mselect.length ? mselect : [this._props.Document]; this._props.selectDocuments(docs); @@ -344,7 +343,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps @undoBatch delete = action((e?: React.PointerEvent<Element> | KeyboardEvent | undefined, hide?: boolean) => { const selected = this.marqueeSelect(false); - SelectionManager.DeselectAll(); + DocumentView.DeselectAll(); selected.forEach(doc => { hide ? (doc.hidden = true) : this._props.removeDocument?.(doc); }); @@ -380,7 +379,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps @undoBatch pileup = action(() => { const selected = this.marqueeSelect(false); - SelectionManager.DeselectAll(); + DocumentView.DeselectAll(); selected.forEach(d => this._props.removeDocument?.(d)); const newCollection = DocUtils.pileup(selected, this.Bounds.left + this.Bounds.width / 2, this.Bounds.top + this.Bounds.height / 2)!; this._props.addDocument?.(newCollection); @@ -390,7 +389,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps }); /** - * This triggers the TabDocView.PinDoc method which is the universal method + * This triggers the DocumentView.PinDoc method which is the universal method * used to pin documents to the currently active presentation trail. * * This one is unique in that it includes the bounds associated with marquee view. diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index e68ed0e17..eac0dc0e1 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -14,7 +14,6 @@ import { Id } from '../../../../fields/FieldSymbols'; import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { CollectionViewType } from '../../../documents/DocumentTypes'; import { BranchingTrailManager } from '../../../util/BranchingTrailManager'; -import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { dropActionType } from '../../../util/DropActionTypes'; import { SettingsManager } from '../../../util/SettingsManager'; @@ -23,7 +22,6 @@ import { UndoStack } from '../../UndoStack'; import { DocumentLinksButton } from '../../nodes/DocumentLinksButton'; import { DocumentView } from '../../nodes/DocumentView'; import { LinkDescriptionPopup } from '../../nodes/LinkDescriptionPopup'; -import { CollectionStackedTimeline } from '../CollectionStackedTimeline'; import { CollectionSubView } from '../CollectionSubView'; import './CollectionLinearView.scss'; @@ -128,14 +126,14 @@ export class CollectionLinearView extends CollectionSubView() { </span> ); getCurrentlyPlayingUI = () => - !CollectionStackedTimeline.CurrentlyPlaying?.length ? null : ( + !DocumentView.CurrentlyPlaying?.length ? null : ( <span className="bottomPopup-background"> <span className="bottomPopup-text"> Currently playing: - {CollectionStackedTimeline.CurrentlyPlaying.map((clip, i) => ( + {DocumentView.CurrentlyPlaying.map((clip, i) => ( <> - <span className="audio-title" onPointerDown={() => DocumentManager.Instance.showDocument(clip.Document, { willZoomCentered: true })}> - {clip.Document.title + (i === CollectionStackedTimeline.CurrentlyPlaying.length - 1 ? ' ' : ',')} + <span className="audio-title" onPointerDown={() => DocumentView.showDocument(clip.Document, { willZoomCentered: true })}> + {clip.Document.title + (i === DocumentView.CurrentlyPlaying.length - 1 ? ' ' : ',')} </span> <FontAwesomeIcon icon={!clip.ComponentView?.IsPlaying?.() ? 'play' : 'pause'} size="lg" onPointerDown={() => clip.ComponentView?.TogglePause?.()} />{' '} <FontAwesomeIcon icon="times" size="lg" onPointerDown={() => clip.ComponentView?.Pause?.()} />{' '} diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx index 49ba85524..931e2c5e0 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx @@ -5,7 +5,7 @@ import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; import { UndoManager } from '../../../util/UndoManager'; -import { StyleProp } from '../../StyleProvider'; +import { StyleProp } from '../../StyleProp'; import { StyleProviderFuncType } from '../../nodes/FieldView'; import { DimUnit } from './CollectionMulticolumnView'; diff --git a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx index ad77c327d..cff0a8b4c 100644 --- a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx @@ -5,7 +5,7 @@ import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; import { UndoManager } from '../../../util/UndoManager'; -import { StyleProp } from '../../StyleProvider'; +import { StyleProp } from '../../StyleProp'; import { StyleProviderFuncType } from '../../nodes/FieldView'; import { DimUnit } from './CollectionMultirowView'; diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 406a7d626..b30954ffd 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -15,16 +15,15 @@ import { ColumnType } from '../../../../fields/SchemaHeaderField'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; import { DocUtils } from '../../../documents/DocUtils'; import { Docs, DocumentOptions, FInfo } from '../../../documents/Documents'; -import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { dropActionType } from '../../../util/DropActionTypes'; -import { SelectionManager } from '../../../util/SelectionManager'; import { SettingsManager } from '../../../util/SettingsManager'; import { undoBatch, undoable } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { EditableView } from '../../EditableView'; import { ObservableReactComponent } from '../../ObservableReactComponent'; -import { DefaultStyleProvider, StyleProp } from '../../StyleProvider'; +import { StyleProp } from '../../StyleProp'; +import { DefaultStyleProvider } from '../../StyleProvider'; import { Colors } from '../../global/globalEnums'; import { DocumentView } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; @@ -92,12 +91,12 @@ export class CollectionSchemaView extends CollectionSubView() { } @computed get _selectedDocs() { - const selected = SelectionManager.Docs.filter(doc => Doc.AreProtosEqual(DocCast(doc.embedContainer), this.Document)); + const selected = DocumentView.SelectedDocs().filter(doc => Doc.AreProtosEqual(DocCast(doc.embedContainer), this.Document)); if (!selected.length) { // if no schema doc is directly selected, test if a child of a schema doc is selected (such as in the preview window) - const childOfSchemaDoc = SelectionManager.Docs.find(sel => DocumentManager.GetContextPath(sel, true).includes(this.Document)); + const childOfSchemaDoc = DocumentView.SelectedDocs().find(sel => DocumentView.getContextPath(sel, true).includes(this.Document)); if (childOfSchemaDoc) { - const contextPath = DocumentManager.GetContextPath(childOfSchemaDoc, true); + const contextPath = DocumentView.getContextPath(childOfSchemaDoc, true); return [contextPath[contextPath.indexOf(childOfSchemaDoc) - 1]]; // the schema doc that is "selected" by virtue of one of its children being selected } } @@ -175,6 +174,7 @@ export class CollectionSchemaView extends CollectionSubView() { document.removeEventListener('keydown', this.onKeyDown); } + isUnstyledView = returnTrue; // used by style provide via ViewBoxInterface rowIndex = (doc: Doc) => this.sortedDocs.docs.indexOf(doc); @action @@ -190,7 +190,7 @@ export class CollectionSchemaView extends CollectionSubView() { !e.shiftKey && this.clearSelection(); const newDoc = this.sortedDocs.docs[lastIndex + 1]; if (this._selectedDocs.includes(newDoc)) { - SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc)); + DocumentView.DeselectView(DocumentView.getFirstDocumentView(curDoc)); } else { this.addDocToSelection(newDoc, e.shiftKey); this._selectedCell && (this._selectedCell[0] = newDoc); @@ -209,7 +209,7 @@ export class CollectionSchemaView extends CollectionSubView() { if (firstIndex > 0 && firstIndex < this.childDocs.length) { !e.shiftKey && this.clearSelection(); const newDoc = this.sortedDocs.docs[firstIndex - 1]; - if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc)); + if (this._selectedDocs.includes(newDoc)) DocumentView.DeselectView(DocumentView.getFirstDocumentView(curDoc)); else { this.addDocToSelection(newDoc, e.shiftKey); this._selectedCell && (this._selectedCell[0] = newDoc); @@ -416,12 +416,12 @@ export class CollectionSchemaView extends CollectionSubView() { @action addDocToSelection = (doc: Doc, extendSelection: boolean) => { - const rowDocView = DocumentManager.Instance.getDocumentView(doc); - if (rowDocView) SelectionManager.SelectView(rowDocView, extendSelection); + const rowDocView = DocumentView.getDocumentView(doc); + if (rowDocView) DocumentView.SelectView(rowDocView, extendSelection); }; @action - clearSelection = () => SelectionManager.DeselectAll(); + clearSelection = () => DocumentView.DeselectAll(); selectRows = (doc: Doc, lastSelected: Doc) => { const index = this.rowIndex(doc); @@ -476,9 +476,9 @@ export class CollectionSchemaView extends CollectionSubView() { this.dataDoc[this.fieldKey ?? 'data'] = new List<Doc>([...removed, ...draggedDocs, ...pushedDocs]); this.clearSelection(); draggedDocs.forEach(doc => { - const draggedView = DocumentManager.Instance.getFirstDocumentView(doc); - if (draggedView) DocumentManager.Instance.RemoveView(draggedView); - DocumentManager.Instance.AddViewRenderedCb(doc, dv => dv.select(true)); + const draggedView = DocumentView.getFirstDocumentView(doc); + if (draggedView) DocumentView.removeView(draggedView); + DocumentView.addViewRenderedCb(doc, dv => dv.select(true)); }); return true; } diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index dfef3aa48..ee6987e89 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -19,9 +19,7 @@ import { ColumnType } from '../../../../fields/SchemaHeaderField'; import { BoolCast, Cast, DateCast, DocCast, FieldValue, StrCast, toList } from '../../../../fields/Types'; import { ImageField } from '../../../../fields/URLField'; import { FInfo, FInfoFieldType } from '../../../documents/Documents'; -import { DocFocusOrOpen } from '../../../util/DocumentManager'; import { dropActionType } from '../../../util/DropActionTypes'; -import { SettingsManager } from '../../../util/SettingsManager'; import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { undoBatch, undoable } from '../../../util/UndoManager'; @@ -29,7 +27,7 @@ import { EditableView } from '../../EditableView'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DefaultStyleProvider } from '../../StyleProvider'; import { Colors } from '../../global/globalEnums'; -import { returnEmptyDocViewList } from '../../nodes/DocumentView'; +import { DocFocusOrOpen, returnEmptyDocViewList } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { KeyValueBox } from '../../nodes/KeyValueBox'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; @@ -300,8 +298,8 @@ export class SchemaDateCell extends ObservableReactComponent<SchemaTableCellProp icon={<FontAwesomeIcon size="sm" icon="caret-down" />} size={Size.XSMALL} type={Type.TERT} - color={SettingsManager.userColor} - background={SettingsManager.userBackgroundColor} + color={SnappingManager.userColor} + background={SnappingManager.userBackgroundColor} popup={ <div style={{ width: 'fit-content', height: '200px' }}> <DatePicker open dateFormat="Pp" selected={this.date?.date ?? Date.now()} onChange={this.handleChange} /> |
