From 2a4e86be98ad0f8d4aa4cb09b982d448b542d916 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 22 Mar 2023 14:20:09 -0400 Subject: removed gitlike and branch stuff. updated fortawesome. added Z ordering buttons. moved ctrl-t/alt-t to edit text title into formattedTextBox --- src/client/views/collections/CollectionView.tsx | 38 ++++++++++++------------- 1 file changed, 18 insertions(+), 20 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index aed88aa1a..eafa50d27 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -2,7 +2,6 @@ import { computed, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast } from '../../../fields/Doc'; -import { Id } from '../../../fields/FieldSymbols'; import { ObjectField } from '../../../fields/ObjectField'; import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types'; @@ -10,13 +9,12 @@ import { TraceMobx } from '../../../fields/util'; import { returnEmptyString } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { CollectionViewType } from '../../documents/DocumentTypes'; -import { BranchCreate, BranchTask } from '../../documents/Gitlike'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; import { InteractionUtils } from '../../util/InteractionUtils'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; -import { OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; +import { OpenWhere } from '../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { CollectionCarousel3DView } from './CollectionCarousel3DView'; import { CollectionCarouselView } from './CollectionCarouselView'; @@ -193,23 +191,23 @@ export class CollectionView extends ViewBoxAnnotatableComponent (this.rootDoc._isLightbox = !this.rootDoc._isLightbox), icon: 'project-diagram' }); - if (!Doc.noviceMode && false) { - optionItems.push({ - description: 'Create Branch', - event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), OpenWhere.addRight), - icon: 'project-diagram', - }); - optionItems.push({ - description: 'Pull Master', - event: () => BranchTask(this.rootDoc, 'pull'), - icon: 'project-diagram', - }); - optionItems.push({ - description: 'Merge Branches', - event: () => BranchTask(this.rootDoc, 'merge'), - icon: 'project-diagram', - }); - } + // if (!Doc.noviceMode && false) { + // optionItems.push({ + // description: 'Create Branch', + // event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), OpenWhere.addRight), + // icon: 'project-diagram', + // }); + // optionItems.push({ + // description: 'Pull Master', + // event: () => BranchTask(this.rootDoc, 'pull'), + // icon: 'project-diagram', + // }); + // optionItems.push({ + // description: 'Merge Branches', + // event: () => BranchTask(this.rootDoc, 'merge'), + // icon: 'project-diagram', + // }); + // } !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'hand-point-right' }); -- cgit v1.2.3-70-g09d2 From 3a3e496dda5f9a1f5286a2c9f62524de59794ade Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 24 Mar 2023 03:37:41 -0400 Subject: overhaul of selection api so that schema and other views behave like freeform and use document views onClick for selection --- src/client/util/SelectionManager.ts | 45 +-- .../views/collections/CollectionCarousel3DView.tsx | 149 +++++----- src/client/views/collections/CollectionView.tsx | 2 +- .../CollectionFreeFormLayoutEngines.tsx | 7 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 9 +- .../collectionFreeForm/MarqueeOptionsMenu.tsx | 2 - .../CollectionMulticolumnView.tsx | 3 +- .../CollectionMultirowView.tsx | 3 +- .../collectionSchema/CollectionSchemaView.tsx | 318 +++++++++------------ .../collections/collectionSchema/SchemaRowBox.tsx | 31 +- .../nodes/CollectionFreeFormDocumentView.scss | 4 +- src/client/views/nodes/DocumentView.tsx | 18 +- 12 files changed, 282 insertions(+), 309 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 0f4f77588..313c255a0 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -1,3 +1,4 @@ +import { ModalManager } from '@material-ui/core'; import { action, observable, ObservableMap } from 'mobx'; import { computedFn } from 'mobx-utils'; import { Doc, Opt } from '../../fields/Doc'; @@ -10,7 +11,8 @@ import { ScriptingGlobals } from './ScriptingGlobals'; export namespace SelectionManager { class Manager { @observable IsDragging: boolean = false; - SelectedViews: ObservableMap = new ObservableMap(); + SelectedViewsMap: ObservableMap = new ObservableMap(); + @observable SelectedViews: DocumentView[] = []; @observable SelectedSchemaDocument: Doc | undefined; @action @@ -20,7 +22,7 @@ export namespace SelectionManager { @action SelectView(docView: DocumentView, ctrlPressed: boolean): void { // if doc is not in SelectedDocuments, add it - if (!manager.SelectedViews.get(docView) && docView.props.Document.type !== DocumentType.MARKER) { + if (!manager.SelectedViewsMap.get(docView) && docView.props.Document.type !== DocumentType.MARKER) { if (!ctrlPressed) { if (LinkManager.currentLink && !LinkManager.Links(docView.rootDoc).includes(LinkManager.currentLink) && docView.rootDoc !== LinkManager.currentLink) { LinkManager.currentLink = undefined; @@ -28,33 +30,38 @@ export namespace SelectionManager { this.DeselectAll(); } - manager.SelectedViews.set(docView, docView.rootDoc); + manager.SelectedViews.push(docView); + manager.SelectedViewsMap.set(docView, docView.rootDoc); docView.props.whenChildContentsActiveChanged(true); - } else if (!ctrlPressed && (Array.from(manager.SelectedViews.entries()).length > 1 || manager.SelectedSchemaDocument)) { - Array.from(manager.SelectedViews.keys()).map(dv => dv !== docView && dv.props.whenChildContentsActiveChanged(false)); + } else if (!ctrlPressed && (Array.from(manager.SelectedViewsMap.entries()).length > 1 || manager.SelectedSchemaDocument)) { + Array.from(manager.SelectedViewsMap.keys()).map(dv => dv !== docView && dv.props.whenChildContentsActiveChanged(false)); manager.SelectedSchemaDocument = undefined; - manager.SelectedViews.clear(); - manager.SelectedViews.set(docView, docView.rootDoc); + manager.SelectedViews.length = 0; + manager.SelectedViewsMap.clear(); + manager.SelectedViews.push(docView); + manager.SelectedViewsMap.set(docView, docView.rootDoc); } } @action - DeselectView(docView: DocumentView): void { - if (manager.SelectedViews.get(docView)) { - manager.SelectedViews.delete(docView); + DeselectView(docView?: DocumentView): void { + if (docView && manager.SelectedViewsMap.get(docView)) { + manager.SelectedViewsMap.delete(docView); + manager.SelectedViews.splice(manager.SelectedViews.indexOf(docView), 1); docView.props.whenChildContentsActiveChanged(false); } } @action DeselectAll(): void { manager.SelectedSchemaDocument = undefined; - Array.from(manager.SelectedViews.keys()).forEach(dv => dv.props.whenChildContentsActiveChanged(false)); - manager.SelectedViews.clear(); + Array.from(manager.SelectedViewsMap.keys()).forEach(dv => dv.props.whenChildContentsActiveChanged(false)); + manager.SelectedViewsMap.clear(); + manager.SelectedViews.length = 0; } } const manager = new Manager(); - export function DeselectView(docView: DocumentView): void { + export function DeselectView(docView?: DocumentView): void { manager.DeselectView(docView); } export function SelectView(docView: DocumentView, ctrlPressed: boolean): void { @@ -67,7 +74,7 @@ export namespace SelectionManager { const IsSelectedCache = computedFn(function isSelected(doc: DocumentView) { // wrapping get() in a computedFn only generates mobx() invalidations when the return value of the function for the specific get parameters has changed - return manager.SelectedViews.get(doc) ? true : false; + return manager.SelectedViewsMap.get(doc) ? true : false; }); // computed functions, such as used in IsSelected generate errors if they're called outside of a // reaction context. Specifying the context with 'outsideReaction' allows an efficiency feature @@ -76,7 +83,7 @@ export namespace SelectionManager { return !doc ? false : outsideReaction - ? manager.SelectedViews.get(doc) + ? manager.SelectedViewsMap.get(doc) ? true : false // get() accesses a hashtable -- setting anything in the hashtable generates a mobx invalidation for every get() : IsSelectedCache(doc); @@ -85,7 +92,7 @@ export namespace SelectionManager { export function DeselectAll(except?: Doc): void { let found: DocumentView | undefined = undefined; if (except) { - for (const view of Array.from(manager.SelectedViews.keys())) { + for (const view of Array.from(manager.SelectedViewsMap.keys())) { if (view.props.Document === except) found = view; } } @@ -95,13 +102,15 @@ export namespace SelectionManager { } export function Views(): Array { - return Array.from(manager.SelectedViews.keys()); //.filter(dv => manager.SelectedViews.get(dv)?._viewType !== CollectionViewType.Docking); + return manager.SelectedViews; + // Array.from(manager.SelectedViewsMap.keys()); //.filter(dv => manager.SelectedViews.get(dv)?._viewType !== CollectionViewType.Docking); } export function SelectedSchemaDoc(): Doc | undefined { return manager.SelectedSchemaDocument; } export function Docs(): Doc[] { - return Array.from(manager.SelectedViews.values()).filter(doc => doc?._viewType !== CollectionViewType.Docking); + return manager.SelectedViews.map(dv => dv.rootDoc).filter(doc => doc?._viewType !== CollectionViewType.Docking); + // Array.from(manager.SelectedViewsMap.values()).filter(doc => doc?._viewType !== CollectionViewType.Docking); } } ScriptingGlobals.add(function SelectionManager_selectedDocType(type: string, expertMode: boolean, checkContext?: boolean) { diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 01f41869e..57ff1b292 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -9,7 +9,7 @@ import { OmitKeys, returnFalse, Utils } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; import { DocumentView } from '../nodes/DocumentView'; import { StyleProp } from '../StyleProvider'; -import "./CollectionCarousel3DView.scss"; +import './CollectionCarousel3DView.scss'; import { CollectionSubView } from './CollectionSubView'; @observer @@ -20,134 +20,143 @@ export class CollectionCarousel3DView extends CollectionSubView() { private _dropDisposer?: DragManager.DragDropDisposer; - componentWillUnmount() { this._dropDisposer?.(); } + componentWillUnmount() { + this._dropDisposer?.(); + } - protected createDashEventsTarget = (ele: HTMLDivElement | null) => { //used for stacking and masonry view + protected createDashEventsTarget = (ele: HTMLDivElement | null) => { + //used for stacking and masonry view this._dropDisposer?.(); if (ele) { this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); } - } + }; panelWidth = () => this.props.PanelWidth() / 3; panelHeight = () => this.props.PanelHeight() * 0.6; onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick); + isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive(); + isChildContentActive = () => (this.isContentActive() ? true : false); + @computed get content() { const currentIndex = NumCast(this.layoutDoc._itemIndex); - const displayDoc = (childPair: { layout: Doc, data: Doc }) => { - return ; + const displayDoc = (childPair: { layout: Doc; data: Doc }) => { + return ( + + ); }; - return (this.childLayoutPairs.map((childPair, index) => { + return this.childLayoutPairs.map((childPair, index) => { return ( -
+
{displayDoc(childPair)} -
); - })); +
+ ); + }); } changeSlide = (direction: number) => { this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) + direction + this.childLayoutPairs.length) % this.childLayoutPairs.length; - } + }; onArrowClick = (e: React.MouseEvent, direction: number) => { e.stopPropagation(); this.changeSlide(direction); - !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = (direction === 1) ? "fwd" : "back"); // while autoscroll is on, keep the other autoscroll button hidden + !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = direction === 1 ? 'fwd' : 'back'); // while autoscroll is on, keep the other autoscroll button hidden !this.layoutDoc.autoScrollOn && this.fadeScrollButton(); // keep pause button visible while autoscroll is on - } + }; interval?: number; startAutoScroll = (direction: number) => { this.interval = window.setInterval(() => { this.changeSlide(direction); }, this.scrollSpeed); - } + }; stopAutoScroll = () => { window.clearInterval(this.interval); this.interval = undefined; this.fadeScrollButton(); - } + }; toggleAutoScroll = (direction: number) => { this.layoutDoc.autoScrollOn = this.layoutDoc.autoScrollOn ? false : true; this.layoutDoc.autoScrollOn ? this.startAutoScroll(direction) : this.stopAutoScroll(); - } + }; fadeScrollButton = () => { window.setTimeout(() => { - !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = "none"); //fade away after 1.5s if it's not clicked. + !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = 'none'); //fade away after 1.5s if it's not clicked. }, 1500); - } + }; @computed get buttons() { if (!this.props.isContentActive()) return null; - return
-
this.onArrowClick(e, -1)} - > - -
-
this.onArrowClick(e, 1)} - > - + return ( +
+
this.onArrowClick(e, -1)}> + +
+
this.onArrowClick(e, 1)}> + +
+ {this.autoScrollButton}
- {this.autoScrollButton} -
; + ); } @computed get autoScrollButton() { const whichButton = this.layoutDoc.showScrollButton; - return <> -
this.toggleAutoScroll(-1)}> - {this.layoutDoc.autoScrollOn ? : } -
-
this.toggleAutoScroll(1)}> - {this.layoutDoc.autoScrollOn ? : } -
- ; + return ( + <> +
this.toggleAutoScroll(-1)}> + {this.layoutDoc.autoScrollOn ? : } +
+
this.toggleAutoScroll(1)}> + {this.layoutDoc.autoScrollOn ? : } +
+ + ); } @computed get dots() { - return (this.childLayoutPairs.map((_child, index) => -
this.layoutDoc._itemIndex = index} />)); + return this.childLayoutPairs.map((_child, index) =>
(this.layoutDoc._itemIndex = index)} />); } render() { const index = NumCast(this.layoutDoc._itemIndex); const translateX = this.panelWidth() * (1 - index); - return
-
- {this.content} -
- {this.props.Document._chromeHidden ? (null) : this.buttons} -
- {this.dots} + return ( +
+
+ {this.content} +
+ {this.props.Document._chromeHidden ? null : this.buttons} +
{this.dots}
-
; + ); } -} \ No newline at end of file +} diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index eafa50d27..51624689e 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -257,7 +257,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent this.props.isContentActive(); + isContentActive = (outsideReaction?: boolean) => this.props.isContentActive() || this.isAnyChildContentActive(); render() { TraceMobx(); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index fa0695fb2..81b0c4d8a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -116,6 +116,8 @@ export function computeStarburstLayout(poolData: Map, pivotDoc zIndex: NumCast(layout.zIndex), pair: { layout, data }, replica: '', + color: 'white', + backgroundColor: 'white', }); }); const divider = { type: 'div', color: 'transparent', x: -burstRadius[0], y: 0, width: 15, height: 15, payload: undefined }; @@ -408,7 +410,7 @@ function normalizeResults( .map(ele => { const newPosRaw = ele[1]; if (newPosRaw) { - const newPos = { + const newPos: PoolData = { x: newPosRaw.x * scale, y: newPosRaw.y * scale, z: newPosRaw.z, @@ -417,6 +419,9 @@ function normalizeResults( zIndex: newPosRaw.zIndex, width: (newPosRaw.width || 0) * scale, height: newPosRaw.height! * scale, + backgroundColor: newPosRaw.backgroundColor, + opacity: newPosRaw.opacity, + color: newPosRaw.color, pair: ele[1].pair, }; poolData.set(newPos.pair.layout[Id] + (newPos.replica || ''), { transition: 'all 1s', ...newPos }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3a8edb1a5..4f81af95d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1291,10 +1291,9 @@ export class CollectionFreeFormView extends CollectionSubView { const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); - const pointerEvents = - this.props.isContentActive() === false || DocumentDecorations.Instance.Interacting - ? 'none' - : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.()); + const pointerEvents = DocumentDecorations.Instance.Interacting + ? 'none' + : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.()); return pointerEvents; }; getChildDocView(entry: PoolData) { @@ -1995,7 +1994,7 @@ export class CollectionFreeFormView extends CollectionSubView Doc.AreProtosEqual(DocCast(doc.context), this.props.Document))); + return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.context), this.props.Document)); } @observable _rowEles: ObservableMap = new ObservableMap(); @observable _colEles: HTMLDivElement[] = []; - @observable _isDragging: boolean = false; @observable _displayColumnWidths: number[] | undefined; @observable _columnMenuIndex: number | undefined; @observable _menuOptions: string[] = []; @@ -133,7 +128,7 @@ export class CollectionSchemaView extends CollectionSubView() { } componentDidMount() { - this.props.setContentView?.(this as DocComponentView); + this.props.setContentView?.(this); document.addEventListener('keydown', this.onKeyDown); } @@ -143,24 +138,36 @@ export class CollectionSchemaView extends CollectionSubView() { @action onKeyDown = (e: KeyboardEvent) => { - if (this._selectedDocs.size > 0) { - if (e.key == 'ArrowDown') { - const lastDoc = Array.from(this._selectedDocs.values()).lastElement(); - const lastIndex = this.rowIndex(lastDoc); - if (lastIndex >= 0 && lastIndex < this.childDocs.length - 1) { - !e.shiftKey && this.clearSelection(); - const newDoc = this.childDocs[lastIndex + 1]; - this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1); - } - } - if (e.key == 'ArrowUp') { - const firstDoc = Array.from(this._selectedDocs.values())[0]; - const firstIndex = this.rowIndex(firstDoc); - if (firstIndex > 0 && firstIndex < this.childDocs.length) { - !e.shiftKey && this.clearSelection(); - const newDoc = this.childDocs[firstIndex - 1]; - this.addDocToSelection(newDoc, e.shiftKey, firstIndex - 1); - } + if (this._selectedDocs.length > 0) { + switch (e.key) { + case 'ArrowDown': + { + const lastDoc = this._selectedDocs.lastElement(); + const lastIndex = this.rowIndex(lastDoc); + const curDoc = this.childDocs[lastIndex]; + if (lastIndex >= 0 && lastIndex < this.childDocs.length - 1) { + !e.shiftKey && this.clearSelection(); + const newDoc = this.childDocs[lastIndex + 1]; + if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc)); + else this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1); + } + e.stopPropagation(); + } + break; + case 'ArrowUp': + { + const firstDoc = this._selectedDocs.lastElement(); + const firstIndex = this.rowIndex(firstDoc); + const curDoc = this.childDocs[firstIndex]; + if (firstIndex > 0 && firstIndex < this.childDocs.length) { + !e.shiftKey && this.clearSelection(); + const newDoc = this.childDocs[firstIndex - 1]; + if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc)); + else this.addDocToSelection(newDoc, e.shiftKey, firstIndex - 1); + } + e.stopPropagation(); + } + break; } } }; @@ -326,60 +333,25 @@ export class CollectionSchemaView extends CollectionSubView() { addDocToSelection = (doc: Doc, extendSelection: boolean, index: number) => { const rowDocView = DocumentManager.Instance.getDocumentView(doc); if (rowDocView) SelectionManager.SelectView(rowDocView, extendSelection); - this._lastSelectedRow = index; - }; - - @action - removeDocFromSelection = (doc: Doc) => { - const rowDocView = DocumentManager.Instance.getDocumentView(doc); - if (rowDocView) SelectionManager.DeselectView(rowDocView); - if (this._selectedDocs.size === 0) { - this._lastSelectedRow = undefined; - } }; @action - clearSelection = () => { - SelectionManager.DeselectAll(); - this._lastSelectedRow = undefined; - }; - - rowOnClickScript = ScriptField.MakeFunction('scriptContext.selectRow(self, shiftKey, ctrlKey || metaKey)', { scriptContext: 'any', shiftKey: 'boolean', ctrlKey: 'boolean', metaKey: 'boolean' })!; - - @action - selectRow = (doc: Doc, shift: boolean, ctrl: boolean) => { - const index = this.childDocs.indexOf(doc); - if (index < 0) return; - if (shift && this._lastSelectedRow !== undefined) { - const startRow = Math.min(this._lastSelectedRow, index); - const endRow = Math.max(this._lastSelectedRow, index); - for (let i = startRow; i <= endRow; i++) { - const currDoc = this.childDocs[i]; - if (!this._selectedDocs.has(currDoc)) this.addDocToSelection(currDoc, true, i); - } - this._lastSelectedRow = index; - } else if (ctrl) { - if (!this._selectedDocs.has(doc)) { - this.addDocToSelection(doc, true, index); - } else { - this.removeDocFromSelection(doc); - } - } else { - if (!this._selectedDocs.has(doc)) { - this.clearSelection(); - this.addDocToSelection(doc, false, index); - } + clearSelection = () => SelectionManager.DeselectAll(); + + selectRows = (rootDoc: Doc, lastSelected: Doc) => { + const index = this.childDocs.indexOf(rootDoc); + const lastSelectedRow = this.childDocs.indexOf(lastSelected); + const startRow = Math.min(lastSelectedRow, index); + const endRow = Math.max(lastSelectedRow, index); + for (let i = startRow; i <= endRow; i++) { + const currDoc = this.childDocs[i]; + if (!this._selectedDocs.includes(currDoc)) this.addDocToSelection(currDoc, true, i); } }; - @action - sortedSelectedDocs = (): Doc[] => { - return this.childDocs.filter(doc => this._selectedDocs.has(doc)); - }; + sortedSelectedDocs = () => this.childDocs.filter(doc => this._selectedDocs.includes(doc)); - setDropIndex = (index: number) => { - this._closestDropIndex = index; - }; + setDropIndex = (index: number) => (this._closestDropIndex = index); @action onInternalDrop = (e: Event, de: DragManager.DropEvent) => { @@ -394,17 +366,20 @@ export class CollectionSchemaView extends CollectionSubView() { return total + curr; }, CollectionSchemaView._rowMenuWidth); this.swapColumns(de.complete.columnDragData.colIndex, i); + e.stopPropagation(); return true; } - if (super.onInternalDrop(e, de)) { - this._isDragging = false; - const pushedDocs: Doc[] = this.childDocs.filter((doc: Doc, index: number) => index >= this._closestDropIndex && !this._selectedDocs.has(doc)); + const draggedDocs = de.complete.docDragData?.draggedDocuments; + if (draggedDocs && super.onInternalDrop(e, de)) { + const pushedDocs = this.childDocs.filter((doc, index) => index >= this._closestDropIndex && !draggedDocs.includes(doc)); this.props.removeDocument?.(pushedDocs); - this.props.removeDocument?.(this._selectedDocSortedArray); - this.addDocument(this._selectedDocSortedArray); + this.props.removeDocument?.(draggedDocs); + this.addDocument(draggedDocs); this.addDocument(pushedDocs); this.setSort(undefined); - this.clearSelection(); + SelectionManager.DeselectAll(); + setTimeout(() => draggedDocs.forEach(doc => DocumentManager.Instance.AddViewRenderedCb(doc, dv => dv.select(true))), 100); + e.stopPropagation(); return true; } return false; @@ -412,46 +387,11 @@ export class CollectionSchemaView extends CollectionSubView() { @action onExternalDrop = async (e: React.DragEvent): Promise => { - super.onExternalDrop( - e, - {}, - undoBatch( - action(docus => { - this._isDragging = false; - docus.map((doc: Doc) => { - this.addDocument(doc); - }); - }) - ) - ); + super.onExternalDrop(e, {}, undoBatch(action(docus => docus.map((doc: Doc) => this.addDocument(doc))))); this.setSort(undefined); }; - @action - startDrag = (e: PointerEvent, doc: Doc, index: number) => { - if (!this._selectedDocs.has(doc)) { - this.clearSelection(); - this.addDocToSelection(doc, false, index); - } - this._isDragging = true; - this._selectedDocSortedArray = this.sortedSelectedDocs(); - const dragData = new DragManager.DocumentDragData(this._selectedDocSortedArray, 'move'); - dragData.moveDocument = this.props.moveDocument; - const dragItem: HTMLElement[] = Array.from(this._selectedDocs.values()).map((doc: Doc) => this._rowEles.get(doc)); - - DragManager.StartDocumentDrag( - dragItem.map(ele => ele), - dragData, - e.clientX, - e.clientY, - undefined - ); - return true; - }; - - onDividerDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, emptyFunction); - }; + onDividerDown = (e: React.PointerEvent) => setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, emptyFunction); @action onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => { @@ -557,9 +497,6 @@ export class CollectionSchemaView extends CollectionSubView() { return undefined; }; - isChildContentActive = () => - this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : this.props.childDocumentsActive?.() === false || this.rootDoc.childDocumentsActive === false ? false : undefined; - @computed get fieldDefaultInput() { switch (this._newFieldType) { case ColumnType.Number: @@ -644,23 +581,17 @@ export class CollectionSchemaView extends CollectionSubView() { ContextMenu.Instance.clearItems(); ContextMenu.Instance.addItem({ description: 'Change field', - event: () => { - this.openColumnMenu(index, false); - }, + event: () => this.openColumnMenu(index, false), icon: 'pencil-alt', }); ContextMenu.Instance.addItem({ description: 'Filter field', - event: () => { - this.openFilterMenu(index); - }, + event: () => this.openFilterMenu(index), icon: 'filter', }); ContextMenu.Instance.addItem({ description: 'Delete column', - event: () => { - this.removeColumn(index); - }, + event: () => this.removeColumn(index), icon: 'trash', }); ContextMenu.Instance.displayMenu(x, y, undefined, false); @@ -672,9 +603,7 @@ export class CollectionSchemaView extends CollectionSubView() { this._menuOptions = this.documentKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase())); }; - getFieldFilters = (field: string) => { - return StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field); - }; + getFieldFilters = (field: string) => StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field); removeFieldFilters = (field: string) => { this.getFieldFilters(field).forEach(filter => { @@ -694,9 +623,7 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - updateFilterSearch = (e: React.ChangeEvent) => { - this._filterValue = e.target.value; - }; + updateFilterSearch = (e: React.ChangeEvent) => (this._filterValue = e.target.value); @computed get newFieldMenu() { return ( @@ -705,7 +632,6 @@ export class CollectionSchemaView extends CollectionSubView() { { this._newFieldType = ColumnType.Number; @@ -718,7 +644,6 @@ export class CollectionSchemaView extends CollectionSubView() { { this._newFieldType = ColumnType.Boolean; @@ -731,7 +656,6 @@ export class CollectionSchemaView extends CollectionSubView() { { this._newFieldType = ColumnType.String; @@ -880,13 +804,11 @@ export class CollectionSchemaView extends CollectionSubView() { ); } - tableWidthFunc = () => this.tableWidth; - rowHeightFunc = () => CollectionSchemaView._rowHeight; - rowClickScriptFunc = () => this.rowOnClickScript; isContentActive = () => this.props.isSelected() || this.props.isContentActive(); screenToLocal = () => this.props.ScreenToLocalTransform().translate(-this.tableWidth, 0); previewWidthFunc = () => this.previewWidth; render() { + trace(); return (
{ + // this is analogous to the panning code for a freeform view. + // however, schema views don't pan so it does nothing. but it does eat the pointerDown event + // if the content is active to prevent the schema from being dragged + this.isContentActive() && setupMoveUpEvents(this, e, returnFalse, emptyFunction, emptyFunction, false); + }} onDrop={this.onExternalDrop.bind(this)}>
@@ -927,53 +855,16 @@ export class CollectionSchemaView extends CollectionSubView() {
{this._columnMenuIndex !== undefined && this.renderColumnMenu} {this._filterColumnIndex !== undefined && this.renderFilterMenu} -
- {this.childDocs.map((doc: Doc, index: number) => { - const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.DataDoc; - let dref: Opt; - return ( -
- (dref = r || undefined)} - LayoutTemplate={this.props.childLayoutTemplate} - LayoutTemplateString={SchemaRowBox.LayoutString(this.props.fieldKey)} - Document={doc} - DataDoc={dataDoc} - ContainingCollectionView={this.props.CollectionView} - ContainingCollectionDoc={this.Document} - PanelWidth={this.tableWidthFunc} - PanelHeight={this.rowHeightFunc} - styleProvider={DefaultStyleProvider} - focus={this.focusDocument} - docFilters={this.childDocFilters} - docRangeFilters={this.childDocRangeFilters} - searchFilterDocs={this.searchFilterDocs} - rootSelected={this.rootSelected} - ScreenToLocalTransform={Transform.Identity} - bringToFront={emptyFunction} - isDocumentActive={this.isContentActive} - isContentActive={emptyFunction} - hideDecorations={true} - hideTitle={true} - hideDocumentButtonBar={true} - hideLinkAnchors={true} - fitWidth={returnTrue} - onClick={this.rowClickScriptFunc} - scriptContext={this} - /> -
- ); - })} -
+ +
{this.previewWidth > 0 &&
} {this.previewWidth > 0 && (
(this._previewRef = ref)}> - {this._lastSelectedRow !== undefined && ( + {Array.from(this._selectedDocs).lastElement() && ( { + tableWidthFunc = () => this.props.schema.tableWidth; + rowHeightFunc = () => CollectionSchemaView._rowHeight; + render() { + return ( +
+ {this.props.schema.childDocs.map((doc: Doc, index: number) => { + const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.schema.props.DataDoc; + return ( +
+ this.props.schema.props.whenChildContentsActiveChanged(active)} + hideDecorations={true} + hideTitle={true} + hideDocumentButtonBar={true} + hideLinkAnchors={true} + fitWidth={returnTrue} + scriptContext={this} + /> +
+ ); + })} +
+ ); + } +} diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 87284be70..0c8c0ee59 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -1,9 +1,9 @@ import React = require('react'); import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed } from 'mobx'; +import { computed } from 'mobx'; import { observer } from 'mobx-react'; -import { emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import { DragManager } from '../../../util/DragManager'; +import { SnappingManager } from '../../../util/SnappingManager'; import { undoBatch } from '../../../util/UndoManager'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { Colors } from '../../global/globalEnums'; @@ -36,24 +36,30 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { return this.schemaView?.rowIndex(this.rootDoc) ?? -1; } - @action - onRowPointerDown = (e: React.PointerEvent) => { - if (!this.isContentActive()) return; - setupMoveUpEvents(this, e, e => this.schemaView?.startDrag(e, this.rootDoc, this.rowIndex) ?? true, emptyFunction, emptyFunction); + componentDidMount(): void { + this.props.setContentView?.(this); + } + + select = (ctrlKey: boolean, shiftKey: boolean) => { + if (!this.schemaView) return; + const lastSelected = Array.from(this.schemaView._selectedDocs).lastElement(); + if (shiftKey && lastSelected) this.schemaView.selectRows(this.rootDoc, lastSelected); + else { + this.props.select?.(ctrlKey); + } }; onPointerEnter = (e: any) => { - if (!this.schemaView?._isDragging) return; + //if (!this.schemaView?._isDragging) return; + if (!SnappingManager.GetIsDragging()) return; document.removeEventListener('pointermove', this.onPointerMove); document.addEventListener('pointermove', this.onPointerMove); }; onPointerMove = (e: any) => { - if (!this.schemaView?._isDragging) return; - let dragIsRow: boolean = true; - DragManager.docsBeingDragged.forEach(doc => { - dragIsRow = this.schemaView?._selectedDocs.has(doc) ?? false; - }); + if (!SnappingManager.GetIsDragging()) return; + const dragIsRow = DragManager.docsBeingDragged.some(doc => doc.context === this.schemaDoc); // this.schemaView?._selectedDocs.has(doc) ?? false; + if (this._ref && dragIsRow) { const rect = this._ref.getBoundingClientRect(); const y = e.clientY - rect.top; //y position within the element. @@ -88,7 +94,6 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { ? { height: CollectionSchemaView._rowHeight, backgroundColor: Colors.LIGHT_BLUE, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined /*, opacity: this.props.dragging ? 0.5 : 1 */ } : { height: CollectionSchemaView._rowHeight, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined } } - onPointerDown={this.onRowPointerDown} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave} ref={(row: HTMLDivElement | null) => { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.scss b/src/client/views/nodes/CollectionFreeFormDocumentView.scss index 724394025..f99011b8f 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.scss +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.scss @@ -5,5 +5,5 @@ touch-action: manipulation; top: 0; left: 0; - pointer-events: none; -} \ No newline at end of file + //pointer-events: none; +} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c13934945..1f717932e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -121,6 +121,7 @@ export interface DocComponentView { addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox reverseNativeScaling?: () => boolean; // DocumentView's setup screenToLocal based on the doc having a nativeWidth/Height. However, some content views (e.g., FreeFormView w/ fitContentsToBox set) may ignore the native dimensions so this flags the DocumentView to not do Nativre scaling. shrinkWrap?: () => void; // requests a document to display all of its contents with no white space. currently only implemented (needed?) for freeform views + select?: (ctrlKey: boolean, shiftKey: boolean) => void; menuControls?: () => JSX.Element; // controls to display in the top menu bar when the document is selected. isAnyChildContentActive?: () => boolean; // is any child content of the document active getKeyFrameEditing?: () => boolean; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown) @@ -236,7 +237,7 @@ export interface DocumentViewInternalProps extends DocumentViewProps { NativeHeight: () => number; isSelected: (outsideReaction?: boolean) => boolean; isHovering: () => boolean; - select: (ctrlPressed: boolean) => void; + select: (ctrlPressed: boolean, shiftPress?: boolean) => void; DocumentView: () => DocumentView; viewPath: () => DocumentView[]; } @@ -538,7 +539,9 @@ export class DocumentViewInternal extends DocComponent dv.docView?._mainCont.current); + const selected = views.some(dv => dv.rootDoc === this.Document) ? views : [this.props.DocumentView()]; + const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.rootDoc)); const [left, top] = this.props.ScreenToLocalTransform().scale(this.NativeDimScaling).inverse().transformPoint(0, 0); dragData.offset = this.props .ScreenToLocalTransform() @@ -551,8 +554,13 @@ export class DocumentViewInternal extends DocComponent (ffview.ChildDrag = this.props.DocumentView())); - DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: hideSource || (!dropAction && !this.layoutDoc.onDragStart && !this.props.dontHideOnDrag) }, () => - setTimeout(action(() => ffview && (ffview.ChildDrag = undefined))) + DragManager.StartDocumentDrag( + selected.map(dv => dv.docView!._mainCont.current!), + dragData, + x, + y, + { hideSource: hideSource || (!dropAction && !this.layoutDoc.onDragStart && !this.props.dontHideOnDrag) }, + () => setTimeout(action(() => ffview && (ffview.ChildDrag = undefined))) ); // this needs to happen after the drop event is processed. ffview?.setupDragLines(false); } @@ -659,7 +667,7 @@ export class DocumentViewInternal extends DocComponent Date: Tue, 4 Apr 2023 20:12:16 -0400 Subject: fixed using freeformview in sidebar of pdfs. fixed issues with dragging items out of schema and with selecting the schema view by clicking on headers. Fixed a lot of errors caused by using OmitKeys which masks type checking. fixed some pointerevent problems with treeview and freeformview --- src/client/documents/Documents.ts | 22 ++-- src/client/views/DocumentDecorations.tsx | 40 +++--- src/client/views/EditableView.tsx | 4 +- src/client/views/InkStrokeProperties.ts | 1 - src/client/views/InkingStroke.tsx | 13 +- src/client/views/MainView.tsx | 1 + src/client/views/PropertiesView.tsx | 73 ++--------- src/client/views/SidebarAnnos.tsx | 15 +-- src/client/views/StyleProvider.tsx | 2 +- src/client/views/TemplateMenu.tsx | 2 +- .../views/collections/CollectionCarousel3DView.tsx | 7 +- .../views/collections/CollectionCarouselView.tsx | 8 +- .../collections/CollectionStackedTimeline.tsx | 54 +++----- .../views/collections/CollectionTreeView.tsx | 24 ++-- src/client/views/collections/CollectionView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 139 +++++++++++--------- .../collections/collectionFreeForm/MarqueeView.tsx | 2 + .../collectionGrid/CollectionGridView.tsx | 9 +- .../collectionSchema/CollectionSchemaView.tsx | 99 +++------------ .../collectionSchema/SchemaColumnHeader.tsx | 10 +- src/client/views/nodes/AudioBox.tsx | 6 +- src/client/views/nodes/ComparisonBox.tsx | 6 +- src/client/views/nodes/DocumentView.tsx | 26 +--- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 12 +- src/client/views/nodes/MapBox/MapBox.tsx | 6 +- src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx | 5 +- src/client/views/nodes/PDFBox.tsx | 141 ++++++++++++++++----- src/client/views/nodes/ScreenshotBox.tsx | 18 ++- src/client/views/nodes/VideoBox.tsx | 12 +- src/client/views/nodes/WebBox.tsx | 14 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 27 ++-- src/client/views/pdf/PDFViewer.tsx | 15 ++- src/fields/Doc.ts | 9 +- 34 files changed, 389 insertions(+), 437 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 9b8b9c877..9cb480c4a 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1420,41 +1420,39 @@ export namespace DocUtils { export function DocumentFromField(target: Doc, fieldKey: string, proto?: Doc, options?: DocumentOptions): Doc | undefined { let created: Doc | undefined; - let layout: ((fieldKey: string) => string) | undefined; const field = target[fieldKey]; - const resolved = options || {}; + const resolved = options ?? {}; if (field instanceof ImageField) { created = Docs.Create.ImageDocument(field.url.href, resolved); - layout = ImageBox.LayoutString; + created.layout = ImageBox.LayoutString(fieldKey); } else if (field instanceof Doc) { created = field; } else if (field instanceof VideoField) { created = Docs.Create.VideoDocument(field.url.href, resolved); - layout = VideoBox.LayoutString; + created.layout = VideoBox.LayoutString(fieldKey); } else if (field instanceof PdfField) { created = Docs.Create.PdfDocument(field.url.href, resolved); - layout = PDFBox.LayoutString; + created.layout = PDFBox.LayoutString(fieldKey); } else if (field instanceof AudioField) { created = Docs.Create.AudioDocument(field.url.href, resolved); - layout = AudioBox.LayoutString; + created.layout = AudioBox.LayoutString(fieldKey); } else if (field instanceof RecordingField) { created = Docs.Create.RecordingDocument(field.url.href, resolved); - layout = RecordingBox.LayoutString; + created.layout = RecordingBox.LayoutString(fieldKey); } else if (field instanceof InkField) { created = Docs.Create.InkDocument(ActiveInkColor(), Doc.ActiveTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), field.inkData, ActiveIsInkMask(), resolved); - layout = InkingStroke.LayoutString; + created.layout = InkingStroke.LayoutString(fieldKey); } else if (field instanceof List && field[0] instanceof Doc) { created = Docs.Create.StackingDocument(DocListCast(field), resolved); - layout = CollectionView.LayoutString; + created.layout = CollectionView.LayoutString(fieldKey); } else if (field instanceof MapField) { created = Docs.Create.MapDocument(DocListCast(field), resolved); - layout = MapBox.LayoutString; + created.layout = MapBox.LayoutString(fieldKey); } else { created = Docs.Create.TextDocument('', { ...{ _width: 200, _height: 25, _autoHeight: true }, ...resolved }); - layout = FormattedTextBox.LayoutString; + created.layout = FormattedTextBox.LayoutString(fieldKey); } if (created) { - created.layout = layout?.(fieldKey); created.title = fieldKey; proto && created.proto && (created.proto = Doc.GetProto(proto)); } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 985e6f88f..9bc583ce5 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -31,6 +31,7 @@ import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { ImageBox } from './nodes/ImageBox'; import React = require('react'); +import { RichTextField } from '../../fields/RichTextField'; @observer export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> { @@ -127,19 +128,23 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P } //@ts-ignore const titleField = +this._accumulatedTitle == this._accumulatedTitle ? +this._accumulatedTitle : this._accumulatedTitle; - Doc.SetInPlace(d.rootDoc, titleFieldKey, titleField, true); - if (d.rootDoc.syncLayoutFieldWithTitle) { - const title = titleField.toString(); + if (titleField.toString().startsWith('')) { + const title = titleField.toString().replace(/\.?/, ''); const curKey = Doc.LayoutFieldKey(d.rootDoc); - if (curKey !== title && d.dataDoc[title] === undefined) { - d.rootDoc.layout = FormattedTextBox.LayoutString(title); - setTimeout(() => { - const val = d.dataDoc[curKey]; - d.dataDoc[curKey] = undefined; - d.dataDoc[title] = val; - }); + if (curKey !== title) { + if (title) { + if (d.dataDoc[title] === undefined || d.dataDoc[title] instanceof RichTextField || typeof d.dataDoc[title] === 'string') { + d.rootDoc.layoutKey = `layout_${title}`; + d.rootDoc[`layout_${title}`] = FormattedTextBox.LayoutString(title); + d.rootDoc[`${title}-nativeWidth`] = d.rootDoc[`${title}-nativeHeight`] = 0; + } + } else { + d.rootDoc.layoutKey = undefined; + } } + } else { + Doc.SetInPlace(d.rootDoc, titleFieldKey, titleField, true); } }), 'title blur' @@ -453,17 +458,6 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P @action onPointerDown = (e: React.PointerEvent): void => { - const views = SelectionManager.Views().map(dv => dv.rootDoc); - this._inkDragDocs = views - .filter(doc => doc.type === DocumentType.INK) - .map(doc => { - if (InkStrokeProperties.Instance._lock) { - Doc.SetNativeHeight(doc, NumCast(doc._height)); - Doc.SetNativeWidth(doc, NumCast(doc._width)); - } - return { doc, x: NumCast(doc.x), y: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) }; - }); - setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction); this.Interacting = true; // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them this._resizeHdlId = e.currentTarget.className; @@ -487,10 +481,6 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P if (!first) return false; let thisPt = { x: e.clientX - this._offX, y: e.clientY - this._offY }; var fixedAspect = Doc.NativeAspect(first.layoutDoc); - InkStrokeProperties.Instance._lock && - SelectionManager.Views() - .filter(dv => dv.rootDoc.type === DocumentType.INK) - .forEach(dv => (fixedAspect = Doc.NativeAspect(dv.rootDoc))); const resizeHdl = this._resizeHdlId.split(' ')[0]; if (fixedAspect && (resizeHdl === 'documentDecorations-bottomRightResizer' || resizeHdl === 'documentDecorations-topLeftResizer')) { diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index bb190e93b..164b6c57a 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -129,7 +129,7 @@ export class EditableView extends React.Component { this._editing = true; this.props.isEditingCallback?.(true); } - e.stopPropagation(); + // e.stopPropagation(); } }; @@ -215,7 +215,7 @@ export class EditableView extends React.Component { className={`editableView-container-editing${this.props.oneLine ? '-oneLine' : ''}`} ref={this._ref} style={{ display: this.props.display, textOverflow: this.props.overflow, minHeight: '10px', whiteSpace: 'nowrap', height: this.props.height || 'auto', maxHeight: this.props.maxHeight }} - onPointerDown={e => e.stopPropagation()} + //onPointerDown={this.stopPropagation} onClick={this.onClick} placeholder={this.props.placeholder}> {this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()} diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index 1d8d52425..e6df0801c 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -19,7 +19,6 @@ export class InkStrokeProperties { return this._Instance || new InkStrokeProperties(); } - @observable _lock = false; @observable _controlButton = false; @observable _currentPoint = -1; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index e3642fdaf..2fd6cc4d6 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -25,10 +25,11 @@ import { action, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, HeightSym, WidthSym } from '../../fields/Doc'; import { InkData, InkField } from '../../fields/InkField'; -import { BoolCast, Cast, DocCast, NumCast, RTFCast, StrCast } from '../../fields/Types'; +import { BoolCast, Cast, NumCast, RTFCast, StrCast } from '../../fields/Types'; import { TraceMobx } from '../../fields/util'; -import { DashColor, OmitKeys, returnFalse, setupMoveUpEvents } from '../../Utils'; +import { DashColor, returnFalse, setupMoveUpEvents } from '../../Utils'; import { CognitiveServices } from '../cognitive_services/CognitiveServices'; +import { Docs } from '../documents/Documents'; import { InteractionUtils } from '../util/InteractionUtils'; import { SnappingManager } from '../util/SnappingManager'; import { Transform } from '../util/Transform'; @@ -41,13 +42,12 @@ import { InkControlPtHandles, InkEndPtHandles } from './InkControlPtHandles'; import './InkStroke.scss'; import { InkStrokeProperties } from './InkStrokeProperties'; import { InkTangentHandles } from './InkTangentHandles'; -import { DocComponentView, DocFocusOptions, DocumentView } from './nodes/DocumentView'; +import { DocComponentView } from './nodes/DocumentView'; import { FieldView, FieldViewProps } from './nodes/FieldView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; +import { PinProps, PresBox } from './nodes/trails'; import { StyleProp } from './StyleProvider'; import Color = require('color'); -import { Docs } from '../documents/Documents'; -import { PinProps, PresBox } from './nodes/trails'; @observer export class InkingStroke extends ViewBoxBaseComponent() { @@ -464,7 +464,8 @@ export class InkingStroke extends ViewBoxBaseComponent() { //top: (this.props.PanelHeight() - (lineHeightGuess * fsize + 20) * (this.props.NativeDimScaling?.() || 1)) / 2, }}> { @observable inOptions: boolean = false; @observable _controlButton: boolean = false; - @observable _lock: boolean = false; componentDidMount() { this.selectedDocListenerDisposer?.(); @@ -586,16 +585,6 @@ export class PropertiesView extends React.Component {
- {InkStrokeProperties.Instance._lock ? 'Unlock ratio' : 'Lock ratio'}
}> -
(InkStrokeProperties.Instance._lock = !InkStrokeProperties.Instance._lock))}> - -
- - {'Rotate 90Ëš'}
}> -
this.rotate(Math.PI / 2))}> - -
-
); } @@ -644,9 +633,6 @@ export class PropertiesView extends React.Component { @action upDownButtons = (dirs: string, field: string) => { switch (field) { - case 'rot': - this.rotate(dirs === 'up' ? 0.1 : -0.1); - break; case 'Xps': this.selectedDoc && (this.selectedDoc.x = NumCast(this.selectedDoc?.x) + (dirs === 'up' ? 10 : -10)); break; @@ -662,7 +648,6 @@ export class PropertiesView extends React.Component { const oldX = NumCast(this.selectedDoc?.x); const oldY = NumCast(this.selectedDoc?.y); this.selectedDoc && (this.selectedDoc._width = oldWidth + (dirs === 'up' ? 10 : -10)); - InkStrokeProperties.Instance._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) / oldWidth) * NumCast(this.selectedDoc?._height)); const doc = this.selectedDoc; if (doc?.type === DocumentType.INK && doc.x && doc.y && doc._height && doc._width) { const ink = Cast(doc.data, InkField)?.inkData; @@ -684,7 +669,6 @@ export class PropertiesView extends React.Component { const oX = NumCast(this.selectedDoc?.x); const oY = NumCast(this.selectedDoc?.y); this.selectedDoc && (this.selectedDoc._height = oHeight + (dirs === 'up' ? 10 : -10)); - InkStrokeProperties.Instance._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) / oHeight) * NumCast(this.selectedDoc?._width)); const docu = this.selectedDoc; if (docu?.type === DocumentType.INK && docu.x && docu.y && docu._height && docu._width) { const ink = Cast(docu.data, InkField)?.inkData; @@ -704,11 +688,7 @@ export class PropertiesView extends React.Component { }; getField(key: string) { - //if (this.selectedDoc) { return Field.toString(this.selectedDoc?.[key] as Field); - // } else { - // return undefined as Opt; - // } } @computed get shapeXps() { @@ -717,9 +697,6 @@ export class PropertiesView extends React.Component { @computed get shapeYps() { return this.getField('y'); } - @computed get shapeRot() { - return this.getField('rotation'); - } @computed get shapeHgt() { return this.getField('_height'); } @@ -732,18 +709,11 @@ export class PropertiesView extends React.Component { set shapeYps(value) { this.selectedDoc && (this.selectedDoc.y = Number(value)); } - set shapeRot(value) { - this.selectedDoc && (this.selectedDoc.rotation = Number(value)); - } set shapeWid(value) { - const oldWidth = NumCast(this.selectedDoc?._width); this.selectedDoc && (this.selectedDoc._width = Number(value)); - InkStrokeProperties.Instance._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) * NumCast(this.selectedDoc?._height)) / oldWidth); } set shapeHgt(value) { - const oldHeight = NumCast(this.selectedDoc?._height); this.selectedDoc && (this.selectedDoc._height = Number(value)); - InkStrokeProperties.Instance._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) * NumCast(this.selectedDoc?._width)) / oldHeight); } @computed get hgtInput() { @@ -790,30 +760,6 @@ export class PropertiesView extends React.Component { 'Y:' ); } - @computed get rotInput() { - return this.inputBoxDuo( - 'rot', - this.shapeRot, - (val: string) => { - if (!isNaN(Number(val))) { - this.rotate(Number(val) - Number(this.shapeRot)); - this.shapeRot = val; - } - return true; - }, - '∠:', - 'rot', - this.shapeRot, - (val: string) => { - if (!isNaN(Number(val))) { - this.rotate(Number(val) - Number(this.shapeRot)); - this.shapeRot = val; - } - return true; - }, - '' - ); - } @observable private _fillBtn = false; @observable private _lineBtn = false; @@ -1080,10 +1026,9 @@ export class PropertiesView extends React.Component { @computed get transformEditor() { return (
- {this.controlPointsButton} + {this.isInk ? this.controlPointsButton : null} {this.hgtInput} {this.XpsInput} - {this.rotInput}
); } @@ -1194,17 +1139,15 @@ export class PropertiesView extends React.Component {
)} - {this.isInk ? ( -
-
(this.openTransform = !this.openTransform))} style={{ backgroundColor: this.openTransform ? 'black' : '' }}> - Transform -
- -
+
+
(this.openTransform = !this.openTransform))} style={{ backgroundColor: this.openTransform ? 'black' : '' }}> + Transform +
+
- {this.openTransform ?
{this.transformEditor}
: null}
- ) : null} + {this.openTransform ?
{this.transformEditor}
: null} +
); } diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 02dd15960..48c0150e6 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -5,7 +5,7 @@ import { Id } from '../../fields/FieldSymbols'; import { List } from '../../fields/List'; import { RichTextField } from '../../fields/RichTextField'; import { DocCast, NumCast, StrCast } from '../../fields/Types'; -import { emptyFunction, OmitKeys, returnAll, returnOne, returnTrue, returnZero } from '../../Utils'; +import { emptyFunction, returnAll, returnFalse, returnOne, returnTrue, returnZero } from '../../Utils'; import { Docs, DocUtils } from '../documents/Documents'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; import { LinkManager } from '../util/LinkManager'; @@ -26,6 +26,7 @@ interface ExtraProps { // usePanelWidth: boolean; showSidebar: boolean; nativeWidth: number; + usePanelWidth?: boolean; whenChildContentsActiveChanged: (isActive: boolean) => void; ScreenToLocalTransform: () => Transform; sidebarAddDocument: (doc: Doc | Doc[], suffix: string) => boolean; @@ -158,13 +159,10 @@ export class SidebarAnnos extends React.Component { .ScreenToLocalTransform() .translate(Doc.NativeWidth(this.props.dataDoc), 0) .scale(this.props.NativeDimScaling?.() || 1); - // panelWidth = () => !this.props.layoutDoc._showSidebar ? 0 : - // this.props.usePanelWidth ? this.props.PanelWidth() : - // (NumCast(this.props.layoutDoc.nativeWidth) - Doc.NativeWidth(this.props.dataDoc)) * this.props.PanelWidth() / NumCast(this.props.layoutDoc.nativeWidth); panelWidth = () => !this.props.showSidebar ? 0 - : this.props.layoutDoc.type === DocumentType.RTF || this.props.layoutDoc.type === DocumentType.MAP + : this.props.usePanelWidth // [DocumentType.RTF, DocumentType.MAP].includes(this.props.layoutDoc.type as any) ? this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) : ((NumCast(this.props.nativeWidth) - Doc.NativeWidth(this.props.dataDoc)) * this.props.PanelWidth()) / NumCast(this.props.nativeWidth); panelHeight = () => this.props.PanelHeight() - this.filtersHeight(); @@ -224,20 +222,21 @@ export class SidebarAnnos extends React.Component {
, props: Opt = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color)); if (docColor) return docColor; const docView = props?.DocumentView?.(); - const backColor = backgroundCol() || docView?.props.styleProvider?.(docView.props.treeViewDoc, docView.props, 'backgroundColor'); + const backColor = backgroundCol() || docView?.props.styleProvider?.(docView.props.treeViewDoc, docView.props, StyleProp.BackgroundColor); if (!backColor) return undefined; return lightOrDark(backColor); case StyleProp.Hidden: diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 681ff66e0..45db240a9 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -79,7 +79,7 @@ export class TemplateMenu extends React.Component { }; componentDidMount() { !this._addedKeys && (this._addedKeys = new ObservableSet()); - Array.from(Object.keys(Doc.GetProto(this.props.docViews[0].props.Document))) + [...Array.from(Object.keys(Doc.GetProto(this.props.docViews[0].props.Document))), ...Array.from(Object.keys(this.props.docViews[0].props.Document))] .filter(key => key.startsWith('layout_')) .map(key => runInAction(() => this._addedKeys.add(key.replace('layout_', '')))); } diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 57ff1b292..a266c9207 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -5,7 +5,7 @@ import * as React from 'react'; import { Doc } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { NumCast, ScriptCast, StrCast } from '../../../fields/Types'; -import { OmitKeys, returnFalse, Utils } from '../../../Utils'; +import { returnFalse, returnZero, Utils } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; import { DocumentView } from '../nodes/DocumentView'; import { StyleProp } from '../StyleProvider'; @@ -43,7 +43,10 @@ export class CollectionCarousel3DView extends CollectionSubView() { const displayDoc = (childPair: { layout: Doc; data: Doc }) => { return (
this.currentTime; - @computed get renderDictation() { - const dictation = Cast(this.dataDoc[this.props.dictationKey], Doc, null); - return !dictation ? null : ( -
- -
- ); - } - // renders selection region on timeline @computed get selectionContainer() { const markerEnd = CollectionStackedTimeline.SelectingRegion === this ? this.currentTime : this._markerEnd; @@ -638,7 +606,6 @@ export class CollectionStackedTimeline extends CollectionSubView )} - {/* {this.renderDictation} */}
// 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 any }); - const focusFunc = (doc: Doc, options: DocFocusOptions) => this.props.playLink(mark); + const focusFunc = (doc: Doc, options: DocFocusOptions): number | undefined => { + this.props.playLink(mark); + return undefined; + }; return { anchor, view: ( (anchor.view = r))} Document={mark} DataDoc={undefined} + docViewPath={returnEmptyDoclist} pointerEvents={this.noEvents ? returnNone : undefined} styleProvider={this.props.styleProvider} renderDepth={this.props.renderDepth + 1} @@ -837,7 +810,16 @@ class StackedTimelineAnchor extends React.Component PanelHeight={height} fitWidth={returnTrue} ScreenToLocalTransform={screenXf} + addDocTab={returnFalse} + pinToPres={emptyFunction} + whenChildContentsActiveChanged={emptyFunction} focus={focusFunc} + isContentActive={returnFalse} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined} + searchFilterDocs={returnEmptyDoclist} + docFilters={returnEmptyFilter} + docRangeFilters={returnEmptyFilter} rootSelected={returnFalse} onClick={script} onDoubleClick={this.props.layoutDoc.autoPlayAnchors ? undefined : doublescript} diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 553967b95..4a11e8f0b 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -7,7 +7,7 @@ import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, OmitKeys, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue } from '../../../Utils'; +import { emptyFunction, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType } from '../../util/DragManager'; @@ -384,12 +384,12 @@ export class CollectionTreeView extends CollectionSubView { + @computed get content() { const background = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor); const pointerEvents = () => (!this.props.isContentActive() && !SnappingManager.GetIsDragging() ? 'none' : undefined); const titleBar = this.props.treeViewHideTitle || this.doc.treeViewHideTitle ? null : this.titleBar; - return [ -
+ return ( +
{!this.buttonMenu && !this.noviceExplainer ? null : (
r && (this._headerHeight = Number(getComputedStyle(r).height.replace(/px/, ''))))}> {this.buttonMenu} @@ -428,9 +428,9 @@ export class CollectionTreeView extends CollectionSubView
-
, - ]; - }; +
+ ); + } render() { TraceMobx(); @@ -439,7 +439,11 @@ export class CollectionTreeView extends CollectionSubView {!(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeViewHasOverlay ? ( - {this.contentFunc} + {this.content} ) : ( - this.contentFunc() + this.content )}
); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 51624689e..bc25ad43a 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -45,7 +45,7 @@ interface CollectionViewProps_ extends FieldViewProps { // property overrides for child documents childDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox) - childDocumentsActive?: () => boolean; // whether child documents can be dragged if collection can be dragged (eg., in a when a Pile document is in startburst mode) + childDocumentsActive?: () => boolean | undefined; // whether child documents can be dragged if collection can be dragged (eg., in a when a Pile document is in startburst mode) childFitWidth?: (child: Doc) => boolean; childShowTitle?: () => string; childOpacity?: () => number; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index aed3683d4..d39668a5d 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, observable, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import { DateField } from '../../../../fields/DateField'; @@ -53,10 +53,14 @@ import { MarqueeView } from './MarqueeView'; import React = require('react'); export type collectionFreeformViewProps = { + noPointerWheel?: () => boolean; // turn off pointerwheel interactions (see PDFViewer) + NativeWidth?: () => number; + NativeHeight?: () => number; + originTopLeft?: boolean; annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox) viewDefDivClick?: ScriptField; childPointerEvents?: string; - scaleField?: string; + viewField?: string; noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale) engineProps?: any; getScrollHeight?: () => number | undefined; @@ -97,8 +101,14 @@ export class CollectionFreeFormView extends CollectionSubView (this.fitContentsToBox ? true : false); // panx, pany, zoomscale all attempt to get values first from the layout controller, then from the layout/dataDoc (or template layout doc), and finally from the resolved template data document. // this search order, for example, allows icons of cropped images to find the panx/pany/zoom on the cropped image's data doc instead of the usual layout doc because the zoom/panX/panY define the cropped image - panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document._panX, NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panX, 1)); - panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document._panY, NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panY, 1)); + panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document[this.panXFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panX, 1)); + panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document[this.panYFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panY, 1)); zoomScaling = () => this.freeformData()?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.[this.scaleFieldKey], 1)); contentTransform = () => - !this.cachedCenteringShiftX && !this.cachedCenteringShiftY && this.zoomScaling() === 1 - ? '' - : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`; + this.props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`; getTransform = () => this.cachedGetTransform.copy(); getLocalTransform = () => this.cachedGetLocalTransform.copy(); getContainerTransform = () => this.cachedGetContainerTransform.copy(); @@ -293,7 +301,7 @@ export class CollectionFreeFormView extends CollectionSubView { - options.docTransform = new Transform(-NumCast(this.rootDoc.panX) + NumCast(anchor.x), -NumCast(this.rootDoc.panY) + NumCast(anchor.y), 1); + options.docTransform = new Transform(-NumCast(this.rootDoc[this.panXFieldKey]) + NumCast(anchor.x), -NumCast(this.rootDoc[this.panYFieldKey]) + NumCast(anchor.y), 1); const res = this.props.focus(this.rootDoc, options); options.docTransform = undefined; return res; @@ -301,7 +309,7 @@ export class CollectionFreeFormView extends CollectionSubView { const xfToCollection = options?.docTransform ?? Transform.Identity(); - const savedState = { panX: NumCast(this.Document._panX), panY: NumCast(this.Document._panY), scale: options?.willZoomCentered ? this.Document[this.scaleFieldKey] : undefined }; + const savedState = { panX: NumCast(this.Document[this.panXFieldKey]), panY: NumCast(this.Document[this.panYFieldKey]), scale: options?.willZoomCentered ? this.Document[this.scaleFieldKey] : undefined }; const cantTransform = this.fitContentsToBox || ((this.rootDoc._isGroup || this.layoutDoc._lockedTransform) && !LightboxView.LightboxDoc); const { panX, panY, scale } = cantTransform || (!options.willPan && !options.willZoomCentered) ? savedState : this.calculatePanIntoView(anchor, xfToCollection, options?.willZoomCentered ? options?.zoomScale || 0.75 : undefined); @@ -772,7 +780,7 @@ export class CollectionFreeFormView extends CollectionSubView= 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, NumCast(this.props.Document.scrollTop) * safeScale || -localTransform.TranslateY / safeScale); + this.setPan(-localTransform.TranslateX / safeScale, (this.props.originTopLeft ? undefined : NumCast(this.props.Document.scrollTop) * safeScale) || -localTransform.TranslateY / safeScale); } }; @action onPointerWheel = (e: React.WheelEvent): void => { - if (this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom + if (this.props.noPointerWheel?.() || this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom PresBox.Instance?.pauseAutoPres(); if (this.layoutDoc._Transform || DocListCast(Doc.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; e.stopPropagation(); @@ -995,7 +1003,7 @@ export class CollectionFreeFormView extends CollectionSubView= panX + panelDim[0] / 2) panX = ranges.xrange.max + panelDim[0] / 2; // snaps pan position of range of content goes out of bounds - else if (ranges.xrange.max <= panX - panelDim[0] / 2) panX = ranges.xrange.min - panelDim[0] / 2; - if (ranges.yrange.min >= panY + panelDim[1] / 2) panY = ranges.yrange.max + panelDim[1] / 2; - else if (ranges.yrange.max <= panY - panelDim[1] / 2) panY = ranges.yrange.min - panelDim[1] / 2; + const panelWidMax = (this.props.PanelWidth() / this.zoomScaling()) * (this.props.originTopLeft ? 2 / this.nativeDimScaling : 1); + const panelWidMin = (this.props.PanelWidth() / this.zoomScaling()) * (this.props.originTopLeft ? 0 : 1); + const panelHgtMax = (this.props.PanelHeight() / this.zoomScaling()) * (this.props.originTopLeft ? 2 / this.nativeDimScaling : 1); + const panelHgtMin = (this.props.PanelHeight() / this.zoomScaling()) * (this.props.originTopLeft ? 0 : 1); + if (ranges.xrange.min >= panX + panelWidMax / 2) panX = ranges.xrange.max + (this.props.originTopLeft ? 0 : panelWidMax / 2); + else if (ranges.xrange.max <= panX - panelWidMin / 2) panX = ranges.xrange.min - (this.props.originTopLeft ? panelWidMax / 2 : panelWidMin / 2); + if (ranges.yrange.min >= panY + panelHgtMax / 2) panY = ranges.yrange.max + (this.props.originTopLeft ? 0 : panelHgtMax / 2); + else if (ranges.yrange.max <= panY - panelHgtMin / 2) panY = ranges.yrange.min - (this.props.originTopLeft ? panelHgtMax / 2 : panelHgtMin / 2); } } if (!this.layoutDoc._lockedTransform || LightboxView.LightboxDoc || DocListCast(Doc.MyOverlayDocs?.data).includes(this.Document)) { @@ -1078,8 +1089,8 @@ export class CollectionFreeFormView extends CollectionSubView { if (this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform || this.props.ContainingCollectionDoc._panX !== undefined) { this.setPan( - NumCast(this.layoutDoc._panX) + ((this.props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale - NumCast(this.layoutDoc._panY) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(), + NumCast(this.layoutDoc[this.panXFieldKey]) + ((this.props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale + NumCast(this.layoutDoc[this.panYFieldKey]) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(), nudgeTime, true ); @@ -1106,12 +1117,14 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).slice(); docs.sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex)); - let zlast = docs.length ? Math.max(docs.length, NumCast(docs[docs.length - 1].zIndex)) : 1; - if (zlast - docs.length > 100) { - for (let i = 0; i < docs.length; i++) doc.zIndex = i + 1; - zlast = docs.length + 1; + let zlast = docs.length ? Math.max(docs.length, NumCast(docs.lastElement().zIndex)) : 1; + if (docs.lastElement() !== doc) { + if (zlast - docs.length > 100) { + for (let i = 0; i < docs.length; i++) doc.zIndex = i + 1; + zlast = docs.length + 1; + } + doc.zIndex = zlast + 1; } - doc.zIndex = zlast + 1; } }; @@ -1134,8 +1147,8 @@ export class CollectionFreeFormView extends CollectionSubView { @@ -1158,8 +1171,8 @@ export class CollectionFreeFormView extends CollectionSubView screen.bot ? Math.min(ph / 10, maxYShift / 2) : 0; @@ -1171,8 +1184,8 @@ export class CollectionFreeFormView extends CollectionSubView { if (cbounds) { const c = [NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym]() / 2, NumCast(this.layoutDoc.y) + this.layoutDoc[HeightSym]() / 2]; - const p = [NumCast(this.layoutDoc._panX), NumCast(this.layoutDoc._panY)]; + const p = [NumCast(this.layoutDoc[this.panXFieldKey]), NumCast(this.layoutDoc[this.panYFieldKey])]; const pbounds = { x: cbounds.x - p[0] + c[0], y: cbounds.y - p[1] + c[1], @@ -1511,8 +1524,8 @@ export class CollectionFreeFormView extends CollectionSubView NumCast(doc._height))) + 20; const dim = Math.ceil(Math.sqrt(docs.length)); docs.forEach((doc, i) => { - doc.x = NumCast(this.Document._panX) + (i % dim) * width - (width * dim) / 2; - doc.y = NumCast(this.Document._panY) + Math.floor(i / dim) * height - (height * dim) / 2; + doc.x = NumCast(this.Document[this.panXFieldKey]) + (i % dim) * width - (width * dim) / 2; + doc.y = NumCast(this.Document[this.panYFieldKey]) + Math.floor(i / dim) * height - (height * dim) / 2; }); }; @@ -1675,7 +1688,7 @@ export class CollectionFreeFormView extends CollectionSubView { - this.props.Document._panX = this.props.Document._panY = 0; + this.props.Document[this.panXFieldKey] = this.props.Document[this.panYFieldKey] = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: 'compress-arrows-alt', @@ -1795,11 +1808,11 @@ export class CollectionFreeFormView extends CollectionSubView !this._renderCutoffData.get(doc[Id])) && setTimeout(this.incrementalRender, 1); }); - children = () => { + get children() { this.incrementalRender(); - const children = typeof this.props.children === 'function' ? ((this.props.children as any)() as JSX.Element[]) : []; + const children = typeof this.props.children === 'function' ? ((this.props.children as any)() as JSX.Element[]) : this.props.children ? [this.props.children] : []; return [...children, ...this.views, ]; - }; + } @computed get placeholder() { return ( @@ -1843,6 +1856,7 @@ export class CollectionFreeFormView extends CollectionSubView this.nativeDimScaling; private groupDropDisposer?: DragManager.DragDropDisposer; protected createGroupEventsTarget = (ele: HTMLDivElement) => { @@ -1912,7 +1927,7 @@ export class CollectionFreeFormView extends CollectionSubView { this.createDashEventsTarget(r); // prevent wheel events from passivly propagating up through containers - r?.addEventListener('wheel', (e: WheelEvent) => this.props.isSelected() && e.preventDefault(), { passive: false }); + !this.props.isAnnotationOverlay && r?.addEventListener('wheel', (e: WheelEvent) => this.props.isSelected() && e.preventDefault(), { passive: false }); }} onWheel={this.onPointerWheel} onClick={this.onClick} @@ -1985,7 +2000,8 @@ interface CollectionFreeFormViewPannableContentsProps { transform: () => string; zoomScaling: () => number; viewDefDivClick?: ScriptField; - children: () => JSX.Element[]; + children?: React.ReactNode | undefined; + //children: () => JSX.Element[]; transition?: string; presPaths: () => JSX.Element | null; presPinView?: boolean; @@ -2079,7 +2095,7 @@ class CollectionFreeFormViewPannableContents extends React.Component - {this.props.children()} + {this.props.children} {!this.props.brushView.width ? null : (
number; PanelHeight: () => number; isAnnotationOverlay?: boolean; + nativeDimScaling: () => number; zoomScaling: () => number; layoutDoc: Doc; cachedCenteringShiftX: number; @@ -2124,10 +2141,10 @@ class CollectionFreeFormBackgroundGrid extends React.Component { + // if (this.props.pointerEvents?.() === 'none') return; this._downX = this._lastX = e.clientX; this._downY = this._lastY = e.clientY; if (!(e.nativeEvent as any).marqueeHit) { @@ -345,6 +346,7 @@ export class MarqueeView extends React.Component { + if (this.props.pointerEvents?.() === 'none') return; if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) { if (Doc.ActiveTool === InkTool.None) { if (!(e.nativeEvent as any).marqueeHit) { diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 9468c5f06..e8ae88ae5 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import { Doc, Opt } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, OmitKeys, returnFalse, setupMoveUpEvents } from '../../../../Utils'; +import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; import { SnappingManager } from '../../../util/SnappingManager'; @@ -186,7 +186,10 @@ export class CollectionGridView extends CollectionSubView() { getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) { return ( ); } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index d47c9762c..fd9bcf681 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1,23 +1,20 @@ import React = require('react'); import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable, ObservableMap, trace, untracked } from 'mobx'; +import { action, computed, observable, ObservableMap, untracked } from 'mobx'; import { observer } from 'mobx-react'; -import { Doc, DocListCast, Field, StrListCast } from '../../../../fields/Doc'; +import { computedFn } from 'mobx-utils'; +import { Doc, Field, StrListCast } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; -import { RichTextField } from '../../../../fields/RichTextField'; import { listSpec } from '../../../../fields/Schema'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; -import { ImageField } from '../../../../fields/URLField'; import { emptyFunction, returnDefault, returnEmptyDoclist, returnEmptyString, returnFalse, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils'; import { Docs, DocUtils } from '../../../documents/Documents'; import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { SelectionManager } from '../../../util/SelectionManager'; -import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; -import { ContextMenuProps } from '../../ContextMenuItem'; import { EditableView } from '../../EditableView'; import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; @@ -215,9 +212,7 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - addNewKey = (key: string, defaultVal: any) => { - this.childDocs.forEach(doc => (doc[key] = defaultVal)); - }; + addNewKey = (key: string, defaultVal: any) => this.childDocs.forEach(doc => (doc[key] = defaultVal)); @undoBatch @action @@ -303,9 +298,7 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - addRowRef = (doc: Doc, ref: HTMLDivElement) => { - this._rowEles.set(doc, ref); - }; + addRowRef = (doc: Doc, ref: HTMLDivElement) => this._rowEles.set(doc, ref); @action setColRef = (index: number, ref: HTMLDivElement) => { @@ -405,68 +398,12 @@ export class CollectionSchemaView extends CollectionSubView() { menuCallback = (x: number, y: number) => { ContextMenu.Instance.clearItems(); - const layoutItems: ContextMenuProps[] = []; - const docItems: ContextMenuProps[] = []; - const dataDoc = this.props.DataDoc || this.props.Document; - - DocUtils.addDocumentCreatorMenuItems( - doc => { - FormattedTextBox.SelectOnLoad = StrCast(doc[Id]); - return this.addRow(doc); - }, - this.addRow, - x, - y, - true - ); - Array.from(Object.keys(Doc.GetProto(dataDoc))) - .filter(fieldKey => dataDoc[fieldKey] instanceof RichTextField || dataDoc[fieldKey] instanceof ImageField || typeof dataDoc[fieldKey] === 'string') - .map(fieldKey => - docItems.push({ - description: ':' + fieldKey, - event: () => { - const created = DocUtils.DocumentFromField(dataDoc, fieldKey, Doc.GetProto(this.props.Document)); - if (created) { - if (this.props.Document.isTemplateDoc) { - Doc.MakeMetadataFieldTemplate(created, this.props.Document); - } - return this.addRow(created); - } - }, - icon: 'compress-arrows-alt', - }) - ); - Array.from(Object.keys(Doc.GetProto(dataDoc))) - .filter(fieldKey => DocListCast(dataDoc[fieldKey]).length) - .map(fieldKey => - docItems.push({ - description: ':' + fieldKey, - event: () => { - const created = Docs.Create.CarouselDocument([], { _width: 400, _height: 200, title: fieldKey }); - if (created) { - const container = this.props.Document.resolvedDataDoc ? Doc.GetProto(this.props.Document) : this.props.Document; - if (container.isTemplateDoc) { - Doc.MakeMetadataFieldTemplate(created, container); - return Doc.AddDocToList(container, Doc.LayoutFieldKey(container), created); - } - return this.addRow(created) || false; - } - }, - icon: 'compress-arrows-alt', - }) - ); - !Doc.noviceMode && ContextMenu.Instance.addItem({ description: 'Doc Fields ...', subitems: docItems, icon: 'eye' }); - !Doc.noviceMode && ContextMenu.Instance.addItem({ description: 'Containers ...', subitems: layoutItems, icon: 'eye' }); + DocUtils.addDocumentCreatorMenuItems(doc => this.addRow(doc), this.addRow, x, y, true); + ContextMenu.Instance.setDefaultItem('::', (name: string): void => { Doc.GetProto(this.props.Document)[name] = ''; - const created = Docs.Create.TextDocument('', { title: name, _autoHeight: true }); - if (created) { - if (this.props.Document.isTemplateDoc) { - Doc.MakeMetadataFieldTemplate(created, this.props.Document); - } - this.addRow(created); - } + this.addRow(Docs.Create.TextDocument('', { title: name, _autoHeight: true })); }); ContextMenu.Instance.displayMenu(x, y, undefined, true); }; @@ -543,9 +480,7 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - closeColumnMenu = () => { - this._columnMenuIndex = undefined; - }; + closeColumnMenu = () => (this._columnMenuIndex = undefined); @action openFilterMenu = (index: number) => { @@ -596,19 +531,14 @@ export class CollectionSchemaView extends CollectionSubView() { getFieldFilters = (field: string) => StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field); removeFieldFilters = (field: string) => { - this.getFieldFilters(field).forEach(filter => { - Doc.setDocFilter(this.Document, field, filter.split(':')[1], 'remove'); - }); + this.getFieldFilters(field).forEach(filter => Doc.setDocFilter(this.Document, field, filter.split(':')[1], 'remove')); }; onFilterKeyDown = (e: React.KeyboardEvent) => { + //prettier-ignore switch (e.key) { - case 'Enter': - this.closeFilterMenu(true); - break; - case 'Escape': - this.closeFilterMenu(false); - break; + case 'Enter' : this.closeFilterMenu(true); break; + case 'Escape': this.closeFilterMenu(false);break; } }; @@ -903,6 +833,7 @@ interface CollectionSchemaViewDocsProps { class CollectionSchemaViewDocs extends React.Component { tableWidthFunc = () => this.props.schema.tableWidth; rowHeightFunc = () => CollectionSchemaView._rowHeight; + childScreenToLocal = computedFn((index: number) => () => this.props.schema.props.ScreenToLocalTransform().translate(0, -CollectionSchemaView._rowHeight - index * this.rowHeightFunc())); render() { return (
@@ -932,7 +863,7 @@ class CollectionSchemaViewDocs extends React.Component @action onPointerDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction); + setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction, false); }; render() { return ( -
{ - col && this.props.setColRef(this.props.columnIndex, col); - }}> +
col && this.props.setColRef(this.props.columnIndex, col)}>
this.props.resizeColumn(e, this.props.columnIndex)}>
{this.fieldKey}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 384975b45..a6acf882c 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -7,7 +7,7 @@ import { Doc, DocListCast } from '../../../fields/Doc'; import { ComputedField } from '../../../fields/ScriptField'; import { Cast, DateCast, NumCast } from '../../../fields/Types'; import { AudioField, nullAudio } from '../../../fields/URLField'; -import { emptyFunction, formatTime, OmitKeys, returnFalse, setupMoveUpEvents } from '../../../Utils'; +import { emptyFunction, formatTime, returnFalse, setupMoveUpEvents } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { Networking } from '../../Network'; import { DragManager } from '../../util/DragManager'; @@ -19,7 +19,6 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import './AudioBox.scss'; import { FieldView, FieldViewProps } from './FieldView'; -import { SelectionManager } from '../../util/SelectionManager'; import { PinProps, PresBox } from './trails'; /** @@ -655,7 +654,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent (this._stackedTimeline = r))} - {...OmitKeys(this.props, ['CollectionFreeFormDocumentView']).omit} + {...this.props} + CollectionFreeFormDocumentView={undefined} fieldKey={this.annotationKey} dictationKey={this.fieldKey + '-dictation'} mediaPath={this.path} diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index ecffe6c4f..ace388c57 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -3,7 +3,7 @@ import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, Opt } from '../../../fields/Doc'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; -import { emptyFunction, OmitKeys, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils'; +import { emptyFunction, returnFalse, returnNone, returnZero, setupMoveUpEvents } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { SnappingManager } from '../../util/SnappingManager'; @@ -122,7 +122,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { //whichDoc !== targetDoc && r?.focus(whichDoc, { instant: true }); }} - {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight']).omit} + {...this.props} + NativeWidth={returnZero} + NativeHeight={returnZero} isContentActive={returnFalse} isDocumentActive={returnFalse} styleProvider={this.docStyleProvider} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 091a6b050..c7bf37a45 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -12,7 +12,7 @@ import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { AudioField } from '../../../fields/URLField'; import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; -import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, OmitKeys, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils'; +import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils'; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { DocServer } from '../../DocServer'; import { Docs, DocUtils } from '../../documents/Documents'; @@ -512,7 +512,6 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' }); - !Doc.noviceMode && - appearanceItems.push({ - description: 'Add a Field', - event: () => { - const alias = Doc.MakeAlias(this.rootDoc); - alias.layout = FormattedTextBox.LayoutString('newfield'); - alias.title = 'newfield'; - alias._height = 35; - alias._width = 100; - alias.syncLayoutFieldWithTitle = true; - alias.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc.width); - alias.y = NumCast(this.rootDoc.y); - this.props.addDocument?.(alias); - }, - icon: 'eye', - }); LinkManager.Links(this.Document).length && appearanceItems.splice(0, 0, { description: `${this.layoutDoc.hideLinkButton ? 'Show' : 'Hide'} Link Button`, event: action(() => (this.layoutDoc.hideLinkButton = !this.layoutDoc.hideLinkButton)), icon: 'eye' }); !appearance && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' }); @@ -863,7 +846,7 @@ export class DocumentViewInternal extends DocComponent (this.disableClickScriptFunc ? undefined : this.onClickHandler); setHeight = (height: number) => (this.layoutDoc._height = height); setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view)); - isContentActive = (outsideReaction?: boolean) => { + isContentActive = (outsideReaction?: boolean): boolean | undefined => { return this.props.isContentActive() === false ? false : Doc.ActiveTool !== InkTool.None || @@ -1064,7 +1047,7 @@ export class DocumentViewInternal extends DocComponent, props: Opt, property: string) => this.props?.styleProvider?.(doc, props, property + ':caption'); + captionStyleProvider = (doc: Opt, props: Opt, property: string) => this.props?.styleProvider?.(doc, props, property + ':caption'); @computed get innards() { TraceMobx(); const ffscale = () => this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.ScreenToLocalTransform().Scale || 1; @@ -1079,7 +1062,7 @@ export class DocumentViewInternal extends DocComponent
); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index e53422ab7..8d3534a5c 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -20,7 +20,7 @@ export interface FieldViewProps extends DocumentViewSharedProps { select: (isCtrlPressed: boolean) => void; isContentActive: (outsideReaction?: boolean) => boolean | undefined; - isDocumentActive?: () => boolean; + isDocumentActive?: () => boolean | undefined; isSelected: (outsideReaction?: boolean) => boolean; setHeight?: (height: number) => void; NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal NOTE: Must also be added to DocumentViewInternalsProps diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 48e54b722..b5193cd20 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -11,7 +11,7 @@ import { ComputedField } from '../../../fields/ScriptField'; import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { DashColor, emptyFunction, OmitKeys, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../Utils'; +import { DashColor, emptyFunction, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices'; import { Docs, DocUtils } from '../../documents/Documents'; @@ -409,8 +409,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent [this.content]; - private _mainCont: React.RefObject = React.createRef(); private _annotationLayer: React.RefObject = React.createRef(); @observable _marqueeing: number[] | undefined; @@ -473,7 +471,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent - {this.contentFunc} + {this.content} {this.annotationLayer} {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : ( diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index ea8f47b39..36be7d257 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -8,7 +8,7 @@ import { Doc, DocListCast, Opt, WidthSym } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; import { InkTool } from '../../../../fields/InkField'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, OmitKeys, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils'; +import { emptyFunction, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; import { SnappingManager } from '../../../util/SnappingManager'; @@ -635,7 +635,8 @@ export class MapBox extends ViewBoxAnnotatableComponent ( (this._stack = r)} - {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit} + {...this.props} + setContentView={emptyFunction} Document={this.props.place} DataDoc={undefined} fieldKey="data" diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 5f207cc0d..a254edd87 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -5,16 +5,20 @@ import * as Pdfjs from 'pdfjs-dist'; import 'pdfjs-dist/web/pdf_viewer.css'; import { Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; -import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; +import { InkTool } from '../../../fields/InkField'; +import { ComputedField } from '../../../fields/ScriptField'; +import { Cast, FieldValue, ImageCast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField, PdfField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, setupMoveUpEvents, Utils } from '../../../Utils'; +import { emptyFunction, returnFalse, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; -import { DocumentType } from '../../documents/DocumentTypes'; +import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; import { KeyCodes } from '../../util/KeyCodes'; +import { SelectionManager } from '../../util/SelectionManager'; import { undoBatch, UndoManager } from '../../util/UndoManager'; import { CollectionFreeFormView } from '../collections/collectionFreeForm'; +import { CollectionStackingView } from '../collections/CollectionStackingView'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; @@ -41,7 +45,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent; private _pdfViewer: PDFViewer | undefined; private _searchRef = React.createRef(); - private _selectReactionDisposer: IReactionDisposer | undefined; + private _disposers: { [name: string]: IReactionDisposer } = {}; private _sidebarRef = React.createRef(); @observable private _searching: boolean = false; @@ -184,11 +188,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent disposer?.()); } componentDidMount() { this.props.setContentView?.(this); - this._selectReactionDisposer = reaction( + this._disposers.select = reaction( () => this.props.isSelected(), () => { document.removeEventListener('keydown', this.onKeyDown); @@ -196,6 +200,16 @@ export class PDFBox extends ViewBoxAnnotatableComponent this.rootDoc.scrollTop, + () => { + if (!(ComputedField.WithoutComputed(() => FieldValue(this.props.Document[this.SidebarKey + '-panY'])) instanceof ComputedField)) { + this.props.Document[this.SidebarKey + '-panY'] = ComputedField.MakeFunction('this.scrollTop'); + } + this.props.Document[this.SidebarKey + '-viewScale'] = 1; + this.props.Document[this.SidebarKey + '-panX'] = 0; + } + ); } brushView = (view: { width: number; height: number; panX: number; panY: number }) => this._pdfViewer?.brushView(view); @@ -303,7 +317,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { + sidebarAddDocument = (doc: Doc | Doc[], sidebarKey: string = this.SidebarKey) => { if (!this.layoutDoc._showSidebar) this.toggleSidebar(); return this.addDocument(doc, sidebarKey); }; @@ -428,6 +442,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent { const funcs: ContextMenuProps[] = []; + funcs.push({ + description: 'Toggle Sidebar Type', + event: () => (this.rootDoc.sidebarViewType = this.rootDoc.sidebarViewType === CollectionViewType.Freeform ? CollectionViewType.Stacking : CollectionViewType.Freeform), + icon: 'expand-arrows-alt', + }); funcs.push({ description: 'Copy path', event: () => this.pdfUrl && Utils.CopyText(Utils.prepend('') + this.pdfUrl.url.pathname), icon: 'expand-arrows-alt' }); funcs.push({ description: 'update icon', event: () => this.pdfUrl && this.updateIcon(), icon: 'expand-arrows-alt' }); //funcs.push({ description: "Toggle Sidebar ", event: () => this.toggleSidebar(), icon: "expand-arrows-alt" }); @@ -467,12 +486,87 @@ export class PDFBox extends ViewBoxAnnotatableComponent this.sidebarNativeWidth; + sidebarNativeHeightFunc = () => this.sidebarNativeHeight; + sidebarMoveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.moveDocument(doc, targetCollection, addDocument, this.SidebarKey); + sidebarRemDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, this.SidebarKey); + sidebarScreenToLocal = () => this.props.ScreenToLocalTransform().translate((this.sidebarWidth() - this.props.PanelWidth()) / this.pdfScale, 0); + @computed get sidebarCollection() { + const renderComponent = (tag: string) => { + const ComponentTag = tag === CollectionViewType.Freeform ? CollectionFreeFormView : CollectionStackingView; + return ComponentTag === CollectionStackingView ? ( + + ) : ( +
setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.props.DocumentView?.()!, false), true)}> + +
+ ); + }; + return ( +
+ {renderComponent(StrCast(this.layoutDoc.sidebarViewType))} +
+ ); + } isPdfContentActive = () => this.isAnyChildContentActive() || this.props.isSelected() || (this.props.renderDepth === 0 && LightboxView.IsLightboxDocView(this.props.docViewPath())); @computed get renderPdfView() { TraceMobx(); const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; const scale = previewScale * (this.props.NativeDimScaling?.() || 1); - return ( + return !this._pdf ? null : (
-
- -
+
{this.sidebarCollection}
{this.settingsPanel()}
); @@ -535,21 +614,17 @@ export class PDFBox extends ViewBoxAnnotatableComponent>(); render() { TraceMobx(); - if (this._pdf) { - if (!this.props.thumbShown?.()) { - return this.renderPdfView; - } - return null; - } + if (this.props.thumbShown?.()) return null; + const pdfView = this.renderPdfView; const href = this.pdfUrl?.url.href; - if (href) { + if (!pdfView && href) { if (PDFBox.pdfcache.get(href)) setTimeout(action(() => (this._pdf = PDFBox.pdfcache.get(href)))); else { if (!PDFBox.pdfpromise.get(href)) PDFBox.pdfpromise.set(href, Pdfjs.getDocument(href).promise); PDFBox.pdfpromise.get(href)?.then(action((pdf: any) => PDFBox.pdfcache.set(href, (this._pdf = pdf)))); } } - return this.renderTitleBox; + return pdfView ?? this.renderTitleBox; } } diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 61e4894f0..db11a7776 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -11,7 +11,7 @@ import { ComputedField } from '../../../fields/ScriptField'; import { Cast, NumCast } from '../../../fields/Types'; import { AudioField, VideoField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, OmitKeys, returnFalse, returnOne } from '../../../Utils'; +import { emptyFunction, returnFalse, returnOne, returnZero } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { Networking } from '../../Network'; @@ -277,7 +277,6 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent [this.threed, this.content]; videoPanelHeight = () => (NumCast(this.dataDoc[this.fieldKey + '-nativeHeight'], this.layoutDoc[HeightSym]()) / NumCast(this.dataDoc[this.fieldKey + '-nativeWidth'], this.layoutDoc[WidthSym]())) * this.props.PanelWidth(); formattedPanelHeight = () => Math.max(0, this.props.PanelHeight() - this.videoPanelHeight()); render() { @@ -287,7 +286,10 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent
- {this.contentFunc} + <> + {this.threed} + {this.content} +
{!(this.dataDoc[this.fieldKey + '-dictation'] instanceof Doc) ? null : ( )} diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 0b88f5fe3..0570c7fcb 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -9,7 +9,7 @@ import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { AudioField, ImageField, VideoField } from '../../../fields/URLField'; -import { emptyFunction, formatTime, OmitKeys, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../Utils'; +import { emptyFunction, formatTime, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { Networking } from '../../Network'; @@ -894,8 +894,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent this._playing; - contentFunc = () => [this.youtubeVideoId ? this.youtubeContent : this.content]; - scaling = () => this.props.NativeDimScaling?.() || 1; panelWidth = () => (this.props.PanelWidth() * this.heightPercent) / 100; @@ -1068,7 +1066,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent - {this.contentFunc} + {this.youtubeVideoId ? this.youtubeContent : this.content}
{this.annotationLayer} diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index d57518a8d..66d0fd385 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -11,7 +11,7 @@ import { listSpec } from '../../../fields/Schema'; import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField, WebField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, getWordAtPoint, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, smoothScroll, StopEvent, Utils } from '../../../Utils'; +import { emptyFunction, getWordAtPoint, returnFalse, returnOne, returnZero, setupMoveUpEvents, smoothScroll, StopEvent, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; @@ -305,7 +305,9 @@ export class WebBox extends ViewBoxAnnotatableComponent string[]) => ( + const renderAnnotations = (docFilters: () => string[]) => ( this.props.Document._fitContentsToBox; + fitContentsToBox = () => BoolCast(this.props.Document._fitContentsToBox); sidebarContentScaling = () => (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); sidebarAddDocument = (doc: Doc | Doc[], sidebarKey: string = this.SidebarKey) => { if (!this.layoutDoc._showSidebar) this.toggleSidebar(); - // console.log("printting allSideBarDocs"); - // console.log(this.allSidebarDocs); return this.addDocument(doc, sidebarKey); }; sidebarMoveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.moveDocument(doc, targetCollection, addDocument, this.SidebarKey); @@ -1785,8 +1783,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent @@ -1800,33 +1798,36 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent ) : (
setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.props.DocumentView?.()!, false), true)}> { return this.props.styleProvider?.(doc, props, property); }; - renderAnnotations = (docFilters?: () => string[], mixBlendMode?: any, display?: string) => ( + renderAnnotations = (docFilters: () => string[], mixBlendMode?: any, display?: string) => (
{ pointerEvents: Doc.ActiveTool !== InkTool.None ? 'all' : undefined, }}> { PanelHeight={this.panelHeight} PanelWidth={this.panelWidth} ScreenToLocalTransform={this.overlayTransform} + isAnyChildContentActive={returnFalse} + isAnnotationOverlayScrollable={true} dropAction={'alias'} docFilters={docFilters} select={emptyFunction} diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 553c4525c..cc024d83a 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1213,7 +1213,7 @@ export namespace Doc { return doc[StrCast(doc.layoutKey, 'layout')]; } export function LayoutFieldKey(doc: Doc): string { - return StrCast(Doc.Layout(doc).layout).split("'")[1]; + return StrCast(Doc.Layout(doc)[StrCast(doc.layoutKey, 'layout')]).split("'")[1]; // bcz: TODO check on this . used to always reference 'layout', now it uses the layout speicfied by the current layoutKey } export function NativeAspect(doc: Doc, dataDoc?: Doc, useDim?: boolean) { return Doc.NativeWidth(doc, dataDoc, useDim) / (Doc.NativeHeight(doc, dataDoc, useDim) || 1); @@ -1222,9 +1222,10 @@ export namespace Doc { return !doc ? 0 : NumCast(doc._nativeWidth, NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '-nativeWidth'], useWidth ? doc[WidthSym]() : 0)); } export function NativeHeight(doc?: Doc, dataDoc?: Doc, useHeight?: boolean) { - const dheight = doc ? NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '-nativeHeight'], useHeight ? doc[HeightSym]() : 0) : 0; - const nheight = doc ? (Doc.NativeWidth(doc, dataDoc, useHeight) * doc[HeightSym]()) / doc[WidthSym]() : 0; - return !doc ? 0 : NumCast(doc._nativeHeight, nheight || dheight); + if (!doc) return 0; + const nheight = (Doc.NativeWidth(doc, dataDoc, useHeight) * doc[HeightSym]()) / doc[WidthSym](); + const dheight = NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '-nativeHeight'], useHeight ? doc[HeightSym]() : 0); + return NumCast(doc._nativeHeight, nheight || dheight); } export function SetNativeWidth(doc: Doc, width: number | undefined, fieldKey?: string) { doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + '-nativeWidth'] = width; -- cgit v1.2.3-70-g09d2