diff options
Diffstat (limited to 'src/client/views/collections')
34 files changed, 424 insertions, 422 deletions
diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx index 4c0a917f5..cbcc980a9 100644 --- a/src/client/views/collections/CollectionCalendarView.tsx +++ b/src/client/views/collections/CollectionCalendarView.tsx @@ -62,7 +62,7 @@ export class CollectionCalendarView extends CollectionSubView() { screenToLocalTransform = () => this._props .ScreenToLocalTransform() - .translate(Doc.NativeWidth(this._props.Document), 0) + .translate(Doc.NativeWidth(this.Document), 0) .scale(this._props.NativeDimScaling?.() || 1); get calendarsKey() { @@ -74,7 +74,7 @@ export class CollectionCalendarView extends CollectionSubView() { <div className="collectionCalendarView"> <CollectionStackingView {...this._props} - setContentView={emptyFunction} + setContentViewBox={emptyFunction} ref={this._stackRef} PanelHeight={this.panelHeight} PanelWidth={this._props.PanelWidth} diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 8e072e235..7e484f3df 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -2,7 +2,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Utils, returnFalse, returnZero } from '../../../Utils'; +import { Utils, emptyFunction, returnFalse, returnZero } from '../../../Utils'; import { Doc, DocListCast } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; @@ -10,7 +10,8 @@ import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; import { SelectionManager } from '../../util/SelectionManager'; import { StyleProp } from '../StyleProvider'; -import { DocFocusOptions, DocumentView } from '../nodes/DocumentView'; +import { DocumentView } from '../nodes/DocumentView'; +import { FocusViewOptions } from '../nodes/FieldView'; import './CollectionCarousel3DView.scss'; import { CollectionSubView } from './CollectionSubView'; const { default: { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } } = require('../global/globalCssVariables.module.scss'); // prettier-ignore @@ -49,7 +50,7 @@ export class CollectionCarousel3DView extends CollectionSubView() { .translate(-this.panelWidth() + ((this.centerScale - 1) * this.panelWidth()) / 2, -((Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight()) + ((this.centerScale - 1) * this.panelHeight()) / 2) .scale(1 / this.centerScale); - focus = (anchor: Doc, options: DocFocusOptions) => { + focus = (anchor: Doc, options: FocusViewOptions) => { const docs = DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]); if (anchor.type !== DocumentType.CONFIG && !docs.includes(anchor)) return; options.didMove = true; @@ -70,7 +71,7 @@ export class CollectionCarousel3DView extends CollectionSubView() { NativeWidth={returnZero} NativeHeight={returnZero} layout_fitWidth={undefined} - onDoubleClick={this.onChildDoubleClick} + onDoubleClickScript={this.onChildDoubleClick} renderDepth={this._props.renderDepth + 1} LayoutTemplate={this._props.childLayoutTemplate} LayoutTemplateString={this._props.childLayoutString} @@ -80,7 +81,6 @@ export class CollectionCarousel3DView extends CollectionSubView() { isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive} PanelWidth={this.panelWidth} PanelHeight={this.panelHeight} - bringToFront={returnFalse} /> ); }; diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index a125f1356..dae16bafb 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -7,11 +7,11 @@ import { Doc, Opt } from '../../../fields/Doc'; import { DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { DragManager } from '../../util/DragManager'; import { StyleProp } from '../StyleProvider'; -import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView'; +import { DocumentView } from '../nodes/DocumentView'; +import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import './CollectionCarouselView.scss'; import { CollectionSubView } from './CollectionSubView'; -import { FieldViewProps } from '../nodes/FieldView'; @observer export class CollectionCarouselView extends CollectionSubView() { @@ -41,7 +41,7 @@ export class CollectionCarouselView extends CollectionSubView() { e.stopPropagation(); this.layoutDoc._carousel_index = (NumCast(this.layoutDoc._carousel_index) - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length; }; - captionStyleProvider = (doc: Doc | undefined, captionProps: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => { + captionStyleProvider = (doc: Doc | undefined, captionProps: Opt<FieldViewProps>, property: string): any => { // first look for properties on the document in the carousel, then fallback to properties on the container const childValue = doc?.['caption-' + property] ? this._props.styleProvider?.(doc, captionProps, property) : undefined; return childValue ?? this._props.styleProvider?.(this.layoutDoc, captionProps, property); @@ -66,9 +66,9 @@ export class CollectionCarouselView extends CollectionSubView() { NativeWidth={returnZero} NativeHeight={returnZero} layout_fitWidth={undefined} - setContentView={undefined} - onDoubleClick={this.onContentDoubleClick} - onClick={this.onContentClick} + setContentViewBox={undefined} + onDoubleClickScript={this.onContentDoubleClick} + onClickScript={this.onContentClick} isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive} isContentActive={this._props.childContentsActive ?? this._props.isContentActive() === false ? returnFalse : emptyFunction} hideCaptions={!!carouselShowsCaptions} // hide captions if the carousel is configured to show the captions @@ -78,7 +78,6 @@ export class CollectionCarouselView extends CollectionSubView() { Document={curDoc.layout} TemplateDataDocument={DocCast(curDoc.layout.resolvedDataDoc)} PanelHeight={this.panelHeight} - bringToFront={returnFalse} /> </div> {!carouselShowsCaptions ? null : ( diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 874cdffd9..87973fd81 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import * as GoldenLayout from '../../../client/goldenLayout'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; -import { AclAdmin, AclEdit } from '../../../fields/DocSymbols'; +import { AclAdmin, AclEdit, DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; @@ -277,8 +277,8 @@ export class CollectionDockingView extends CollectionSubView() { } setupGoldenLayout = async () => { if (this._unmounting) return; - //const config = StrCast(this._props.Document.dockingConfig, JSON.stringify(DashboardView.resetDashboard(this._props.Document))); - const config = StrCast(this._props.Document.dockingConfig); + //const config = StrCast(this.Document.dockingConfig, JSON.stringify(DashboardView.resetDashboard(this.Document))); + const config = StrCast(this.Document.dockingConfig); if (config) { const matches = config.match(/\"documentId\":\"[a-z0-9-]+\"/g); const docids = matches?.map(m => m.replace('"documentId":"', '').replace('"', '')) ?? []; @@ -322,7 +322,7 @@ export class CollectionDockingView extends CollectionSubView() { ); new _global.ResizeObserver(this.onResize).observe(this._containerRef.current); this._reactionDisposer = reaction( - () => StrCast(this._props.Document.dockingConfig), + () => StrCast(this.Document.dockingConfig), config => { if (!this._goldenLayout || this._ignoreStateChange !== config) { // bcz: TODO! really need to diff config with ignoreStateChange and modify the current goldenLayout instead of building a new one. @@ -381,7 +381,7 @@ export class CollectionDockingView extends CollectionSubView() { .map(id => DocServer.GetCachedRefField(id)) .filter(f => f) .map(f => f as Doc); - const changesMade = this._props.Document.dockingConfig !== json; + const changesMade = this.Document.dockingConfig !== json; if (changesMade) { if (![AclAdmin, AclEdit].includes(GetEffectiveAcl(this.dataDoc))) { this.layoutDoc.dockingConfig = json; @@ -431,7 +431,7 @@ export class CollectionDockingView extends CollectionSubView() { }; public CaptureThumbnail() { - const content = this._props.DocumentView?.()?.ContentDiv; + const content = this.DocumentView?.()?.ContentDiv; if (content) { const _width = Number(getComputedStyle(content).width.replace('px', '')); const _height = Number(getComputedStyle(content).height.replace('px', '')); @@ -449,7 +449,7 @@ export class CollectionDockingView extends CollectionSubView() { if (clone) { const cloned = await Doc.MakeClone(doc); Array.from(cloned.map.entries()).map(entry => (json = json.replace(entry[0], entry[1][Id]))); - Doc.GetProto(cloned.clone).dockingConfig = json; + cloned.clone[DocData].dockingConfig = json; return DashboardView.openDashboard(cloned.clone); } const matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g); @@ -463,7 +463,7 @@ export class CollectionDockingView extends CollectionSubView() { const newtab = origtabdocs.length ? Doc.MakeCopy(origtab, true, undefined, true) : Doc.MakeEmbedding(origtab); const newtabdocs = origtabdocs.map(origtabdoc => Doc.MakeEmbedding(origtabdoc)); if (newtabdocs.length) { - Doc.GetProto(newtab).data = new List<Doc>(newtabdocs); + newtab[DocData].data = new List<Doc>(newtabdocs); newtabdocs.forEach(ntab => Doc.SetContainer(ntab, newtab)); } json = json.replace(origtab[Id], newtab[Id]); @@ -479,7 +479,7 @@ export class CollectionDockingView extends CollectionSubView() { stateChanged = () => { this._ignoreStateChange = JSON.stringify(this._goldenLayout.toConfig()); const json = JSON.stringify(this._goldenLayout.toConfig()); - const changesMade = this._props.Document.dockingConfig !== json; + const changesMade = this.Document.dockingConfig !== json; return changesMade; }; @@ -490,7 +490,7 @@ export class CollectionDockingView extends CollectionSubView() { // if you close a tab that is not embedded somewhere else (an embedded Doc can be opened simultaneously in a tab), then add the tab to recently closed if (tab.DashDoc.embedContainer === this.Document) tab.DashDoc.embedContainer = undefined; if (!tab.DashDoc.embedContainer) Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true); - Doc.RemoveDocFromList(Doc.GetProto(tab.DashDoc), 'proto_embeddings', tab.DashDoc); + Doc.RemoveDocFromList(tab.DashDoc[DocData], 'proto_embeddings', tab.DashDoc); } if (CollectionDockingView.Instance) { const dview = CollectionDockingView.Instance.Document; diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx index 8627ba650..41c5d5b42 100644 --- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx +++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx @@ -71,7 +71,7 @@ export class CollectionMasonryViewFieldRow extends ObservableReactComponent<CMVF if (ele) { this._ele = ele; this._props.observeHeight(ele); - this._dropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this)); + this._dropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this), this._props.Document); } }; @action diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 98ae01591..0f90818ef 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -19,14 +19,17 @@ import { undoBatch } from '../../util/UndoManager'; import { AntimodeMenu } from '../AntimodeMenu'; import { EditableView } from '../EditableView'; import { MainView } from '../MainView'; -import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; +import { DocumentView, DocumentViewInternal, returnEmptyDocViewList } from '../nodes/DocumentView'; import { DefaultStyleProvider } from '../StyleProvider'; import { CollectionLinearView } from './collectionLinear'; import './CollectionMenu.scss'; +import { DocData } from '../../../fields/DocSymbols'; interface CollectionMenuProps { panelHeight: () => number; panelWidth: () => number; + toggleTopBar: () => void; + topBarHeight: () => number; } @observer @@ -66,15 +69,6 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> { }; @action - toggleTopBar = () => { - if (SettingsManager.Instance.headerBarHeight > 0) { - SettingsManager.Instance.headerBarHeight = 0; - } else { - SettingsManager.Instance.headerBarHeight = 60; - } - }; - - @action toggleProperties = () => { if (MainView.Instance.propertiesWidth() > 0) { SettingsManager.Instance.propertiesWidth = 0; @@ -95,16 +89,14 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> { <div className="collectionMenu-contMenuButtons" ref={this._docBtnRef} style={{ height: this._props.panelHeight() }}> <CollectionLinearView Document={selDoc} + docViewPath={returnEmptyDocViewList} fieldKey="data" dropAction="embed" - setHeight={returnFalse} styleProvider={DefaultStyleProvider} - bringToFront={emptyFunction} select={emptyFunction} isContentActive={returnTrue} isAnyChildContentActive={returnFalse} isSelected={returnFalse} - docViewPath={returnEmptyDoclist} moveDocument={returnFalse} addDocument={returnFalse} addDocTab={DocumentViewInternal.addDocTabFunc} @@ -125,8 +117,8 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> { } render() { - const headerIcon = SettingsManager.Instance.headerBarHeight > 0 ? 'angle-double-up' : 'angle-double-down'; - const headerTitle = SettingsManager.Instance.headerBarHeight > 0 ? 'Close Header Bar' : 'Open Header Bar'; + 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'; @@ -136,8 +128,8 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> { toggleType={ToggleType.BUTTON} type={Type.PRIM} color={SettingsManager.userColor} - onClick={this.toggleTopBar} - toggleStatus={SettingsManager.Instance.headerBarHeight > 0} + onClick={this.props.toggleTopBar} + toggleStatus={this.props.topBarHeight() > 0} icon={<FontAwesomeIcon icon={headerIcon} size="lg" />} tooltip={headerTitle} /> @@ -221,7 +213,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu params: ['target', 'source'], title: 'set content', script: 'getProto(this.target).data = copyField(this.source);', - immediate: undoBatch((source: Doc[]) => (Doc.GetProto(this.target).data = new List<Doc>(source))), + immediate: undoBatch((source: Doc[]) => (this.target[DocData].data = new List<Doc>(source))), initialize: emptyFunction, }; _onClickCommand = { diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 302ccd2db..b8133806f 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, Field, Opt } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Copy, Id } from '../../../fields/FieldSymbols'; @@ -18,14 +18,15 @@ import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { LightboxView } from '../LightboxView'; -import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView'; -import { FieldViewProps } from '../nodes/FieldView'; +import { DocumentView } from '../nodes/DocumentView'; +import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; import './CollectionNoteTakingView.scss'; import { CollectionNoteTakingViewColumn } from './CollectionNoteTakingViewColumn'; import { CollectionNoteTakingViewDivider } from './CollectionNoteTakingViewDivider'; import { CollectionSubView } from './CollectionSubView'; +import { JsxElement } from 'typescript'; const _global = (window /* browser */ || global) /* node */ as any; /** @@ -51,7 +52,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } @computed get chromeHidden() { - return BoolCast(this.layoutDoc.chromeHidden) || this._props.onBrowseClick?.() ? true : false; + return BoolCast(this.layoutDoc.chromeHidden) || this._props.onBrowseClickScript?.() ? true : false; } // columnHeaders returns the list of SchemaHeaderFields currently being used by the layout doc to render the columns @computed get colHeaderData() { @@ -189,7 +190,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { }; // let's dive in and get the actual document we want to drag/move around - focusDocument = (doc: Doc, options: DocFocusOptions) => { + focusDocument = (doc: Doc, options: FocusViewOptions) => { Doc.BrushDoc(doc); const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); if (found) { @@ -203,7 +204,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } }; - styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => { + styleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => { switch (property) { case StyleProp.BoxShadow: if (doc && DragManager.docsBeingDragged.includes(doc)) { @@ -238,7 +239,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { PanelWidth={width} PanelHeight={height} styleProvider={this.styleProvider} - docViewPath={this._props.docViewPath} + containerViewPath={this.childContainerViewPath} layout_fitWidth={this._props.childLayoutFitWidth} isContentActive={emptyFunction} onKey={this.onKeyDown} @@ -254,9 +255,9 @@ export class CollectionNoteTakingView extends CollectionSubView() { rootSelected={this.rootSelected} layout_showTitle={this._props.childlayout_showTitle} dragAction={StrCast(this.layoutDoc.childDragAction) as dropActionType} - onClick={this.onChildClickHandler} - onBrowseClick={this._props.onBrowseClick} - onDoubleClick={this.onChildDoubleClickHandler} + onClickScript={this.onChildClickHandler} + onBrowseClickScript={this._props.onBrowseClickScript} + onDoubleClickScript={this.onChildDoubleClickHandler} ScreenToLocalTransform={noteTakingDocTransform} focus={this.focusDocument} childFilters={this.childDocFilters} @@ -267,10 +268,9 @@ export class CollectionNoteTakingView extends CollectionSubView() { addDocument={this._props.addDocument} moveDocument={this._props.moveDocument} removeDocument={this._props.removeDocument} - contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents) as any} + contentPointerEvents={StrCast(this.layoutDoc.childContentPointerEvents) as any} whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged} addDocTab={this._props.addDocTab} - bringToFront={returnFalse} pinToPres={this._props.pinToPres} /> ); @@ -407,11 +407,10 @@ export class CollectionNoteTakingView extends CollectionSubView() { @undoBatch onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { - const docView = fieldProps.DocumentView?.(); - if (docView && (e.ctrlKey || docView.Document._createDocOnCR) && ['Enter'].includes(e.key)) { + if ((e.ctrlKey || fieldProps.Document._createDocOnCR) && ['Enter'].includes(e.key)) { e.stopPropagation?.(); - const newDoc = Doc.MakeCopy(docView.Document, true); - Doc.GetProto(newDoc).text = undefined; + const newDoc = Doc.MakeCopy(fieldProps.Document, true); + newDoc[DocData].text = undefined; FormattedTextBox.SetSelectOnLoad(newDoc); return this.addDocument?.(newDoc); } @@ -443,7 +442,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } return true; } - } else if (de.complete.linkDragData?.dragDocument.embedContainer === this._props.Document && de.complete.linkDragData?.linkDragView?.CollectionFreeFormDocumentView) { + } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.Document && de.complete.linkDragData?.linkDragView?.CollectionFreeFormDocumentView) { const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' }); if (!this._props.addDocument?.(source)) e.preventDefault(); de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed @@ -503,6 +502,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { const type = 'number'; return ( <CollectionNoteTakingViewColumn + key={heading?.heading ?? 'unset'} unobserveHeight={ref => this.refList.splice(this.refList.indexOf(ref), 1)} observeHeight={ref => { if (ref) { @@ -511,7 +511,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { action((entries: any) => { if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.IsDragging) { const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', ''))))); - if (!LightboxView.IsLightboxDocView(this._props.docViewPath())) { + if (!LightboxView.Contains(this.DocumentView?.())) { this._props.setHeight?.(height); } } @@ -536,7 +536,6 @@ export class CollectionNoteTakingView extends CollectionSubView() { dividerWidth={this.DividerWidth} maxColWidth={this.maxColWidth} availableWidth={this.availableWidth} - key={heading?.heading ?? 'unset'} headings={this.headings} heading={heading?.heading ?? 'unset'} headingObject={heading} @@ -598,14 +597,11 @@ export class CollectionNoteTakingView extends CollectionSubView() { @computed get renderedSections() { TraceMobx(); const sections = Array.from(this.Sections.entries()); - return sections.map((sec, i) => ( - <> - {this.sectionNoteTaking(sec[0], sec[1])} - {i === sections.length - 1 ? null : ( // - <CollectionNoteTakingViewDivider key={`divider${i}`} isContentActive={this.isContentActive} index={i} setColumnStartXCoords={this.setColumnStartXCoords} xMargin={this.xMargin} /> - )} - </> - )); + return sections.reduce((list, sec, i) => { + list.push(this.sectionNoteTaking(sec[0], sec[1])); + i !== sections.length - 1 && list.push(<CollectionNoteTakingViewDivider key={`divider${i}`} isContentActive={this.isContentActive} index={i} setColumnStartXCoords={this.setColumnStartXCoords} xMargin={this.xMargin} />); + return list; + }, [] as JSX.Element[]); } @computed get nativeWidth() { @@ -643,8 +639,8 @@ export class CollectionNoteTakingView extends CollectionSubView() { onDragOver={e => this.onPointerMove(true, e.clientX, e.clientY)} onDrop={this.onExternalDrop.bind(this)} onContextMenu={this.onContextMenu} - onWheel={e => this._props.isContentActive(true) && e.stopPropagation()}> - {this.renderedSections} + onWheel={e => this._props.isContentActive() && e.stopPropagation()}> + <>{this.renderedSections}</> </div> ); } diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx index 3f6d3c82e..38846c79d 100644 --- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx @@ -81,7 +81,7 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV if (ele) { this._ele = ele; this._props.observeHeight(ele); - this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this)); + this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this), this._props.Document); } }; @@ -90,11 +90,11 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV } @undoBatch - columnDrop = action((e: Event, de: DragManager.DropEvent) => { + columnDrop = (e: Event, de: DragManager.DropEvent) => { const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) }; drop.docs?.forEach(d => Doc.SetInPlace(d, this._props.pivotField, drop.val, false)); return true; - }); + }; getValue = (value: string): any => { const parsed = parseInt(value); diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index b1d379631..d0df77cbe 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -48,7 +48,7 @@ export class CollectionPileView extends CollectionSubView() { removePileDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => { (doc instanceof Doc ? [doc] : doc).forEach(d => Doc.deiconifyView(d)); const ret = this._props.moveDocument?.(doc, targetCollection, addDoc) || false; - if (ret && !DocListCast(this.dataDoc[this.fieldKey ?? 'data']).length) this._props.DocumentView?.()._props.removeDocument?.(this.Document); + if (ret && !DocListCast(this.dataDoc[this.fieldKey ?? 'data']).length) this.DocumentView?.()._props.removeDocument?.(this.Document); return ret; }; diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 22a67c501..5c47d4b9e 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -3,6 +3,7 @@ import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; import { Doc, Opt } from '../../../fields/Doc'; +import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; @@ -23,17 +24,17 @@ import { undoBatch, UndoManager } from '../../util/UndoManager'; import { CollectionSubView } from '../collections/CollectionSubView'; import { LightboxView } from '../LightboxView'; import { AudioWaveform } from '../nodes/audio/AudioWaveform'; -import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; +import { DocumentView, OpenWhere } from '../nodes/DocumentView'; +import { FocusFuncType, FocusViewOptions, StyleProviderFuncType } from '../nodes/FieldView'; import { LabelBox } from '../nodes/LabelBox'; import { VideoBox } from '../nodes/VideoBox'; import { ObservableReactComponent } from '../ObservableReactComponent'; import './CollectionStackedTimeline.scss'; -import { FieldViewProps } from '../nodes/FieldView'; export type CollectionStackedTimelineProps = { Play: () => void; Pause: () => void; - playLink: (linkDoc: Doc, options: DocFocusOptions) => void; + playLink: (linkDoc: Doc, options: FocusViewOptions) => void; playFrom: (seekTimeInSeconds: number, endTime?: number) => void; playing: () => boolean; thumbnails?: () => string[]; @@ -162,7 +163,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack makeDocUnfiltered = (doc: Doc) => this.childDocList?.some(item => item === doc); - getView = async (doc: Doc, options: DocFocusOptions): Promise<Opt<DocumentView>> => + 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)); @@ -427,8 +428,8 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack _isTimelineLabel: true, layout_borderRounding: anchorEndTime === undefined ? '100%' : undefined, }); - Doc.GetProto(anchor)[startTag] = anchorStartTime; - Doc.GetProto(anchor)[endTag] = anchorEndTime; + anchor[DocData][startTag] = anchorStartTime; + anchor[DocData][endTag] = anchorEndTime; if (addAsAnnotation) { if (Cast(dataDoc[fieldKey], listSpec(Doc), null)) { Cast(dataDoc[fieldKey], listSpec(Doc), []).push(anchor); @@ -579,7 +580,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack const timespan = Math.max(0, Math.min(end - this.clipStart, this.clipEnd)) - Math.max(0, start - this.clipStart); const width = (timespan / this.clipDuration) * this.timelineContentWidth; const height = this._props.PanelHeight() / maxLevel; - return this._props.Document.hideAnchors ? null : ( + return this.Document.hideAnchors ? null : ( <div className={'collectionStackedTimeline-marker-timeline'} key={d.anchor[Id]} @@ -691,8 +692,8 @@ interface StackedTimelineAnchorProps { width: number; height: number; toTimeline: (screen_delta: number, width: number) => number; - styleProvider?: StyleProviderFunc; - playLink: (linkDoc: Doc, options: DocFocusOptions) => void; + styleProvider?: StyleProviderFuncType; + playLink: (linkDoc: Doc, options: FocusViewOptions) => void; setTime: (time: number) => void; startTag: string; endTag: string; @@ -701,7 +702,7 @@ interface StackedTimelineAnchorProps { isDocumentActive?: () => boolean | undefined; ScreenToLocalTransform: () => Transform; _timeline: HTMLDivElement | null; - focus: DocFocusFunc; + focus: FocusFuncType; currentTimecode: () => number; isSelected: () => boolean; stackedTimeline: CollectionStackedTimeline; @@ -810,7 +811,7 @@ class StackedTimelineAnchor extends ObservableReactComponent<StackedTimelineAnch // renders anchor LabelBox renderInner = computedFn(function (this: StackedTimelineAnchor, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), screenXf: () => Transform, width: () => number, height: () => number) { const anchor = observable({ view: undefined as Opt<DocumentView> | null }); - const focusFunc = (doc: Doc, options: DocFocusOptions): number | undefined => { + const focusFunc = (doc: Doc, options: FocusViewOptions): number | undefined => { this._props.playLink(mark, options); return undefined; }; @@ -825,7 +826,7 @@ class StackedTimelineAnchor extends ObservableReactComponent<StackedTimelineAnch ref={action((r: DocumentView | null) => (anchor.view = r))} Document={mark} TemplateDataDocument={undefined} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} pointerEvents={this.noEvents ? returnNone : undefined} styleProvider={this._props.styleProvider} renderDepth={this._props.renderDepth + 1} @@ -842,11 +843,10 @@ class StackedTimelineAnchor extends ObservableReactComponent<StackedTimelineAnch searchFilterDocs={returnEmptyDoclist} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} - onClick={script} - onDoubleClick={this._props.layoutDoc.autoPlayAnchors ? undefined : doublescript} + onClickScript={script} + onDoubleClickScript={this._props.layoutDoc.autoPlayAnchors ? undefined : doublescript} ignoreAutoHeight={false} hideResizeHandles={true} - bringToFront={emptyFunction} contextMenuItems={this.contextMenuItems} /> ), diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 995f071ca..89e72152a 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -24,8 +24,8 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from '../EditableView'; import { LightboxView } from '../LightboxView'; import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; -import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView'; -import { FieldViewProps } from '../nodes/FieldView'; +import { DocumentView } from '../nodes/DocumentView'; +import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; import { CollectionMasonryViewFieldRow } from './CollectionMasonryViewFieldRow'; @@ -203,7 +203,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection componentDidMount() { super.componentDidMount?.(); - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); // reset section headers when a new filter is inputted this._pivotFieldDisposer = reaction( @@ -249,7 +249,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection }; // let's dive in and get the actual document we want to drag/move around - focusDocument = (doc: Doc, options: DocFocusOptions) => { + focusDocument = (doc: Doc, options: FocusViewOptions) => { Doc.BrushDoc(doc); const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); @@ -265,7 +265,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection return undefined; }; - styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => { + styleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => { if (property === StyleProp.Opacity && doc) { if (this._props.childOpacity) { return this._props.childOpacity(); @@ -278,18 +278,17 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection }; @undoBatch onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { - const docView = fieldProps.DocumentView?.(); - if (docView && ['Enter'].includes(e.key) && e.ctrlKey) { + if (['Enter'].includes(e.key) && e.ctrlKey) { e.stopPropagation?.(); const below = !e.altKey && e.key !== 'Tab'; - const layout_fieldKey = StrCast(docView.LayoutFieldKey); - const newDoc = Doc.MakeCopy(docView.Document, true); - const dataField = docView.Document[Doc.LayoutFieldKey(newDoc)]; + const layout_fieldKey = StrCast(fieldProps.fieldKey); + const newDoc = Doc.MakeCopy(fieldProps.Document, true); + const dataField = fieldProps.Document[Doc.LayoutFieldKey(newDoc)]; newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined; - if (layout_fieldKey !== 'layout' && docView.Document[layout_fieldKey] instanceof Doc) { - newDoc[layout_fieldKey] = docView.Document[layout_fieldKey]; + if (layout_fieldKey !== 'layout' && fieldProps.Document[layout_fieldKey] instanceof Doc) { + newDoc[layout_fieldKey] = fieldProps.Document[layout_fieldKey]; } - Doc.GetProto(newDoc).text = undefined; + newDoc[DocData].text = undefined; FormattedTextBox.SetSelectOnLoad(newDoc); return this.addDocument?.(newDoc); } @@ -325,13 +324,13 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection renderDepth={this._props.renderDepth + 1} PanelWidth={panelWidth} PanelHeight={panelHeight} - pointerEvents={this._props.DocumentView?.()._props.onClick?.() ? returnNone : undefined} // if the stack has an onClick, then we don't want the contents to be interactive (see CollectionPileView) + pointerEvents={this.DocumentView?.()._props.onClickScript?.() ? returnNone : undefined} // if the stack has an onClick, then we don't want the contents to be interactive (see CollectionPileView) styleProvider={this.styleProvider} - docViewPath={this._props.docViewPath} + containerViewPath={this.childContainerViewPath} layout_fitWidth={this.childFitWidth} isContentActive={doc.onClick ? this.isChildButtonContentActive : this.isChildContentActive} onKey={this.onKeyDown} - onBrowseClick={this._props.onBrowseClick} + onBrowseClickScript={this._props.onBrowseClickScript} isDocumentActive={this.isContentActive} LayoutTemplate={this._props.childLayoutTemplate} LayoutTemplateString={this._props.childLayoutString} @@ -342,8 +341,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection rootSelected={this.rootSelected} layout_showTitle={this._props.childlayout_showTitle} dragAction={(this.layoutDoc.childDragAction ?? this._props.childDragAction) as dropActionType} - onClick={this.onChildClickHandler} - onDoubleClick={this.onChildDoubleClickHandler} + onClickScript={this.onChildClickHandler} + onDoubleClickScript={this.onChildDoubleClickHandler} ScreenToLocalTransform={stackedDocTransform} focus={this.focusDocument} childFilters={this.childDocFilters} @@ -356,10 +355,9 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection addDocument={this._props.addDocument} moveDocument={this._props.moveDocument} removeDocument={this._props.removeDocument} - contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents) as any} + contentPointerEvents={StrCast(this.layoutDoc.childContentPointerEvents) as any} whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged} addDocTab={this._props.addDocTab} - bringToFront={returnFalse} pinToPres={this._props.pinToPres} /> ); @@ -469,7 +467,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection } return true; } - } else if (de.complete.linkDragData?.dragDocument.embedContainer === this._props.Document && de.complete.linkDragData?.linkDragView?.CollectionFreeFormDocumentView) { + } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.Document && de.complete.linkDragData?.linkDragView?.CollectionFreeFormDocumentView) { const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' }); if (!this._props.addDocument?.(source)) e.preventDefault(); de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed @@ -540,7 +538,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection action((entries: any) => { if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.IsDragging) { const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', ''))))); - if (!LightboxView.IsLightboxDocView(this._props.docViewPath())) { + if (!LightboxView.Contains(this.DocumentView?.())) { this._props.setHeight?.(height); } } @@ -552,7 +550,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection addDocument={this.addDocument} chromeHidden={this.chromeHidden} colHeaderData={this.colHeaderData} - Document={this._props.Document} + Document={this.Document} TemplateDataDocument={this._props.TemplateDataDocument} renderChildren={this.children} columnWidth={this.columnWidth} @@ -584,7 +582,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection return ( <CollectionMasonryViewFieldRow showHandle={first} - Document={this._props.Document} + Document={this.Document} chromeHidden={this.chromeHidden} pivotField={this.pivotField} unobserveHeight={ref => this.refList.splice(this.refList.indexOf(ref), 1)} @@ -671,7 +669,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection addDocument={this._props.addDocument} moveDocument={this._props.moveDocument} addDocTab={this._props.addDocTab} - onBrowseClick={this._props.onBrowseClick} + onBrowseClickScript={this._props.onBrowseClickScript} pinToPres={emptyFunction} rootSelected={this.rootSelected} removeDocument={this._props.removeDocument} @@ -681,9 +679,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection renderDepth={this._props.renderDepth} focus={emptyFunction} styleProvider={this._props.styleProvider} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} whenChildContentsActiveChanged={emptyFunction} - bringToFront={emptyFunction} childFilters={this._props.childFilters} childFiltersByRanges={this._props.childFiltersByRanges} searchFilterDocs={this._props.searchFilterDocs} @@ -739,7 +736,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection onWheel={e => this.isContentActive() && e.stopPropagation()}> {this.renderedSections} {!this.showAddAGroup ? null : ( - <div key={`${this._props.Document[Id]}-addGroup`} className="collectionStackingView-addGroupButton" style={{ width: !this.isStackingView ? '100%' : this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}> + <div key={`${this.Document[Id]}-addGroup`} className="collectionStackingView-addGroupButton" style={{ width: !this.isStackingView ? '100%' : this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}> <EditableView {...editableViewProps} /> </div> )} diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 69f1c332d..c455f20d8 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -74,7 +74,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent< if (ele) { this._ele = ele; this._props.observeHeight(ele); - this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this)); + this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this), this._props.Document); } }; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 570330174..fdbd1cc90 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -62,17 +62,16 @@ export function CollectionSubView<X>(moreProps?: X) { } get dataDoc() { - return this._props.TemplateDataDocument instanceof Doc && this._props.Document.isTemplateForField - ? Doc.GetProto(this._props.TemplateDataDocument) - : this._props.Document.resolvedDataDoc - ? this._props.Document - : Doc.GetProto(this._props.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template + return this._props.TemplateDataDocument instanceof Doc && this.Document.isTemplateForField ? Doc.GetProto(this._props.TemplateDataDocument) : this.Document.resolvedDataDoc ? this.Document : Doc.GetProto(this.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template } + get childContainerViewPath() { + return this.DocumentView?.().docViewPath; + } // this returns whether either the collection is selected, or the template that it is part of is selected rootSelected = () => this._props.isSelected() || BoolCast(this._props.TemplateDataDocument && this._props.rootSelected?.()); - // The data field for rendering this collection will be on the this._props.Document unless we're rendering a template in which case we try to use props.TemplateDataDocument. + // The data field for rendering this collection will be on the this.Document unless we're rendering a template in which case we try to use props.TemplateDataDocument. // When a document has a TemplateDataDoc but it's not a template, then it contains its own rendering data, but needs to pass the TemplateDataDoc through // to its children which may be templates. // If 'annotationField' is specified, then all children exist on that field of the extension document, otherwise, they exist directly on the data document under 'fieldKey' @@ -93,14 +92,14 @@ export function CollectionSubView<X>(moreProps?: X) { @computed get childDocList() { return Cast(this.dataField, listSpec(Doc)); } - collectionFilters = () => this._focusFilters ?? StrListCast(this._props.Document._childFilters); - collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this._props.Document._childFiltersByRanges, listSpec('string'), []); + collectionFilters = () => this._focusFilters ?? StrListCast(this.Document._childFilters); + collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.Document._childFiltersByRanges, listSpec('string'), []); // child filters apply to the descendants of the documents in this collection childDocFilters = () => [...(this._props.childFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()]; // unrecursive filters apply to the documents in the collection, but no their children. See Utils.noRecursionHack unrecursiveDocFilters = () => [...(this._props.childFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])]; childDocRangeFilters = () => [...(this._props.childFiltersByRanges?.() || []), ...this.collectionRangeDocFilters()]; - searchFilterDocs = () => this._props.searchFilterDocs?.() ?? DocListCast(this._props.Document._searchFilterDocs); + searchFilterDocs = () => this._props.searchFilterDocs?.() ?? DocListCast(this.Document._searchFilterDocs); @computed.struct get childDocs() { TraceMobx(); let rawdocs: (Doc | Promise<Doc>)[] = []; @@ -123,7 +122,7 @@ export function CollectionSubView<X>(moreProps?: X) { const childDocFilters = this.childDocFilters(); const childFiltersByRanges = this.childDocRangeFilters(); const searchDocs = this.searchFilterDocs(); - if (this._props.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !childFiltersByRanges.length && !searchDocs.length)) { + if (this.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !childFiltersByRanges.length && !searchDocs.length)) { return childDocs.filter(cd => !cd.cookies); // remove any documents that require a cookie if there are no filters to provide one } @@ -132,9 +131,9 @@ export function CollectionSubView<X>(moreProps?: X) { // dragging facets const dragged = this._props.childFilters?.().some(f => f.includes(Utils.noDragDocsFilter)); if (dragged && SnappingManager.CanEmbed && DragManager.docsBeingDragged.includes(d)) return false; - let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this._props.Document).length > 0; + let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this.Document).length > 0; if (notFiltered) { - notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this._props.Document).length > 0; + notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this.Document).length > 0; const fieldKey = Doc.LayoutFieldKey(d); const annos = !Field.toString(Doc.LayoutField(d) as Field).includes(CollectionView.name); const data = d[annos ? fieldKey + '_annotations' : fieldKey]; @@ -167,7 +166,7 @@ export function CollectionSubView<X>(moreProps?: X) { @action protected async setCursorPosition(position: [number, number]) { let ind; - const doc = this._props.Document; + const doc = this.Document; const id = Doc.UserDoc()[Id]; const email = Doc.CurrentUserEmail; const pos = { x: position[0], y: position[1] }; @@ -197,13 +196,11 @@ export function CollectionSubView<X>(moreProps?: X) { @undoBatch protected onGesture(e: Event, ge: GestureUtils.GestureEvent) {} - protected onInternalPreDrop(e: Event, de: DragManager.DropEvent) { + protected onInternalPreDrop(e: Event, de: DragManager.DropEvent, dropAction: dropActionType) { if (de.complete.docDragData) { - // override the dropEvent's dropAction - const dropAction = this.layoutDoc.dropAction as dropActionType; // if the dropEvent's dragAction is, say 'embed', but we're just dragging within a collection, we may not actually want to make an embedding. // so we check if our collection has a dropAction set on it and if so, we use that instead. - if (dropAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this._props.Document && this.childDocs.includes(d))) { + if (dropAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this.Document && this.childDocs.includes(d))) { de.complete.docDragData.dropAction = dropAction; } e.stopPropagation(); @@ -467,7 +464,7 @@ export function CollectionSubView<X>(moreProps?: X) { } if (generatedDocuments.length) { // Creating a dash document - const isFreeformView = this._props.Document._type_collection === CollectionViewType.Freeform; + const isFreeformView = this.Document._type_collection === CollectionViewType.Freeform; const set = !isFreeformView ? generatedDocuments : generatedDocuments.length > 1 diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 7036ec41c..ee5147428 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -16,7 +16,8 @@ import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from '../EditableView'; -import { DocFocusOptions, DocumentView } from '../nodes/DocumentView'; +import { DocumentView } from '../nodes/DocumentView'; +import { FocusViewOptions } from '../nodes/FieldView'; import { PresBox } from '../nodes/trails'; import { CollectionSubView } from './CollectionSubView'; import './CollectionTimeView.scss'; @@ -38,7 +39,7 @@ export class CollectionTimeView extends CollectionSubView() { } componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); runInAction(() => { this._childClickedScript = ScriptField.MakeScript('openInLightbox(this)', { this: Doc.name }); this._viewDefDivClick = ScriptField.MakeScript('pivotColumnClick(this,payload)', { payload: 'any' }); @@ -68,7 +69,7 @@ export class CollectionTimeView extends CollectionSubView() { }; @action - scrollPreview = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: DocFocusOptions) => { + scrollPreview = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: FocusViewOptions) => { // if in preview, then override document's fields with view spec this._focusFilters = StrListCast(anchor.config_docFilters); this._focusRangeFilters = StrListCast(anchor.config_docRangeFilters); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 18e0b98ef..741013148 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -140,20 +140,20 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree if ((this._mainEle = ele)) this._treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.Document, this.onInternalPreDrop.bind(this)); }; - protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent) => { - const dropAction = this.layoutDoc.dropAction as dropActionType; + protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent, dropAction: dropActionType) => { const dragData = de.complete.docDragData; if (dragData) { const sameTree = Doc.AreProtosEqual(dragData.treeViewDoc, this.Document) ? true : false; const isAlreadyInTree = () => sameTree || dragData.draggedDocuments.some(d => d.embedContainer === this.Document && this.childDocs.includes(d)); - if (isAlreadyInTree() !== sameTree) { - console.log('WHAAAT'); - } dragData.dropAction = dropAction && !isAlreadyInTree() ? dropAction : sameTree && dragData.dropAction !== 'inSame' ? 'same' : dragData.dropAction; e.stopPropagation(); } }; + configDrag = (dragData: DragManager.DocumentDragData) => { + dragData.treeViewDoc = this.Document; + }; + screenToLocalTransform = () => this.ScreenToLocalBoxXf().translate(0, -this._headerHeight); @action @@ -169,7 +169,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree this._props.removeDocument?.(doc); if (ind > 0 && prev) { FormattedTextBox.SetSelectOnLoad(prev); - DocumentManager.Instance.getDocumentView(prev, this._props.DocumentView?.())?.select(false); + DocumentManager.Instance.getDocumentView(prev, this.DocumentView?.())?.select(false); } return true; } @@ -254,7 +254,6 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree moveDocument={returnFalse} removeDocument={returnFalse} whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} - bringToFront={returnFalse} /> ); } @@ -347,9 +346,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree renderDepth={this._props.renderDepth + 1} focus={emptyFunction} styleProvider={this._props.styleProvider} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} whenChildContentsActiveChanged={emptyFunction} - bringToFront={emptyFunction} childFilters={this._props.childFilters} childFiltersByRanges={this._props.childFiltersByRanges} searchFilterDocs={this._props.searchFilterDocs} @@ -447,20 +445,19 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree {!(this.Document instanceof Doc) || !this.treeChildren ? null : this.Document.treeView_HasOverlay ? ( <CollectionFreeFormView {...this._props} - setContentView={emptyFunction} + setContentViewBox={emptyFunction} NativeWidth={returnZero} NativeHeight={returnZero} pointerEvents={this._props.isContentActive() && SnappingManager.IsDragging ? returnAll : returnNone} isAnnotationOverlay={true} isAnnotationOverlayScrollable={true} - childDocumentsActive={this._props.isDocumentActive} + childDocumentsActive={this._props.isContentActive} fieldKey={this._props.fieldKey + '_annotations'} dropAction="move" select={emptyFunction} addDocument={this.addAnnotationDocument} removeDocument={this.remAnnotationDocument} moveDocument={this.moveAnnotationDocument} - bringToFront={emptyFunction} renderDepth={this._props.renderDepth + 1}> {this.content} </CollectionFreeFormView> diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 4a239e4b1..18eb4dd1f 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -13,7 +13,7 @@ import { dropActionType } from '../../util/DragManager'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; import { OpenWhere } from '../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { CollectionCalendarView } from './CollectionCalendarView'; @@ -33,7 +33,7 @@ import { CollectionLinearView } from './collectionLinear'; import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView'; import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView'; import { CollectionSchemaView } from './collectionSchema/CollectionSchemaView'; -interface CollectionViewProps_ extends FieldViewProps { +export interface CollectionViewProps extends React.PropsWithChildren<FieldViewProps> { isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc) isAnnotationOverlayScrollable?: boolean; // whether the annotation overlay can be vertically scrolled (just for tree views, currently) layoutEngine?: () => string; @@ -63,9 +63,8 @@ interface CollectionViewProps_ extends FieldViewProps { RemFromMap?: (treeViewDoc: Doc, index: number[]) => void; hierarchyIndex?: number[]; // hierarchical index of a document up to the rendering root (primarily used for tree views) } -export interface CollectionViewProps extends React.PropsWithChildren<CollectionViewProps_> {} @observer -export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & CollectionViewProps>() { +export class CollectionView extends ViewBoxAnnotatableComponent<CollectionViewProps>() implements ViewBoxInterface { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); } @@ -190,7 +189,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'hand-point-right' }); - if (!Doc.noviceMode && !this.Document.annotationOn) { + if (!Doc.noviceMode && !this.Document.annotationOn && !this._props.hideClickBehaviors) { const existingOnClick = cm.findByDescription('OnClick...'); const onClicks = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : []; const funcs = [ @@ -232,13 +231,9 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab childLayoutTemplate = () => this._props.childLayoutTemplate?.() || Cast(this.Document.childLayoutTemplate, Doc, null); isContentActive = (outsideReaction?: boolean) => this._isContentActive; - pointerEvents = () => { - const viewPath = this._props.DocumentView?.()?._props.docViewPath(); - return ( - this.layoutDoc._lockedPosition && // - viewPath?.lastElement()?.Document?._type_collection === CollectionViewType.Freeform - ); - }; + pointerEvents = () => + this.layoutDoc._lockedPosition && // + this.Document?._type_collection === CollectionViewType.Freeform; render() { TraceMobx(); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 80808be92..9bc3ef822 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -29,7 +29,8 @@ import { LightboxView } from '../LightboxView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; import { Colors } from '../global/globalEnums'; -import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; +import { DocumentView, OpenWhere, OpenWhereMod, returnEmptyDocViewList } from '../nodes/DocumentView'; +import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView'; import { KeyValueBox } from '../nodes/KeyValueBox'; import { DashFieldView } from '../nodes/formattedText/DashFieldView'; import { PinProps, PresBox, PresMovement } from '../nodes/trails'; @@ -37,7 +38,6 @@ import { CollectionDockingView } from './CollectionDockingView'; import { CollectionView } from './CollectionView'; import './TabDocView.scss'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; -import { FieldViewProps } from '../nodes/FieldView'; const _global = (window /* browser */ || global) /* node */ as any; interface TabDocViewProps { @@ -118,7 +118,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { titleEle.onchange = (e: any) => { undoable(() => { titleEle.size = e.currentTarget.value.length + 3; - Doc.GetProto(doc).title = e.currentTarget.value; + doc[DocData].title = e.currentTarget.value; }, 'edit tab title')(); }; @@ -416,7 +416,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { return tab !== undefined; }; @action - focusFunc = (doc: Doc, options: DocFocusOptions) => { + focusFunc = (doc: Doc, options: FocusViewOptions) => { if (!this.tab.header.parent._activeContentItem || this.tab.header.parent._activeContentItem !== this.tab.contentItem) { this.tab.header.parent.setActiveContentItem(this.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) } @@ -452,7 +452,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { hideTitle={this._props.keyValue} Document={this._document} TemplateDataDocument={!Doc.AreProtosEqual(this._document[DocData], this._document) ? this._document[DocData] : undefined} - onBrowseClick={DocumentView.exploreMode} + onBrowseClickScript={DocumentView.exploreMode} waitForDoubleClickToClick={this.waitForDoubleClick} isContentActive={this.isContentActive} isDocumentActive={returnFalse} @@ -469,8 +469,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { dontCenter={'y'} whenChildContentsActiveChanged={this.whenChildContentActiveChanges} focus={this.focusFunc} - docViewPath={returnEmptyDoclist} - bringToFront={emptyFunction} + containerViewPath={returnEmptyDoclist} pinToPres={TabDocView.PinDoc} /> {this.disableMinimap() ? null : <TabMinimapView key="minimap" addDocTab={this.addDocTab} PanelHeight={this.PanelHeight} PanelWidth={this.PanelWidth} background={this.miniMapColor} document={this._document} tabView={this.tabView} />} @@ -528,7 +527,7 @@ class TabMiniThumb extends React.Component<TabMiniThumbProps> { } @observer export class TabMinimapView extends ObservableReactComponent<TabMinimapViewProps> { - static miniStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => { + static miniStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string): any => { if (doc) { switch (property.split(':')[0]) { default: @@ -595,17 +594,15 @@ export class TabMinimapView extends ObservableReactComponent<TabMinimapViewProps <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this._props.background() }}> <CollectionFreeFormView Document={this._props.document} - docViewPath={returnEmptyDoclist} + docViewPath={returnEmptyDocViewList} childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this. noOverlay={true} // don't render overlay Docs since they won't scale - setHeight={returnFalse} isContentActive={emptyFunction} isAnyChildContentActive={returnFalse} select={emptyFunction} isSelected={returnFalse} dontRegisterView={true} fieldKey={Doc.LayoutFieldKey(this._props.document)} - bringToFront={emptyFunction} addDocument={returnFalse} moveDocument={returnFalse} removeDocument={returnFalse} diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 01b80e209..be5737a25 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -4,7 +4,7 @@ import { IconButton, Size } from 'browndash-components'; import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Utils, emptyFunction, lightOrDark, return18, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, simulateMouseClick } from '../../../Utils'; +import { Utils, emptyFunction, lightOrDark, return18, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick } from '../../../Utils'; import { Doc, DocListCast, Field, FieldResult, Opt, StrListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; @@ -27,8 +27,8 @@ import { UndoManager, undoBatch, undoable } from '../../util/UndoManager'; import { EditableView } from '../EditableView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { StyleProp } from '../StyleProvider'; -import { DocumentView, DocumentViewInternal, DocumentViewInternalProps, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; -import { FieldViewProps } from '../nodes/FieldView'; +import { DocumentView, DocumentViewInternal, OpenWhere } from '../nodes/DocumentView'; +import { FieldViewProps, StyleProviderFuncType } from '../nodes/FieldView'; import { KeyValueBox } from '../nodes/KeyValueBox'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; @@ -62,7 +62,7 @@ export interface TreeViewProps { ScreenToLocalTransform: () => Transform; contextMenuItems?: { script: ScriptField; filter: ScriptField; icon: string; label: string }[]; dontRegisterView?: boolean; - styleProvider?: StyleProviderFunc | undefined; + styleProvider?: StyleProviderFuncType | undefined; treeViewHideHeaderFields: () => boolean; renderedIds: string[]; // list of document ids rendered used to avoid unending expansion of items in a cycle onCheckedClick?: () => ScriptField; @@ -198,7 +198,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { const ind = DocListCast(this.dataDoc[key]).indexOf(doc instanceof Doc ? doc : doc.lastElement()); const res = (doc instanceof Doc ? [doc] : doc).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._props.DocumentView?.())?.select(false); + res && ind > 0 && DocumentManager.Instance.getDocumentView(DocListCast(this.dataDoc[key])[ind - 1], this.treeView.DocumentView?.())?.select(false); return res; }; @@ -282,12 +282,13 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { _treeEle: any; protected createTreeDropTarget = (ele: HTMLDivElement) => { this._treedropDisposer?.(); - ele && ((this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this), undefined, this.preTreeDrop.bind(this))), this.Document); + ele && ((this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this), this.Document, this.preTreeDrop.bind(this))), this.Document); if (this._treeEle) this._props.unobserveHeight(this._treeEle); this._props.observeHeight((this._treeEle = ele)); }; componentWillUnmount() { + this._treedropDisposer?.(); this._renderTimer && clearTimeout(this._renderTimer); Object.values(this._disposers).forEach(disposer => disposer?.()); this._treeEle && this._props.unobserveHeight(this._treeEle); @@ -339,11 +340,9 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { const before = pt[1] < rect.top + rect.height / 2; const inside = pt[0] > rect.left + rect.width * 0.33 || (!before && this.treeViewOpen && this.childDocs?.length); this._header.current!.className = 'treeView-header'; - if (!this.treeView.outlineMode || DragManager.DocDragData?.treeViewDoc === this.treeView.Document) { - if (inside) this._header.current!.className += ' treeView-header-inside'; - else if (before) this._header.current!.className += ' treeView-header-above'; - else if (!before) this._header.current!.className += ' treeView-header-below'; - } + if (inside) this._header.current!.className += ' treeView-header-inside'; + else if (before) this._header.current!.className += ' treeView-header-above'; + else if (!before) this._header.current!.className += ' treeView-header-below'; e.stopPropagation(); }; @@ -367,8 +366,9 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { _width: 1000, _height: 10, }); - Doc.GetProto(bullet).title = ComputedField.MakeFunction('this.text?.Text'); - Doc.GetProto(bullet).data = new List<Doc>([]); + const bulletData = bullet[DocData]; + bulletData.title = ComputedField.MakeFunction('this.text?.Text'); + bulletData.data = new List<Doc>([]); DocumentManager.Instance.AddViewRenderedCb(bullet, dv => dv.ComponentView?.setFocus?.()); return bullet; @@ -386,9 +386,8 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { return this._props.addDocument(folder); }; - preTreeDrop = (e: Event, de: DragManager.DropEvent) => { - const dragData = de.complete.docDragData; - dragData && (dragData.dropAction = this.treeView.Document === dragData.treeViewDoc ? 'same' : dragData.dropAction); + preTreeDrop = (e: Event, de: DragManager.DropEvent, docDropAction: dropActionType) => { + // fall through and let the CollectionTreeView handle this since treeView items have no special properties of their own }; @undoBatch @@ -415,7 +414,8 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { docDragData.dropAction, docDragData.removeDocument, docDragData.moveDocument, - docDragData.treeViewDoc === this.treeView.Document + docDragData.treeViewDoc === this.treeView.Document, + de.embedKey ); e.stopPropagation(); !added && e.preventDefault(); @@ -425,7 +425,16 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { }; dropping: boolean = false; - dropDocuments(droppedDocuments: Doc[], before: boolean, inside: number | boolean, dropAction: dropActionType, removeDocument: DragManager.RemoveFunction | undefined, moveDocument: DragManager.MoveFunction | undefined, forceAdd: boolean) { + dropDocuments( + droppedDocuments: Doc[], + before: boolean, + inside: number | boolean, + dropAction: dropActionType, + removeDocument: DragManager.RemoveFunction | undefined, + moveDocument: DragManager.MoveFunction | undefined, + forceAdd: boolean, + canEmbed?: boolean + ) { const parentAddDoc = (doc: Doc | Doc[]) => this._props.addDocument(doc, undefined, undefined, before); const localAdd = (doc: Doc | Doc[]) => { const innerAdd = (doc: Doc) => { @@ -437,9 +446,9 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && innerAdd(doc), true as boolean); }; const addDoc = inside ? localAdd : parentAddDoc; - const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same' || dropAction === 'inSame') && moveDocument; - const canAdd = (!this.treeView.outlineMode && !StrCast((inside ? this.Document : this._props.treeViewParent)?.treeView_FreezeChildren).includes('add')) || forceAdd; + const canAdd = !StrCast((inside ? this.Document : this._props.treeViewParent)?.treeView_FreezeChildren).includes('add') || forceAdd; if (canAdd && (dropAction !== 'inSame' || droppedDocuments.every(d => d.embedContainer === this._props.parentTreeView?.Document))) { + const move = (!dropAction || canEmbed || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same' || dropAction === 'inSame') && moveDocument; this._props.parentTreeView instanceof TreeView && (this._props.parentTreeView.dropping = true); const res = droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false); this._props.parentTreeView instanceof TreeView && (this._props.parentTreeView.dropping = false); @@ -601,7 +610,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { docs.sort((a, b) => (NumCast(a.zIndex) > NumCast(b.zIndex) ? 1 : -1)).forEach((d, i) => (d.zIndex = i)); } const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[key])) instanceof ComputedField; - const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true); + const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false); !dataIsComputed && added && Doc.SetContainer(doc, this.Document); return added; @@ -840,7 +849,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { ? folderOp : Doc.IsSystem(this.Document) ? [] - : this.treeView.fileSysMode && this.Document === Doc.GetProto(this.Document) + : this.treeView.fileSysMode && this.Document === this.Document[DocData] ? [openEmbedding, makeFolder] : this.Document._type_collection === CollectionViewType.Docking ? [] @@ -867,7 +876,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { e.preventDefault(); } }; - titleStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => { + titleStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string): any => { if (!doc || doc !== this.Document) return this._props?.treeView?._props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView const treeView = this.treeView; @@ -899,7 +908,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { } return treeView._props.styleProvider?.(doc, props, property); }; - embeddedStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => { + embeddedStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string): any => { if (property.startsWith(StyleProp.Decorations)) return null; return this._props?.treeView?._props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView }; @@ -973,17 +982,16 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { Document={this.Document} layout_fitWidth={returnTrue} scriptContext={this} - hideDecorationTitle={this.treeView.outlineMode} - hideResizeHandles={this.treeView.outlineMode} + hideDecorations={true} + hideClickBehaviors={true} styleProvider={this.titleStyleProvider} onClickScriptDisable="never" // tree docViews have a script to show fields, etc. - docViewPath={this.treeView._props.docViewPath} - treeViewDoc={this.treeView.Document} + containerViewPath={this.treeView.childContainerViewPath} addDocument={undefined} addDocTab={this._props.addDocTab} pinToPres={this.treeView._props.pinToPres} - onClick={this.onChildClick} - onDoubleClick={this.onChildDoubleClick} + onClickScript={this.onChildClick} + onDoubleClickScript={this.onChildDoubleClick} dragAction={this._props.dragAction} moveDocument={this.move} removeDocument={this._props.removeDoc} @@ -998,7 +1006,6 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { isDocumentActive={this._props.isContentActive} focus={this.refocus} whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged} - bringToFront={emptyFunction} disableBrushing={this.treeView._props.disableBrushing} hideLinkButton={BoolCast(this.treeView.Document.childHideLinkButton)} dontRegisterView={BoolCast(this.treeView.Document.childDontRegisterViews, this._props.dontRegisterView)} @@ -1040,7 +1047,19 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { key="titleheader" ref={this._header} onClick={this.ignoreEvent} - onPointerDown={this.ignoreEvent} + onPointerDown={e => { + this.treeView.isContentActive() && + setupMoveUpEvents( + this, + e, + () => { + this._dref?.startDragging(e.clientX, e.clientY, '' as any); + return true; + }, + returnFalse, + emptyFunction + ); + }} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}> <div @@ -1072,22 +1091,21 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { isContentActive={isActive} isDocumentActive={isActive} styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider} - hideTitle={asText} fitContentsToBox={returnTrue} - hideDecorationTitle={this.treeView.outlineMode} - hideResizeHandles={this.treeView.outlineMode} - onClick={this.onChildClick} - focus={this.refocus} - onKey={this.onKeyDown} + hideTitle={asText} + hideDecorations={true} + hideClickBehaviors={true} hideLinkButton={BoolCast(this.treeView.Document.childHideLinkButton)} dontRegisterView={BoolCast(this.treeView.Document.childDontRegisterViews, this._props.dontRegisterView)} ScreenToLocalTransform={this.docTransform} renderDepth={this._props.renderDepth + 1} - treeViewDoc={this.treeView?.Document} - docViewPath={this.treeView._props.docViewPath} + onClickScript={this.onChildClick} + onKey={this.onKeyDown} + containerViewPath={this.treeView.childContainerViewPath} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} + focus={this.refocus} addDocument={this._props.addDocument} moveDocument={this.move} removeDocument={this._props.removeDoc} @@ -1097,7 +1115,6 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { addDocTab={this._props.addDocTab} pinToPres={this.treeView._props.pinToPres} disableBrushing={this.treeView._props.disableBrushing} - bringToFront={returnFalse} scriptContext={this} /> </div> @@ -1142,7 +1159,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { const before = pt[1] < rect.top + rect.height / 2; const inside = this.treeView.fileSysMode && !this.Document.isFolder ? false : pt[0] > rect.left + rect.width * 0.33 || (!before && this.treeViewOpen && this.childDocs?.length ? true : false); - const docs = this.treeView.onTreeDrop(de, (docs: Doc[]) => this.dropDocuments(docs, before, inside, 'copy', undefined, undefined, false)); + const docs = this.treeView.onTreeDrop(de, (docs: Doc[]) => this.dropDocuments(docs, before, inside, 'copy', undefined, undefined, false, false)); }; render() { @@ -1209,7 +1226,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { move: DragManager.MoveFunction, dragAction: dropActionType, addDocTab: (doc: Doc, where: OpenWhere) => boolean, - styleProvider: undefined | StyleProviderFunc, + styleProvider: undefined | StyleProviderFuncType, screenToLocalXf: () => Transform, isContentActive: (outsideReaction?: boolean) => boolean, panelWidth: () => number, diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 5204633ea..f0a31a8c6 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -130,7 +130,7 @@ export class CollectionFreeFormLinkView extends ObservableReactComponent<Collect LinkManager.currentLink = this._props.LinkDocs[0]; this.toggleProperties(); // OverlayView.Instance.addElement( - // <LinkEditor sourceDoc={this._props.A._props.Document} linkDoc={this._props.LinkDocs[0]} + // <LinkEditor sourceDoc={this._props.A.Document} linkDoc={this._props.LinkDocs[0]} // showLinks={action(() => { })} // />, { x: 300, y: 300 }); }) @@ -204,8 +204,8 @@ export class CollectionFreeFormLinkView extends ObservableReactComponent<Collect const atop = this.visibleY(adiv); const btop = this.visibleY(bdiv); if (!a.width || !b.width) return undefined; - const aDocBounds = (A._props as any).DocumentView?.().getBounds() || { left: 0, right: 0, top: 0, bottom: 0 }; - const bDocBounds = (B._props as any).DocumentView?.().getBounds() || { left: 0, right: 0, top: 0, bottom: 0 }; + const aDocBounds = (A._props as any).DocumentView?.().getBounds || { left: 0, right: 0, top: 0, bottom: 0 }; + const bDocBounds = (B._props as any).DocumentView?.().getBounds || { left: 0, right: 0, top: 0, bottom: 0 }; const aleft = this.visibleX(adiv); const bleft = this.visibleX(bdiv); const aclipped = aleft !== a.left || atop !== a.top; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 95d521f65..e5b6c366f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -11,7 +11,7 @@ import './CollectionFreeFormLinksView.scss'; export class CollectionFreeFormLinksView extends React.Component { @computed get uniqueConnections() { return Array.from(new Set(DocumentManager.Instance.LinkedDocumentViews)) - .filter(c => !LightboxView.LightboxDoc || (LightboxView.IsLightboxDocView(c.a.docViewPath) && LightboxView.IsLightboxDocView(c.b.docViewPath))) + .filter(c => !LightboxView.LightboxDoc || (LightboxView.Contains(c.a) && LightboxView.Contains(c.b))) .map(c => <CollectionFreeFormLinkView key={c.l[Id]} A={c.a} B={c.b} LinkDocs={[c.l]} />); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx index ec8416303..69cbae86f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx @@ -1,4 +1,4 @@ -import { computed } from 'mobx'; +import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; @@ -18,6 +18,10 @@ export interface CollectionFreeFormPannableContentsProps { @observer export class CollectionFreeFormPannableContents extends React.Component<CollectionFreeFormPannableContentsProps> { + constructor(props: CollectionFreeFormPannableContentsProps) { + super(props); + makeObservable(this); + } @computed get presPaths() { return CollectionFreeFormView.ShowPresPaths ? PresBox.Instance.pathLines(this.props.Document) : null; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index 7d3acaea7..9e7d364ea 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -176,6 +176,11 @@ // touch action none means that the browser will handle none of the touch actions. this allows us to implement our own actions. touch-action: none; transform-origin: top left; + > svg { + height: 100%; + width: 100%; + margin: auto; + } .collectionfreeformview-placeholder { background: gray; @@ -270,34 +275,31 @@ padding: 10px; .msg { - position: relative; - // display: block; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -o-user-select: none; - user-select: none; - + position: relative; + // display: block; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -o-user-select: none; + user-select: none; } - + .gif-container { - position: relative; - margin-top: 5px; - // display: block; - - justify-content: center; - align-items: center; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -o-user-select: none; - user-select: none; - - + position: relative; + margin-top: 5px; + // display: block; + + justify-content: center; + align-items: center; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -o-user-select: none; + user-select: none; + .gif { background-color: transparent; height: 300px; } } - } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 881c80a1a..ec3ac4174 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,6 +1,6 @@ import { Bezier } from 'bezier-js'; import { Colors } from 'browndash-components'; -import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction, toJS } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; @@ -38,8 +38,8 @@ import { ActiveInkWidth, InkingStroke, SetActiveInkColor, SetActiveInkWidth } fr import { LightboxView } from '../../LightboxView'; import { CollectionFreeFormDocumentView, CollectionFreeFormDocumentViewWrapper } from '../../nodes/CollectionFreeFormDocumentView'; import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp'; -import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere } from '../../nodes/DocumentView'; -import { FieldViewProps } from '../../nodes/FieldView'; +import { DocumentView, OpenWhere } from '../../nodes/DocumentView'; +import { FieldViewProps, FocusViewOptions } from '../../nodes/FieldView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../../nodes/trails/PresBox'; import { CreateImage } from '../../nodes/WebBoxRenderer'; @@ -54,7 +54,7 @@ import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCurso import './CollectionFreeFormView.scss'; import { MarqueeView } from './MarqueeView'; -export type collectionFreeformViewProps = { +export interface collectionFreeformViewProps { NativeWidth?: () => number; NativeHeight?: () => number; originTopLeft?: boolean; @@ -65,14 +65,22 @@ export type collectionFreeformViewProps = { noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale) engineProps?: any; getScrollHeight?: () => number | undefined; -}; +} @observer export class CollectionFreeFormView extends CollectionSubView<Partial<collectionFreeformViewProps>>() { public get displayName() { - return 'CollectionFreeFormView(' + this._props.Document.title?.toString() + ')'; + return 'CollectionFreeFormView(' + this.Document.title?.toString() + ')'; } // this makes mobx trace() statements more descriptive + @observable _paintedId = 'id' + Utils.GenerateGuid().replace(/-/g, ''); + @computed get paintFunc() { + const paintFunc = StrCast(this.Document[DocData].paintFunc).trim(); + return !paintFunc + ? '' + : `const dashDiv = document.querySelector('#${this._paintedId}'); + (async () => { ${paintFunc} })()`; + } constructor(props: any) { super(props); makeObservable(this); @@ -162,7 +170,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return this._props.isAnnotationOverlay || this._props.originTopLeft ? 0 : this._props.PanelWidth() / 2 / scaling; // shift so pan position is at center of window for non-overlay collections } @computed get cachedCenteringShiftY(): number { - const dv = this._props.DocumentView?.(); + const dv = this.DocumentView?.(); const fitWidth = this._props.layout_fitWidth?.(this.Document) ?? dv?.layoutDoc.layout_fitWidth; const scaling = !this.nativeDimScaling ? 1 : this.nativeDimScaling; // if freeform has a native aspect, then the panel height needs to be adjusted to match it @@ -180,12 +188,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } public static gotoKeyframe(timer: NodeJS.Timeout | undefined, docs: Doc[], duration: number) { - if (timer) clearTimeout(timer); - return DocumentView.SetViewTransition(docs, 'all', duration, undefined, true); + return DocumentView.SetViewTransition(docs, 'all', duration, timer, undefined, true); } public static updateKeyframe(timer: NodeJS.Timeout | undefined, docs: Doc[], time: number) { - if (timer) clearTimeout(timer); - const newTimer = DocumentView.SetViewTransition(docs, 'all', 1000, undefined, true); + const newTimer = DocumentView.SetViewTransition(docs, 'all', 1000, timer, undefined, true); const timecode = Math.round(time); docs.forEach(doc => { CollectionFreeFormDocumentView.animFields.forEach(val => { @@ -223,7 +229,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @observable _keyframeEditing = false; @action setKeyFrameEditing = (set: boolean) => (this._keyframeEditing = set); getKeyFrameEditing = () => this._keyframeEditing; - onBrowseClickHandler = () => this._props.onBrowseClick?.() || ScriptCast(this.layoutDoc.onBrowseClick); + onBrowseClickHandler = () => this._props.onBrowseClickScript?.() || ScriptCast(this.layoutDoc.onBrowseClick); onChildClickHandler = () => this._props.childClickScript || ScriptCast(this.Document.onChildClick); onChildDoubleClickHandler = () => this._props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); elementFunc = () => this._layoutElements; @@ -250,7 +256,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection }; selectDocuments = (docs: Doc[]) => { SelectionManager.DeselectAll(); - docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this._props.DocumentView?.())).forEach(dv => dv && SelectionManager.SelectView(dv, true)); + docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).forEach(dv => dv && SelectionManager.SelectView(dv, true)); }; addDocument = (newBox: Doc | Doc[]) => { let retVal = false; @@ -288,20 +294,20 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return dispTime === -1 || curTime === -1 || (curTime - dispTime >= -1e-4 && curTime <= endTime); } - groupFocus = (anchor: Doc, options: DocFocusOptions) => { + groupFocus = (anchor: Doc, options: FocusViewOptions) => { options.docTransform = new Transform(-NumCast(this.layoutDoc[this.panXFieldKey]) + NumCast(anchor.x), -NumCast(this.layoutDoc[this.panYFieldKey]) + NumCast(anchor.y), 1); const res = this._props.focus(this.Document, options); options.docTransform = undefined; return res; }; - focus = (anchor: Doc, options: DocFocusOptions) => { + focus = (anchor: Doc, options: FocusViewOptions) => { if (this._lightboxDoc) return; if (anchor === this.Document) { - if (options.willZoomCentered && options.zoomScale) { - this.fitContentOnce(); - options.didMove = true; - } + // if (options.willZoomCentered && options.zoomScale) { + // this.fitContentOnce(); + // options.didMove = true; + // } } if (anchor.type !== DocumentType.CONFIG && !DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]).includes(anchor)) return; const xfToCollection = options?.docTransform ?? Transform.Identity(); @@ -321,7 +327,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } }; - getView = async (doc: Doc, options: DocFocusOptions): Promise<Opt<DocumentView>> => + getView = async (doc: Doc, options: FocusViewOptions): Promise<Opt<DocumentView>> => new Promise<Opt<DocumentView>>(res => { if (doc.hidden && this._lightboxDoc !== doc) options.didMove = !(doc.hidden = false); const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv)); @@ -409,7 +415,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @undoBatch internalLinkDrop(e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData) { - if (linkDragData.linkDragView.props.docViewPath().includes(this._props.docViewPath().lastElement())) { + if (this.DocumentView?.() && linkDragData.linkDragView.containerViewPath?.().includes(this.DocumentView())) { const [x, y] = this.screenToFreeformContentsXf.transformPoint(de.x, de.y); let added = false; // do nothing if link is dropped into any freeform view parent of dragged document @@ -467,7 +473,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return this.childLayoutPairs .map(pair => pair.layout) .reduce((cluster, cd) => { - const grouping = this._props.Document._freeform_useClusters ? NumCast(cd.layout_cluster, -1) : NumCast(cd.group, -1); + const grouping = this.Document._freeform_useClusters ? NumCast(cd.layout_cluster, -1) : NumCast(cd.group, -1); if (grouping !== -1) { const layoutDoc = Doc.Layout(cd); const cx = NumCast(cd.x) - this._clusterDistance / 2; @@ -484,9 +490,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection if (cluster !== -1) { const ptsParent = e; if (ptsParent) { - const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this._props.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === cluster); - const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this._props.DocumentView?.())!); - const { left, top } = clusterDocs[0].getBounds() || { left: 0, top: 0 }; + 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 { left, top } = clusterDocs[0].getBounds || { left: 0, top: 0 }; const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? 'embed' : undefined); de.moveDocument = this._props.moveDocument; de.offset = this.screenToFreeformContentsXf.transformDirection(ptsParent.clientX - left, ptsParent.clientY - top); @@ -506,7 +512,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @action updateClusters(_freeform_useClusters: boolean) { - this._props.Document._freeform_useClusters = _freeform_useClusters; + this.Document._freeform_useClusters = _freeform_useClusters; this._clusterSets.length = 0; this.childLayoutPairs.map(pair => pair.layout).map(c => this.updateCluster(c)); } @@ -514,7 +520,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @action updateClusterDocs(docs: Doc[]) { const childLayouts = this.childLayoutPairs.map(pair => pair.layout); - if (this._props.Document._freeform_useClusters) { + if (this.Document._freeform_useClusters) { const docFirst = docs[0]; docs.map(doc => this._clusterSets.map(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1))); const preferredInd = NumCast(docFirst.layout_cluster); @@ -557,7 +563,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @action updateCluster = (doc: Doc) => { const childLayouts = this.childLayoutPairs.map(pair => pair.layout); - if (this._props.Document._freeform_useClusters) { + if (this.Document._freeform_useClusters) { this._clusterSets.forEach(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1)); const preferredInd = NumCast(doc.layout_cluster); doc.layout_cluster = -1; @@ -586,7 +592,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } }; - clusterStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => { + clusterStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => { let styleProp = this._props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1 if (doc && this.childDocList?.includes(doc)) switch (property) { @@ -616,7 +622,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection trySelectCluster = (addToSel: boolean) => { if (this._hitCluster !== -1) { !addToSel && SelectionManager.DeselectAll(); - const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this._props.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === this._hitCluster); + 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; } @@ -629,7 +635,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this._downY = this._lastY = e.pageY; this._downTime = Date.now(); const scrollMode = e.altKey ? (Doc.UserDoc().freeformScrollMode === freeformScrollMode.Pan ? freeformScrollMode.Zoom : freeformScrollMode.Pan) : Doc.UserDoc().freeformScrollMode; - if (e.button === 0 && (!(e.ctrlKey && !e.metaKey) || scrollMode !== freeformScrollMode.Pan) && this._props.isContentActive(true)) { + if (e.button === 0 && (!(e.ctrlKey && !e.metaKey) || scrollMode !== freeformScrollMode.Pan) && this._props.isContentActive()) { if (!this.Document.isGroup) { // group freeforms don't pan when dragged -- instead let the event go through to allow the group itself to drag // prettier-ignore @@ -704,7 +710,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection }; @action onEraserUp = (e: PointerEvent): void => { - this._deleteList.forEach(ink => ink.props.removeDocument?.(ink.Document)); + this._deleteList.forEach(ink => ink._props.removeDocument?.(ink.Document)); this._deleteList = []; this._batch?.end(); }; @@ -714,7 +720,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection if (this._lightboxDoc) this._lightboxDoc = undefined; if (Utils.isClick(e.pageX, e.pageY, this._downX, this._downY, this._downTime)) { if (this.onBrowseClickHandler()) { - this.onBrowseClickHandler().script.run({ documentView: this._props.DocumentView?.(), clientX: e.clientX, clientY: e.clientY }); + this.onBrowseClickHandler().script.run({ documentView: this.DocumentView?.(), clientX: e.clientX, clientY: e.clientY }); e.stopPropagation(); e.preventDefault(); } else if (this.isContentActive() && e.shiftKey) { @@ -737,7 +743,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const ctrlKey = e.ctrlKey && !e.shiftKey; const shiftKey = e.shiftKey && !e.ctrlKey; PresBox.Instance?.pauseAutoPres(); - this._props.DocumentView?.().clearViewTransition(); + this.DocumentView?.().clearViewTransition(); const [dxi, dyi] = this.screenToFreeformContentsXf.transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); const { x: dx, y: dy } = Utils.rotPt(dxi, dyi, this.ScreenToLocalBoxXf().Rotate); this.setPan(NumCast(this.Document[this.panXFieldKey]) - (ctrlKey ? 0 : dx), NumCast(this.Document[this.panYFieldKey]) - (shiftKey ? 0 : dy), 0, true); @@ -808,9 +814,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const eraserMax = { X: Math.max(lastPoint.X, currPoint.X), Y: Math.max(lastPoint.Y, currPoint.Y) }; return this.childDocs - .map(doc => DocumentManager.Instance.getDocumentView(doc, this._props.DocumentView?.())) + .map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())) .filter(inkView => inkView?.ComponentView instanceof InkingStroke) - .map(inkView => ({ inkViewBounds: inkView!.getBounds(), inkStroke: inkView!.ComponentView as InkingStroke, inkView: inkView! })) + .map(inkView => ({ inkViewBounds: inkView!.getBounds, inkStroke: inkView!.ComponentView as InkingStroke, inkView: inkView! })) .filter( ({ inkViewBounds }) => inkViewBounds && // bounding box of eraser segment and ink stroke overlap @@ -905,7 +911,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._props.DocumentView?.())?.ComponentView as InkingStroke; + const otherInk = DocumentManager.Instance.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)); @@ -959,8 +965,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const localTransform = invTransform.scaleAbout(deltaScale, x, y); if (localTransform.Scale >= 0.05 || localTransform.Scale > this.zoomScaling()) { const safeScale = Math.min(Math.max(0.05, localTransform.Scale), 20); - this._props.Document[this.scaleFieldKey] = Math.abs(safeScale); - this.setPan(-localTransform.TranslateX / safeScale, (this._props.originTopLeft ? undefined : NumCast(this._props.Document.layout_scrollTop) * safeScale) || -localTransform.TranslateY / safeScale); + this.Document[this.scaleFieldKey] = Math.abs(safeScale); + this.setPan(-localTransform.TranslateX / safeScale, (this._props.originTopLeft ? undefined : NumCast(this.Document.layout_scrollTop) * safeScale) || -localTransform.TranslateY / safeScale); } }; @@ -968,7 +974,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection onPointerWheel = (e: React.WheelEvent): void => { if (this.Document.isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom PresBox.Instance?.pauseAutoPres(); - if (this.layoutDoc._Transform || this._props.Document.treeView_OutlineMode === TreeViewType.outline) return; + if (this.layoutDoc._Transform || this.Document.treeView_OutlineMode === TreeViewType.outline) return; e.stopPropagation(); const docHeight = NumCast(this.Document[Doc.LayoutFieldKey(this.Document) + '_nativeHeight'], this.nativeHeight); const scrollable = this.isAnnotationOverlay && NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this._props.PanelHeight() / this.nativeDimScaling + 1e-4; @@ -979,7 +985,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection freeformScrollMode.Zoom : freeformScrollMode.Pan // prettier-ignore ) { case freeformScrollMode.Pan: - if (((!e.metaKey && !e.altKey) || Doc.UserDoc().freeformScrollMode === freeformScrollMode.Zoom) && this._props.isContentActive(true)) { + if (((!e.metaKey && !e.altKey) || Doc.UserDoc().freeformScrollMode === freeformScrollMode.Zoom) && this._props.isContentActive()) { const deltaX = e.shiftKey ? e.deltaX : e.ctrlKey ? 0 : e.deltaX; const deltaY = e.shiftKey ? 0 : e.ctrlKey ? e.deltaY : e.deltaY; this.scrollPan({ deltaX: -deltaX * this.screenToFreeformContentsXf.Scale, deltaY: e.shiftKey ? 0 : -deltaY * this.screenToFreeformContentsXf.Scale }); @@ -987,9 +993,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } default: case freeformScrollMode.Zoom: - if ((e.ctrlKey || !scrollable) && this._props.isContentActive(true)) { + if ((e.ctrlKey || !scrollable) && this._props.isContentActive()) { this.zoom(e.clientX, e.clientY, Math.max(-1, Math.min(1, e.deltaY))); // if (!this._props.isAnnotationOverlay) // bcz: do we want to zoom in on images/videos/etc? - e.preventDefault(); + // e.preventDefault(); } break; } @@ -1065,7 +1071,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @action nudge = (x: number, y: number, nudgeTime: number = 500) => { - const collectionDoc = this._props.docViewPath().lastElement().Document; + const collectionDoc = this.Document; if (collectionDoc?._type_collection !== CollectionViewType.Freeform) { this.setPan( NumCast(this.layoutDoc[this.panXFieldKey]) + ((this._props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale @@ -1170,35 +1176,33 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @undoBatch onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { - const docView = fieldProps.DocumentView?.(); - if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.Document._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) { + if ((e.metaKey || e.ctrlKey || e.altKey || fieldProps.Document._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) { e.stopPropagation?.(); const below = !e.altKey && e.key !== 'Tab'; - const layout_fieldKey = StrCast(docView.LayoutFieldKey); - const newDoc = Doc.MakeCopy(docView.Document, true); - const dataField = docView.Document[Doc.LayoutFieldKey(newDoc)]; + const layout_fieldKey = StrCast(fieldProps.fieldKey); + const newDoc = Doc.MakeCopy(fieldProps.Document, true); + const dataField = fieldProps.Document[Doc.LayoutFieldKey(newDoc)]; newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined; - if (below) newDoc.y = NumCast(docView.Document.y) + NumCast(docView.Document._height) + 10; - else newDoc.x = NumCast(docView.Document.x) + NumCast(docView.Document._width) + 10; - if (layout_fieldKey !== 'layout' && docView.Document[layout_fieldKey] instanceof Doc) { - newDoc[layout_fieldKey] = docView.Document[layout_fieldKey]; + if (below) newDoc.y = NumCast(fieldProps.Document.y) + NumCast(fieldProps.Document._height) + 10; + else newDoc.x = NumCast(fieldProps.Document.x) + NumCast(fieldProps.Document._width) + 10; + if (layout_fieldKey !== 'layout' && fieldProps.Document[layout_fieldKey] instanceof Doc) { + newDoc[layout_fieldKey] = fieldProps.Document[layout_fieldKey]; } - Doc.GetProto(newDoc).text = undefined; + newDoc[DocData].text = undefined; FormattedTextBox.SetSelectOnLoad(newDoc); return this.addDocument?.(newDoc); } }; @computed get childPointerEvents() { - const engine = this._props.layoutEngine?.() || StrCast(this._props.Document._layoutEngine); - const pointerevents = SnappingManager.IsResizing + const engine = this._props.layoutEngine?.() || StrCast(this.Document._layoutEngine); + return SnappingManager.IsResizing ? 'none' : this._props.childPointerEvents?.() ?? - (this._props.viewDefDivClick || // - (engine === computePassLayout.name && !this._props.isSelected()) || - this.isContentActive() === false - ? 'none' - : this._props.pointerEvents?.()); - return pointerevents; + (this._props.viewDefDivClick || // + (engine === computePassLayout.name && !this._props.isSelected()) || + this.isContentActive() === false + ? 'none' + : this._props.pointerEvents?.()); } @observable _childPointerEvents: 'none' | 'all' | 'visiblepainted' | undefined = undefined; @@ -1212,6 +1216,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection {...OmitKeys(entry, ['replica', 'pair']).omit} key={childLayout[Id] + (entry.replica || '')} Document={childLayout} + containerViewPath={this.DocumentView?.().docViewPath} + styleProvider={this.clusterStyleProvider} TemplateDataDocument={childData} dragStarting={this.dragStarting} dragEnding={this.dragEnding} @@ -1225,10 +1231,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection LayoutTemplateString={childLayout.z ? undefined : this._props.childLayoutString} rootSelected={childData ? this.rootSelected : returnFalse} waitForDoubleClickToClick={this._props.waitForDoubleClickToClick} - onClick={this.onChildClickHandler} + onClickScript={this.onChildClickHandler} onKey={this.onKeyDown} - onDoubleClick={this.onChildDoubleClickHandler} - onBrowseClick={this.onBrowseClickHandler} + onDoubleClickScript={this.onChildDoubleClickHandler} + onBrowseClickScript={this.onBrowseClickHandler} + bringToFront={this.bringToFront} ScreenToLocalTransform={childLayout.z ? this.ScreenToLocalBoxXf : this.ScreenToContentsXf} PanelWidth={childLayout[Width]} PanelHeight={childLayout[Height]} @@ -1244,10 +1251,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection moveDocument={this._props.moveDocument} pinToPres={this._props.pinToPres} whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged} - docViewPath={this._props.docViewPath} - styleProvider={this.clusterStyleProvider} dragAction={(this.Document.childDragAction ?? this._props.childDragAction) as dropActionType} - bringToFront={this.bringToFront} layout_showTitle={this._props.childlayout_showTitle} dontRegisterView={this._props.dontRegisterView} pointerEvents={this.childPointerEventsFunc} @@ -1324,7 +1328,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } onViewDefDivClick = (e: React.MouseEvent, payload: any) => { - (this._props.viewDefDivClick || ScriptCast(this._props.Document.onViewDefDivClick))?.script.run({ this: this._props.Document, payload }); + (this._props.viewDefDivClick || ScriptCast(this.Document.onViewDefDivClick))?.script.run({ this: this.Document, payload }); e.stopPropagation(); }; @@ -1379,7 +1383,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection poolData: Map<string, PoolData>, engine: (poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) => ViewDefResult[] ) { - return engine(poolData, this._props.Document, this.childLayoutPairs, [this._props.PanelWidth(), this._props.PanelHeight()], this.viewDefsToJSX, this._props.engineProps); + return engine(poolData, this.Document, this.childLayoutPairs, [this._props.PanelWidth(), this._props.PanelHeight()], this.viewDefsToJSX, this._props.engineProps); } doFreeformLayout(poolData: Map<string, PoolData>) { @@ -1439,7 +1443,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection infoUI = () => (this.Document._hideInfo || this.Document.annotationOn || this._props.renderDepth ? null : <CollectionFreeFormInfoUI Document={this.Document} Freeform={this} close={this.closeInfo} />); componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); super.componentDidMount?.(); setTimeout( action(() => { @@ -1476,17 +1480,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection ); this._disposers.pointerevents = reaction( - () => { - const engine = this._props.layoutEngine?.() || StrCast(this._props.Document._layoutEngine); - return SnappingManager.IsResizing - ? 'none' - : this._props.childPointerEvents?.() ?? - (this._props.viewDefDivClick || // - (engine === computePassLayout.name && !this._props.isSelected()) || - this.isContentActive() === false - ? 'none' - : this._props.pointerEvents?.()); - }, + () => this.childPointerEvents, pointerevents => (this._childPointerEvents = pointerevents as any), { fireImmediately: true } ); @@ -1497,6 +1491,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection ); }) ); + + this._disposers.paintFunc = reaction( + () => ({ code: this.paintFunc, first: this._firstRender, width: this.Document._width, height: this.Document._height }), + ({ code, first }) => code && !first && eval(code), + { fireImmediately: true } + ); + this._disposers.layoutElements = reaction( // layoutElements can't be a computed value because doLayoutComputation() is an action that has side effect of updating clusters () => this.doInternalLayoutComputation, @@ -1540,7 +1541,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection updateIcon = () => CollectionFreeFormView.UpdateIcon( this.layoutDoc[Id] + '-icon' + new Date().getTime(), - this._props.docViewPath().lastElement().ContentDiv!, + this.DocumentView?.().ContentDiv!, NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._height), this._props.PanelWidth(), @@ -1651,15 +1652,15 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const appearance = ContextMenu.Instance.findByDescription('Appearance...'); const appearanceItems = appearance && 'subitems' in appearance ? appearance.subitems : []; - !this._props.Document.isGroup && appearanceItems.push({ description: 'Reset View', event: this.resetView, icon: 'compress-arrows-alt' }); - !this._props.Document.isGroup && appearanceItems.push({ description: 'Toggle Auto Reset View', event: this.toggleResetView, icon: 'compress-arrows-alt' }); + !this.Document.isGroup && appearanceItems.push({ description: 'Reset View', event: this.resetView, icon: 'compress-arrows-alt' }); + !this.Document.isGroup && appearanceItems.push({ description: 'Toggle Auto Reset View', event: this.toggleResetView, icon: 'compress-arrows-alt' }); !Doc.noviceMode && appearanceItems.push({ description: 'Toggle auto arrange', event: () => (this.layoutDoc._autoArrange = !this.layoutDoc._autoArrange), icon: 'compress-arrows-alt', }); - if (this._props.setContentView === emptyFunction) { + if (this._props.setContentViewBox === emptyFunction) { !appearance && ContextMenu.Instance.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'eye' }); return; } @@ -1668,7 +1669,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection !Doc.noviceMode && appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: 'compress-arrows-alt' }); this._props.renderDepth && appearanceItems.push({ description: 'Ungroup collection', event: this.promoteCollection, icon: 'table' }); - this._props.Document.isGroup && this.Document.transcription && appearanceItems.push({ description: 'Ink to text', event: this.transcribeStrokes, icon: 'font' }); + this.Document.isGroup && this.Document.transcription && appearanceItems.push({ description: 'Ink to text', event: this.transcribeStrokes, icon: 'font' }); !Doc.noviceMode ? appearanceItems.push({ description: 'Arrange contents in grid', event: this.layoutDocsInGrid, icon: 'table' }) : null; !Doc.noviceMode ? appearanceItems.push({ description: (this.Document._freeform_useClusters ? 'Hide' : 'Show') + ' Clusters', event: () => this.updateClusters(!this.Document._freeform_useClusters), icon: 'braille' }) : null; @@ -1692,8 +1693,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @undoBatch transcribeStrokes = () => { - if (this._props.Document.isGroup && this._props.Document.transcription) { - const text = StrCast(this._props.Document.transcription); + if (this.Document.isGroup && this.Document.transcription) { + const text = StrCast(this.Document.transcription); const lines = text.split('\n'); const height = 30 + 15 * lines.length; @@ -1741,7 +1742,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection incrementalRendering = () => this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])).length !== 0; incrementalRender = action(() => { - if (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this._props.docViewPath())) { + if (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.())) { const layout_unrendered = this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])); const loadIncrement = 5; for (var i = 0; i < Math.min(layout_unrendered.length, loadIncrement); i++) { @@ -1751,17 +1752,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this.childDocs.some(doc => !this._renderCutoffData.get(doc[Id])) && setTimeout(this.incrementalRender, 1); }); - // if a freeform view has any children, then the children will likely consist of a single child - // which will be a DocumentView. In this sitation, this freeform views acts as an annotation overlay for - // the underlying DocumentView and will pan and scoll with the underlying Documen tView. - @computed get underlayViews() { - return this._props.children ? [toJS(this._props.children)] : []; - } - @computed get placeholder() { return ( <div className="collectionfreeformview-placeholder" style={{ background: this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor) }}> - <span className="collectionfreeformview-placeholderSpan">{this._props.Document.annotationOn ? '' : this._props.Document.title?.toString()}</span> + <span className="collectionfreeformview-placeholderSpan">{this.Document.annotationOn ? '' : this.Document.title?.toString()}</span> </div> ); } @@ -1790,24 +1784,23 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection </div> ); } - @computed get pannableContents() { - this.incrementalRender(); + get pannableContents() { + this.incrementalRender(); // needs to happen synchronously or freshly typed text documents will flash and miss their first characters return ( <CollectionFreeFormPannableContents Document={this.Document} brushedView={this.brushedView} isAnnotationOverlay={this.isAnnotationOverlay} transform={this.PanZoomCenterXf} - transition={this._panZoomTransition ? `transform ${this._panZoomTransition}ms` : Cast(this.layoutDoc._viewTransition, 'string', Cast(this._props.DocumentView?.()?.Document._viewTransition, 'string', null))} + transition={this._panZoomTransition ? `transform ${this._panZoomTransition}ms` : Cast(this.layoutDoc._viewTransition, 'string', Cast(this.Document._viewTransition, 'string', null))} viewDefDivClick={this._props.viewDefDivClick}> - {this.underlayViews} + {this.props.children ?? null} {/* most likely case of children is document content that's being annoated: eg., an image */} {this.contentViews} <CollectionFreeFormRemoteCursors {...this._props} key="remoteCursors" /> </CollectionFreeFormPannableContents> ); } - @computed get marqueeView() { - TraceMobx(); + get marqueeView() { return ( <MarqueeView {...this._props} @@ -1870,6 +1863,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return ( <div className="collectionfreeformview-container" + id={this._paintedId} ref={r => { this.createDashEventsTarget(r); this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel); @@ -1891,20 +1885,21 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection width: `${100 / (this.nativeDimScaling || 1)}%`, height: this._props.getScrollHeight?.() ?? `${100 / (this.nativeDimScaling || 1)}%`, }}> - {this._lightboxDoc ? ( + {this.paintFunc ? null : this._lightboxDoc ? ( <div style={{ padding: 15, width: '100%', height: '100%' }}> <DocumentView {...this._props} Document={this._lightboxDoc} + containerViewPath={this.DocumentView?.().docViewPath} TemplateDataDocument={undefined} PanelWidth={this.lightboxPanelWidth} PanelHeight={this.lightboxPanelHeight} NativeWidth={returnZero} NativeHeight={returnZero} - onClick={this.onChildClickHandler} + onClickScript={this.onChildClickHandler} onKey={this.onKeyDown} - onDoubleClick={this.onChildDoubleClickHandler} - onBrowseClick={this.onBrowseClickHandler} + onDoubleClickScript={this.onChildDoubleClickHandler} + onBrowseClickScript={this.onBrowseClickHandler} childFilters={this.childDocFilters} childFiltersByRanges={this.childDocRangeFilters} searchFilterDocs={this.searchFilterDocs} @@ -1942,15 +1937,15 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY DocumentManager.Instance.showDocument(dv.Document, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => { if (!focused) { const selfFfview = !dv.Document.isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined; - let containers = dv.props.docViewPath(); + let containers = dv.containerViewPath?.() ?? []; let parFfview = dv.CollectionFreeFormView; for (var cont of containers) { parFfview = parFfview ?? cont.CollectionFreeFormView; } - while (parFfview?.Document.isGroup) parFfview = parFfview.props.DocumentView?.().CollectionFreeFormView; + while (parFfview?.Document.isGroup) parFfview = parFfview.DocumentView?.().CollectionFreeFormView; const ffview = selfFfview && selfFfview.layoutDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview ffview?.zoomSmoothlyAboutPt(ffview.screenToFreeformContentsXf.transformPoint(clientX, clientY), ffview?.isAnnotationOverlay ? 1 : 0.5, browseTransitionTime); - Doc.linkFollowHighlight(dv?.props.Document, false); + Doc.linkFollowHighlight(dv?.Document, false); } }); } @@ -1968,13 +1963,13 @@ ScriptingGlobals.add(function curKeyFrame(readOnly: boolean) { }); ScriptingGlobals.add(function pinWithView(pinContent: boolean) { SelectionManager.Views.forEach(view => - view.props.pinToPres(view.Document, { + view._props.pinToPres(view.Document, { currentFrame: Cast(view.Document.currentFrame, 'number', null), pinData: { poslayoutview: pinContent, dataview: pinContent, }, - pinViewport: MarqueeView.CurViewBounds(view.Document, view.props.PanelWidth(), view.props.PanelHeight()), + pinViewport: MarqueeView.CurViewBounds(view.Document, view._props.PanelWidth(), view._props.PanelHeight()), }) ); }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 39d828302..a417d777a 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -219,7 +219,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps const scrollMode = e.altKey ? (Doc.UserDoc().freeformScrollMode === freeformScrollMode.Pan ? freeformScrollMode.Zoom : freeformScrollMode.Pan) : Doc.UserDoc().freeformScrollMode; // allow marquee if right drag/meta drag, or pan mode - if (e.button === 2 || e.metaKey || scrollMode === freeformScrollMode.Pan) { + if (e.button === 2 || e.metaKey || (this._props.isContentActive() && scrollMode === freeformScrollMode.Pan && Doc.ActiveTool === InkTool.None)) { this.setPreviewCursor(e.clientX, e.clientY, true, false, this._props.Document); e.preventDefault(); } else PreviewCursor.Instance.Visible = false; @@ -352,9 +352,10 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps const newCollection = creator ? creator(selected, { title: 'nested stack' }) : ((doc: Doc) => { - Doc.GetProto(doc).data = new List<Doc>(selected); - Doc.GetProto(doc).isGroup = makeGroup; - Doc.GetProto(doc).title = makeGroup ? 'grouping' : 'nested freeform'; + const docData = doc[DocData]; + docData.data = new List<Doc>(selected); + docData.isGroup = makeGroup; + docData.title = makeGroup ? 'grouping' : 'nested freeform'; doc._freeform_panX = doc._freeform_panY = 0; return doc; })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true)); diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 113ffedb3..f25872c2b 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -192,7 +192,7 @@ export class CollectionGridView extends CollectionSubView() { {...this._props} NativeWidth={returnZero} NativeHeight={returnZero} - setContentView={emptyFunction} + setContentViewBox={emptyFunction} Document={layout} TemplateDataDocument={layout.resolvedDataDoc as Doc} isContentActive={this.isChildContentActive} @@ -200,7 +200,7 @@ export class CollectionGridView extends CollectionSubView() { PanelHeight={height} ScreenToLocalTransform={dxf} whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged} - onClick={this.onChildClickHandler} + onClickScript={this.onChildClickHandler} renderDepth={this._props.renderDepth + 1} dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as any} // 'y', 'x', 'xy' /> @@ -340,7 +340,7 @@ export class CollectionGridView extends CollectionSubView() { * Handles text document creation on double click. */ onPointerDown = (e: React.PointerEvent) => { - if (this._props.isContentActive(true)) { + if (this._props.isContentActive()) { setupMoveUpEvents( this, e, diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index d105b04f7..228af78aa 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -79,16 +79,16 @@ export class CollectionLinearView extends CollectionSubView() { @action changeDescriptionSetting = () => { - if (LinkDescriptionPopup.showDescriptions) { - if (LinkDescriptionPopup.showDescriptions === 'ON') { - LinkDescriptionPopup.showDescriptions = 'OFF'; - LinkDescriptionPopup.descriptionPopup = false; + if (LinkDescriptionPopup.Instance.showDescriptions) { + if (LinkDescriptionPopup.Instance.showDescriptions === 'ON') { + LinkDescriptionPopup.Instance.showDescriptions = 'OFF'; + LinkDescriptionPopup.Instance.display = false; } else { - LinkDescriptionPopup.showDescriptions = 'ON'; + LinkDescriptionPopup.Instance.showDescriptions = 'ON'; } } else { - LinkDescriptionPopup.showDescriptions = 'OFF'; - LinkDescriptionPopup.descriptionPopup = false; + LinkDescriptionPopup.Instance.showDescriptions = 'OFF'; + LinkDescriptionPopup.Instance.display = false; } }; @@ -110,7 +110,7 @@ export class CollectionLinearView extends CollectionSubView() { <Tooltip title={<div className="dash-tooltip">{'Toggle description pop-up'} </div>} placement="top"> <span className="bottomPopup-descriptions" onClick={this.changeDescriptionSetting}> - Labels: {LinkDescriptionPopup.showDescriptions ? LinkDescriptionPopup.showDescriptions : 'ON'} + Labels: {LinkDescriptionPopup.Instance.showDescriptions ? LinkDescriptionPopup.Instance.showDescriptions : 'ON'} </span> </Tooltip> @@ -147,8 +147,8 @@ export class CollectionLinearView extends CollectionSubView() { switch (doc.layout) { case '<LinkingUI>': return this.getLinkUI(); case '<CurrentlyPlayingUI>': return this.getCurrentlyPlayingUI(); - case '<UndoStack>': return <UndoStack />; - case '<Branching>': return Doc.UserDoc().isBranchingMode ? <BranchingTrailManager /> : null; + case '<UndoStack>': return <UndoStack key={doc[Id]}/>; + case '<Branching>': return Doc.UserDoc().isBranchingMode ? <BranchingTrailManager key={doc[Id]} /> : null; } const nested = doc._type_collection === CollectionViewType.Linear; @@ -189,9 +189,8 @@ export class CollectionLinearView extends CollectionSubView() { dontRegisterView={BoolCast(this.Document.childDontRegisterViews)} focus={emptyFunction} styleProvider={this._props.styleProvider} - docViewPath={returnEmptyDoclist} + containerViewPath={this.childContainerViewPath} whenChildContentsActiveChanged={emptyFunction} - bringToFront={emptyFunction} childFilters={this._props.childFilters} childFiltersByRanges={this._props.childFiltersByRanges} searchFilterDocs={this._props.searchFilterDocs} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 563084af8..b181b59ce 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -4,7 +4,7 @@ import { Button } from 'browndash-components'; import { action, computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { returnFalse } from '../../../../Utils'; +import { emptyFunction, returnFalse } from '../../../../Utils'; import { Doc, DocListCast } from '../../../../fields/Doc'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { DragManager, dropActionType } from '../../../util/DragManager'; @@ -127,7 +127,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { private get totalRatioAllocation(): number | undefined { const layoutInfoLen = this.resolvedLayoutInformation.widthSpecifiers.length; if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) { - return this._props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)) - 2 * NumCast(this._props.Document._xMargin); + return this._props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)) - 2 * NumCast(this.Document._xMargin); } } @@ -259,16 +259,16 @@ export class CollectionMulticolumnView extends CollectionSubView() { Document={childLayout} TemplateDataDocument={childLayout.resolvedDataDoc as Doc} styleProvider={this._props.styleProvider} - docViewPath={this._props.docViewPath} + containerViewPath={this.childContainerViewPath} LayoutTemplate={this._props.childLayoutTemplate} LayoutTemplateString={this._props.childLayoutString} renderDepth={this._props.renderDepth + 1} PanelWidth={width} PanelHeight={height} rootSelected={this.rootSelected} - dragAction={(this._props.Document.childDragAction ?? this._props.childDragAction) as dropActionType} - onClick={this.onChildClickHandler} - onDoubleClick={this.onChildDoubleClickHandler} + dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType} + onClickScript={this.onChildClickHandler} + onDoubleClickScript={this.onChildDoubleClickHandler} suppressSetHeight={true} ScreenToLocalTransform={dxf} isContentActive={this.isChildContentActive} @@ -287,7 +287,6 @@ export class CollectionMulticolumnView extends CollectionSubView() { whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged} addDocTab={this._props.addDocTab} pinToPres={this._props.pinToPres} - bringToFront={returnFalse} dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as any} // 'y', 'x', 'xy' /> ); diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index bf0d39197..659f7ccdc 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -1,7 +1,7 @@ import { action, computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { returnFalse } from '../../../../Utils'; +import { emptyFunction, returnFalse } from '../../../../Utils'; import { Doc, DocListCast } from '../../../../fields/Doc'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { DragManager, dropActionType } from '../../../util/DragManager'; @@ -122,7 +122,7 @@ export class CollectionMultirowView extends CollectionSubView() { private get totalRatioAllocation(): number | undefined { const layoutInfoLen = this.resolvedLayoutInformation.heightSpecifiers.length; if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) { - return this._props.PanelHeight() - (this.totalFixedAllocation + resizerHeight * (layoutInfoLen - 1)) - 2 * NumCast(this._props.Document._yMargin); + return this._props.PanelHeight() - (this.totalFixedAllocation + resizerHeight * (layoutInfoLen - 1)) - 2 * NumCast(this.Document._yMargin); } } @@ -254,23 +254,22 @@ export class CollectionMultirowView extends CollectionSubView() { Document={layout} TemplateDataDocument={layout.resolvedDataDoc as Doc} styleProvider={this._props.styleProvider} - docViewPath={this._props.docViewPath} + containerViewPath={this.childContainerViewPath} LayoutTemplate={this._props.childLayoutTemplate} LayoutTemplateString={this._props.childLayoutString} renderDepth={this._props.renderDepth + 1} PanelWidth={width} PanelHeight={height} rootSelected={this.rootSelected} - dropAction={StrCast(this.Document.childDragAction) as dropActionType} - onClick={this.onChildClickHandler} - onDoubleClick={this.onChildDoubleClickHandler} + dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType} + onClickScript={this.onChildClickHandler} + onDoubleClickScript={this.onChildDoubleClickHandler} ScreenToLocalTransform={dxf} isContentActive={this.isChildContentActive} isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive} hideResizeHandles={layout.layout_fitWidth || this._props.childHideResizeHandles ? true : false} hideDecorationTitle={this._props.childHideDecorationTitle} fitContentsToBox={this._props.fitContentsToBox} - dragAction={this._props.childDragAction} focus={this._props.focus} childFilters={this.childDocFilters} childFiltersByRanges={this.childDocRangeFilters} @@ -282,7 +281,6 @@ export class CollectionMultirowView extends CollectionSubView() { whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged} addDocTab={this._props.addDocTab} pinToPres={this._props.pinToPres} - bringToFront={returnFalse} dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as any} // 'y', 'x', 'xy' /> ); diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx index c38c6dc4e..d580d9c52 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx @@ -1,16 +1,16 @@ -import { action, observable } from 'mobx'; +import { action } from 'mobx'; import { observer } from 'mobx-react'; 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 { StyleProviderFunc } from '../../nodes/DocumentView'; +import { StyleProviderFuncType } from '../../nodes/FieldView'; import { DimUnit } from './CollectionMulticolumnView'; interface ResizerProps { width: number; - styleProvider?: StyleProviderFunc; + styleProvider?: StyleProviderFuncType; isContentActive?: () => boolean | undefined; columnUnitLength(): number | undefined; toLeft?: Doc; diff --git a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx index 6f1b3b425..73d08d5ef 100644 --- a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx @@ -1,16 +1,16 @@ -import { action, observable } from 'mobx'; +import { action } from 'mobx'; import { observer } from 'mobx-react'; 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 { StyleProviderFunc } from '../../nodes/DocumentView'; +import { StyleProviderFuncType } from '../../nodes/FieldView'; import { DimUnit } from './CollectionMultirowView'; interface ResizerProps { height: number; - styleProvider?: StyleProviderFunc; + styleProvider?: StyleProviderFuncType; isContentActive?: () => boolean | undefined; columnUnitLength(): number | undefined; toTop?: Doc; diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index da9da8fbe..ee61c4141 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -214,8 +214,9 @@ border: 1px solid $medium-gray; overflow-x: hidden; overflow-y: auto; - padding: 5px; display: inline-flex; + padding: 0; + align-items: center; } .schema-row { diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 492aed0ea..31b4a2dd4 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -16,7 +16,8 @@ import { undoable, undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { EditableView } from '../../EditableView'; import { Colors } from '../../global/globalEnums'; -import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../../nodes/DocumentView'; +import { DocumentView } from '../../nodes/DocumentView'; +import { FocusViewOptions, FieldViewProps } from '../../nodes/FieldView'; import { KeyValueBox } from '../../nodes/KeyValueBox'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DefaultStyleProvider, StyleProp } from '../../StyleProvider'; @@ -24,7 +25,7 @@ import { CollectionSubView } from '../CollectionSubView'; import './CollectionSchemaView.scss'; import { SchemaColumnHeader } from './SchemaColumnHeader'; import { SchemaRowBox } from './SchemaRowBox'; -import { FieldViewProps } from '../../nodes/FieldView'; +const { default: { SCHEMA_NEW_NODE_HEIGHT } } = require('../../global/globalCssVariables.module.scss'); // prettier-ignore export enum ColumnType { Number, @@ -69,7 +70,7 @@ export class CollectionSchemaView extends CollectionSubView() { public static _minColWidth: number = 25; public static _rowMenuWidth: number = 60; public static _previewDividerWidth: number = 4; - public static _newNodeInputHeight: number = 20; + public static _newNodeInputHeight: number = Number(SCHEMA_NEW_NODE_HEIGHT); public fieldInfos = new ObservableMap<string, FInfo>(); @observable _menuKeys: string[] = []; @@ -147,7 +148,7 @@ export class CollectionSchemaView extends CollectionSubView() { } componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); document.addEventListener('keydown', this.onKeyDown); Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => this.fieldInfos.set(pair[0], pair[1])); @@ -498,13 +499,13 @@ export class CollectionSchemaView extends CollectionSubView() { ContextMenu.Instance.displayMenu(x, y, undefined, true); }; - focusDocument = (doc: Doc, options: DocFocusOptions) => { + focusDocument = (doc: Doc, options: FocusViewOptions) => { Doc.BrushDoc(doc); this.scrollToDoc(doc, options); return undefined; }; - scrollToDoc = (doc: Doc, options: DocFocusOptions) => { + scrollToDoc = (doc: Doc, options: FocusViewOptions) => { const found = this._tableContentRef && Array.from(this._tableContentRef.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); if (found) { const rect = found.getBoundingClientRect(); @@ -907,14 +908,13 @@ export class CollectionSchemaView extends CollectionSubView() { childFiltersByRanges={this.childDocRangeFilters} searchFilterDocs={this.searchFilterDocs} styleProvider={DefaultStyleProvider} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} moveDocument={this._props.moveDocument} addDocument={this.addRow} removeDocument={this._props.removeDocument} whenChildContentsActiveChanged={returnFalse} addDocTab={this._props.addDocTab} pinToPres={this._props.pinToPres} - bringToFront={returnFalse} /> )} </div> @@ -962,7 +962,7 @@ class CollectionSchemaViewDoc extends ObservableReactComponent<CollectionSchemaV tableWidthFunc = () => this._props.schema.tableWidth; screenToLocalXf = () => this._props.schema.ScreenToLocalBoxXf().translate(0, -this._props.rowHeight() - this._props.index * this._props.rowHeight()); - noOpacityStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => { + noOpacityStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => { if (property === StyleProp.Opacity) return 1; return DefaultStyleProvider(doc, props, property); }; @@ -971,6 +971,7 @@ class CollectionSchemaViewDoc extends ObservableReactComponent<CollectionSchemaV <DocumentView key={this._props.doc[Id]} {...this._props.schema._props} + containerViewPath={this._props.schema.childContainerViewPath} LayoutTemplate={this._props.schema._props.childLayoutTemplate} LayoutTemplateString={SchemaRowBox.LayoutString(this._props.schema._props.fieldKey, this._props.index)} Document={this._props.doc} @@ -988,7 +989,6 @@ class CollectionSchemaViewDoc extends ObservableReactComponent<CollectionSchemaV searchFilterDocs={this._props.schema.searchFilterDocs} rootSelected={this._props.schema.rootSelected} ScreenToLocalTransform={this.screenToLocalXf} - bringToFront={emptyFunction} dragWhenActive={true} isDocumentActive={this._props.schema._props.childDocumentsActive?.() ? this._props.schema._props.isDocumentActive : this._props.schema.isContentActive} isContentActive={emptyFunction} diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 5a3be826b..f2fe0dde7 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -3,7 +3,7 @@ import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; -import { CgClose } from 'react-icons/cg'; +import { CgClose, CgLock, CgLockUnlock } from 'react-icons/cg'; import { FaExternalLinkAlt } from 'react-icons/fa'; import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../../Utils'; import { Doc } from '../../../../fields/Doc'; @@ -20,17 +20,17 @@ import { CollectionSchemaView } from './CollectionSchemaView'; import './CollectionSchemaView.scss'; import { SchemaTableCell } from './SchemaTableCell'; -interface SchemaRowBoxProps { +interface SchemaRowBoxProps extends FieldViewProps { rowIndex: number; } @observer -export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps & SchemaRowBoxProps>() { +export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() { public static LayoutString(fieldKey: string, rowIndex: number) { return FieldView.LayoutString(SchemaRowBox, fieldKey).replace('fieldKey', `rowIndex={${rowIndex}} fieldKey`); } private _ref: HTMLDivElement | null = null; - constructor(props: any) { + constructor(props: SchemaRowBoxProps) { super(props); makeObservable(this); } @@ -38,11 +38,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps & SchemaRo bounds = () => this._ref?.getBoundingClientRect(); @computed get schemaView() { - return this._props.DocumentView?.()._props.docViewPath().lastElement()?.ComponentView as CollectionSchemaView; + return this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionSchemaView; } @computed get schemaDoc() { - return this._props.DocumentView?.()._props.docViewPath().lastElement()?.Document; + return this.DocumentView?.().containerViewPath?.().lastElement()?.Document; } @computed get rowIndex() { @@ -50,7 +50,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps & SchemaRo } componentDidMount(): void { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); } select = (ctrlKey: boolean, shiftKey: boolean) => { @@ -121,6 +121,22 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps & SchemaRo pointerEvents: !this._props.isContentActive() ? 'none' : undefined, }}> <IconButton + tooltip="whether document interations are enabled" + icon={this.Document._lockedPosition ? <CgLockUnlock size="12px" /> : <CgLock size="12px" />} + size={Size.XSMALL} + onPointerDown={e => + setupMoveUpEvents( + this, + e, + returnFalse, + emptyFunction, + undoable(e => { + e.stopPropagation(); + Doc.toggleLockedPosition(this.Document); + }, 'Delete Row') + ) + }></IconButton> + <IconButton tooltip="close" icon={<CgClose size={'16px'} />} size={Size.XSMALL} diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index 85269028b..dbaa6e110 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -18,7 +18,7 @@ import { EditableView } from '../../EditableView'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DefaultStyleProvider } from '../../StyleProvider'; import { Colors } from '../../global/globalEnums'; -import { OpenWhere } from '../../nodes/DocumentView'; +import { OpenWhere, returnEmptyDocViewList } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { KeyValueBox } from '../../nodes/KeyValueBox'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; @@ -49,7 +49,7 @@ export interface SchemaTableCellProps { @observer export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellProps> { - constructor(props: any) { + constructor(props: SchemaTableCellProps) { super(props); makeObservable(this); } @@ -75,14 +75,13 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro const fieldProps: FieldViewProps = { childFilters: returnEmptyFilter, childFiltersByRanges: returnEmptyFilter, + docViewPath: returnEmptyDocViewList, searchFilterDocs: returnEmptyDoclist, styleProvider: DefaultStyleProvider, - docViewPath: returnEmptyDoclist, isSelected: returnFalse, setHeight: returnFalse, select: emptyFunction, dragAction: 'move', - bringToFront: emptyFunction, renderDepth: 1, isContentActive: returnFalse, whenChildContentsActiveChanged: emptyFunction, |
