diff options
Diffstat (limited to 'src/client/views/collections/CollectionTreeView.tsx')
-rw-r--r-- | src/client/views/collections/CollectionTreeView.tsx | 126 |
1 files changed, 69 insertions, 57 deletions
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 5741fc29b..c1247f5b0 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,19 +1,22 @@ +/* eslint-disable jsx-a11y/no-static-element-interactions */ +/* eslint-disable jsx-a11y/click-events-have-key-events */ import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { DivHeight, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero } from '../../../ClientUtils'; import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; -import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; +import { BoolCast, Cast, NumCast, ScriptCast, StrCast, toList } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { DivHeight, emptyFunction, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero, Utils } from '../../../Utils'; -import { Docs, DocUtils } from '../../documents/Documents'; -import { DocumentManager } from '../../util/DocumentManager'; -import { DragManager, dropActionType } from '../../util/DragManager'; +import { emptyFunction, Utils } from '../../../Utils'; +import { Docs } from '../../documents/Documents'; +import { DocUtils } from '../../documents/DocUtils'; +import { DragManager } from '../../util/DragManager'; +import { dropActionType } from '../../util/DropActionTypes'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; -import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { undoBatch, UndoManager } from '../../util/UndoManager'; @@ -21,13 +24,14 @@ import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from '../EditableView'; import { DocumentView } from '../nodes/DocumentView'; -import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; -import { StyleProp } from '../StyleProvider'; +import { StyleProp } from '../StyleProp'; import { CollectionFreeFormView } from './collectionFreeForm'; import { CollectionSubView } from './CollectionSubView'; import './CollectionTreeView.scss'; +import { TreeViewType } from './CollectionTreeViewType'; import { TreeView } from './TreeView'; + const _global = (window /* browser */ || global) /* node */ as any; export type collectionTreeViewProps = { @@ -44,12 +48,6 @@ export type collectionTreeViewProps = { hierarchyIndex?: number[]; }; -export enum TreeViewType { - outline = 'outline', - fileSystem = 'fileSystem', - default = 'default', -} - @observer export class CollectionTreeView extends CollectionSubView<Partial<collectionTreeViewProps>>() { public static AddTreeFunc = 'addTreeFolder(this.embedContainer)'; @@ -92,8 +90,10 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree // these should stay in synch with counterparts in DocComponent.ts ViewBoxAnnotatableComponent @observable _isAnyChildContentActive = false; - whenChildContentsActiveChanged = action((isActive: boolean) => this._props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive))); - isContentActive = (outsideReaction?: boolean) => (this._isAnyChildContentActive ? true : this._props.isContentActive() ? true : false); + whenChildContentsActiveChanged = action((isActive: boolean) => { + this._props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive)); + }); + isContentActive = () => (this._isAnyChildContentActive ? true : !!this._props.isContentActive()); componentWillUnmount() { this._isDisposing = true; @@ -103,7 +103,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree } componentDidMount() { - //this._props.setContentView?.(this); + // this._props.setContentView?.(this); this._disposers.autoheight = reaction( () => this.layoutDoc.layout_autoHeight, auto => auto && this.computeHeight(), @@ -126,20 +126,19 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree observeHeight = (ref: any) => { if (ref) { this.refList.add(ref); - this.observer = new _global.ResizeObserver( - action((entries: any) => { - if (this.layoutDoc.layout_autoHeight && ref && this.refList.size && !SnappingManager.IsDragging) { - this.computeHeight(); - } - }) - ); + this.observer = new _global.ResizeObserver(() => { + if (this.layoutDoc.layout_autoHeight && ref && this.refList.size && !SnappingManager.IsDragging) { + this.computeHeight(); + } + }); this.layoutDoc.layout_autoHeight && this.computeHeight(); this.observer.observe(ref); } }; protected createTreeDropTarget = (ele: HTMLDivElement) => { this._treedropDisposer?.(); - if ((this._mainEle = ele)) this._treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.Document, this.onInternalPreDrop.bind(this)); + this._mainEle = ele; + if (ele) this._treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.Document, this.onInternalPreDrop.bind(this)); }; protected onInternalDrop(e: Event, de: DragManager.DropEvent) { @@ -167,39 +166,39 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree } }; - dragConfig = (dragData: DragManager.DocumentDragData) => (dragData.treeViewDoc = this.Document); + dragConfig = (dragData: DragManager.DocumentDragData) => { dragData.treeViewDoc = this.Document; }; // prettier-ignore screenToLocalTransform = () => this.ScreenToLocalBoxXf().translate(0, -this._headerHeight); @action - remove = (doc: Doc | Doc[]): boolean => { - const docs = doc instanceof Doc ? [doc] : doc; + remove = (docIn: Doc | Doc[]): boolean => { + const docs = toList(docIn); const targetDataDoc = this.Document[DocData]; const value = DocListCast(targetDataDoc[this._props.fieldKey]); const result = value.filter(v => !docs.includes(v)); - if ((doc instanceof Doc ? [doc] : doc).some(doc => SelectionManager.Views.some(dv => Doc.AreProtosEqual(dv.Document, doc)))) SelectionManager.DeselectAll(); + if (docs.some(doc => DocumentView.Selected().some(dv => Doc.AreProtosEqual(dv.Document, doc)))) DocumentView.DeselectAll(); if (result.length !== value.length) { - if (doc instanceof Doc) { - const ind = DocListCast(targetDataDoc[this._props.fieldKey]).indexOf(doc); + if (docIn instanceof Doc) { + const ind = DocListCast(targetDataDoc[this._props.fieldKey]).indexOf(docIn); const prev = ind && DocListCast(targetDataDoc[this._props.fieldKey])[ind - 1]; - this._props.removeDocument?.(doc); + this._props.removeDocument?.(docIn); if (ind > 0 && prev) { - FormattedTextBox.SetSelectOnLoad(prev); - DocumentManager.Instance.getDocumentView(prev, this.DocumentView?.())?.select(false); + Doc.SetSelectOnLoad(prev); + DocumentView.getDocumentView(prev, this.DocumentView?.())?.select(false); } return true; } - return this._props.removeDocument?.(doc) ?? false; + return this._props.removeDocument?.(docIn) ?? false; } return false; }; @action addDoc = (docs: Doc | Doc[], relativeTo: Opt<Doc>, before?: boolean): boolean => { - const doclist = docs instanceof Doc ? [docs] : docs; - const addDocRelativeTo = (doc: Doc | Doc[]) => doclist.reduce((flg, doc) => flg && Doc.AddDocToList(this.Document[DocData], this._props.fieldKey, doc, relativeTo, before), true); + const addDocRelativeTo = (adocs: Doc | Doc[]) => (adocs as Doc[]).reduce((flg, doc) => flg && Doc.AddDocToList(this.Document[DocData], this._props.fieldKey, doc, relativeTo, before), true); if (this.Document.resolvedDataDoc instanceof Promise) return false; - const res = relativeTo === undefined ? this._props.addDocument?.(docs) || false : addDocRelativeTo(docs); + const doclist = toList(docs); + const res = relativeTo === undefined ? this._props.addDocument?.(doclist) || false : addDocRelativeTo(doclist); res && doclist.forEach(doc => { Doc.SetContainer(doc, this.Document); @@ -207,7 +206,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree }); return res; }; - onContextMenu = (e: React.MouseEvent): void => { + onContextMenu = (): void => { // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout const layoutItems: ContextMenuProps[] = []; const menuDoc = ScriptCast(Cast(this.layoutDoc.layout_headerButton, Doc, null)?.onClick).script.originalScript === CollectionTreeView.AddTreeFunc; @@ -215,11 +214,11 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree if (!Doc.noviceMode) { layoutItems.push({ description: 'Make tree state ' + (this.Document.treeView_OpenIsTransient ? 'persistent' : 'transient'), - event: () => (this.Document.treeView_OpenIsTransient = !this.Document.treeView_OpenIsTransient), + event: () => { this.Document.treeView_OpenIsTransient = !this.Document.treeView_OpenIsTransient; }, // prettier-ignore icon: 'paint-brush', }); - layoutItems.push({ description: (this.Document.treeView_HideHeaderFields ? 'Show' : 'Hide') + ' Header Fields', event: () => (this.Document.treeView_HideHeaderFields = !this.Document.treeView_HideHeaderFields), icon: 'paint-brush' }); - layoutItems.push({ description: (this.Document.treeView_HideTitle ? 'Show' : 'Hide') + ' Title', event: () => (this.Document.treeView_HideTitle = !this.Document.treeView_HideTitle), icon: 'paint-brush' }); + layoutItems.push({ description: (this.Document.treeView_HideHeaderFields ? 'Show' : 'Hide') + ' Header Fields', event: () => { this.Document.treeView_HideHeaderFields = !this.Document.treeView_HideHeaderFields; }, icon: 'paint-brush' }); // prettier-ignore + layoutItems.push({ description: (this.Document.treeView_HideTitle ? 'Show' : 'Hide') + ' Title', event: () => { this.Document.treeView_HideTitle = !this.Document.treeView_HideTitle; }, icon: 'paint-brush' }); // prettier-ignore } ContextMenu.Instance.addItem({ description: 'Options...', subitems: layoutItems, icon: 'eye' }); if (!Doc.noviceMode) { @@ -238,9 +237,9 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree return ( <EditableView contents={this.dataDoc.title} - display={'block'} + display="block" maxHeight={72} - height={'auto'} + height="auto" GetValue={() => StrCast(this.dataDoc.title)} SetValue={undoBatch((value: string, shift: boolean, enter: boolean) => { if (enter && this.Document.treeView_Type === TreeViewType.outline) this.makeTextCollection(this.treeChildren); @@ -251,22 +250,24 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree ); } - onKey = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { + onKey = (e: React.KeyboardEvent /* , fieldProps: FieldViewProps */) => { if (this.outlineMode && e.key === 'Enter') { e.stopPropagation(); this.makeTextCollection(this.treeChildren); return true; } + return undefined; }; get documentTitle() { return ( <FormattedTextBox + // eslint-disable-next-line react/jsx-props-no-spreading {...this._props} fieldKey="text" renderDepth={this._props.renderDepth + 1} isContentActive={this.isContentActive} isDocumentActive={this.isContentActive} - forceAutoHeight={true} // needed to make the title resize even if the rest of the tree view is not layout_autoHeight + forceAutoHeight // needed to make the title resize even if the rest of the tree view is not layout_autoHeight PanelWidth={this.documentTitleWidth} PanelHeight={this.documentTitleHeight} NativeDimScaling={returnOne} @@ -292,9 +293,14 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree @computed get treeViewElements() { TraceMobx(); const dragAction = StrCast(this.Document.childDragAction) as any as dropActionType; - const addDoc = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before); + const treeAddDoc = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before); const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this._props.moveDocument?.(d, target, addDoc) || false; - if (this._renderCount < this.treeChildren.length) setTimeout(action(() => (this._renderCount = Math.min(this.treeChildren.length, this._renderCount + 20)))); + if (this._renderCount < this.treeChildren.length) + setTimeout( + action(() => { + this._renderCount = Math.min(this.treeChildren.length, this._renderCount + 20); + }) + ); return TreeView.GetChildElements( this.treeChildren, this, @@ -303,7 +309,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree this._props.TemplateDataDocument, undefined, undefined, - addDoc, + treeAddDoc, this.remove, moveDoc, dragAction, @@ -324,7 +330,6 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree this.observeHeight, this.unobserveHeight, this.childContextMenuItems(), - //TODO: [AL] add these this._props.AddToMap, this._props.RemFromMap, this._props.hierarchyIndex, @@ -335,7 +340,9 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree return this.dataDoc === null ? null : ( <div className="collectionTreeView-titleBar" - ref={action((r: any) => (this._titleRef = r) && (this._titleHeight = r.getBoundingClientRect().height * this.ScreenToLocalBoxXf().Scale))} + ref={action((r: any) => { + (this._titleRef = r) && (this._titleHeight = r.getBoundingClientRect().height * this.ScreenToLocalBoxXf().Scale); + })} key={this.Document[Id]} style={!this.outlineMode ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}}> {this.outlineMode ? this.documentTitle : this.editableTitle} @@ -406,8 +413,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree addAnnotationDocument = (doc: Doc | Doc[]) => this.addDocument(doc, `${this._props.fieldKey}_annotations`) || false; remAnnotationDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, `${this._props.fieldKey}_annotations`) || false; - moveAnnotationDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => - this.moveDocument(doc, targetCollection, addDocument, `${this._props.fieldKey}_annotations`) || false; + moveAnnotationDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => this.moveDocument(doc, targetCollection, addDocument) || false; @observable _headerHeight = 0; @computed get content() { @@ -418,7 +424,11 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree return ( <div style={{ display: 'flex', flexDirection: 'column', height: '100%', pointerEvents: 'all' }}> {!this.buttonMenu && !this.noviceExplainer ? null : ( - <div className="documentButtonMenu" ref={action((r: HTMLDivElement | null) => r && (this._headerHeight = DivHeight(r)))}> + <div + className="documentButtonMenu" + ref={action((r: HTMLDivElement | null) => { + r && (this._headerHeight = DivHeight(r)); + })}> {this.buttonMenu} {this.noviceExplainer} </div> @@ -451,7 +461,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree minHeight: '100%', }} onWheel={e => e.stopPropagation()} - onClick={e => (!this.layoutDoc.forceActive ? this._props.select(false) : SelectionManager.DeselectAll())} + onClick={() => (!this.layoutDoc.forceActive ? this._props.select(false) : DocumentView.DeselectAll())} onDrop={this.onTreeDrop}> <ul className={`no-indent${this.outlineMode ? '-outline' : ''}`}>{this.treeViewElements}</ul> </div> @@ -468,13 +478,14 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree <div style={{ transform: `scale(${scale})`, transformOrigin: 'top left', width: `${100 / scale}%`, height: `${100 / scale}%` }}> {!(this.Document instanceof Doc) || !this.treeChildren ? null : this.Document.treeView_HasOverlay ? ( <CollectionFreeFormView + // eslint-disable-next-line react/jsx-props-no-spreading {...this._props} setContentViewBox={emptyFunction} NativeWidth={returnZero} NativeHeight={returnZero} pointerEvents={this._props.isContentActive() && SnappingManager.IsDragging ? returnAll : returnNone} - isAnnotationOverlay={true} - isAnnotationOverlayScrollable={true} + isAnnotationOverlay + isAnnotationOverlayScrollable childDocumentsActive={this._props.isContentActive} fieldKey={this._props.fieldKey + '_annotations'} dropAction={dropActionType.move} @@ -498,6 +509,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree } } +// eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function addTreeFolder(doc: Doc) { CollectionTreeView.addTreeFolder(doc); }); |