From 7035e2e6bdcb3efbfa3a4eca887b41eba87e6d6e Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 23 Feb 2021 01:53:52 -0500 Subject: fixed backspace to delete text items in treeViews. simplified UndoRunInTempBatch. fixed clicking on sort line for treeView to only recognize actual clicks. fixed stayInCollection with DocDecorations to not create a giant gray square. prevent server crash when db has bad data somehow. --- src/client/util/CurrentUserUtils.ts | 2 +- src/client/util/DragManager.ts | 2 +- src/client/util/UndoManager.ts | 11 +++-- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/GlobalKeyHandler.ts | 13 +++--- src/client/views/collections/CollectionView.tsx | 9 +--- src/client/views/collections/TreeView.tsx | 52 +++++++++++----------- .../collections/collectionFreeForm/MarqueeView.tsx | 3 +- src/server/websocket.ts | 2 +- 9 files changed, 46 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 288f75592..beced8c3c 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -558,7 +558,7 @@ export class CurrentUserUtils { _width: 60, _height: 60, watchedDocuments, - onClick: ScriptField.MakeScript(click, { scriptContext: "any" }), system: true + onClick: ScriptField.MakeScript(click, { scriptContext: "any" }) })); const userDoc = menuBtns[menuBtns.length - 1]; userDoc.userDoc = doc; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 7b4d43793..19f1f8d15 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -13,7 +13,7 @@ import * as globalCssVariables from "../views/globalCssVariables.scss"; import { UndoManager } from "./UndoManager"; import { SnappingManager } from "./SnappingManager"; -export type dropActionType = "alias" | "copy" | "move" | "same" | "none" | undefined; // undefined = move +export type dropActionType = "alias" | "copy" | "move" | "same" | "none" | undefined; // undefined = move, "same" = move but don't call removeDropProperties export function SetupDrag( _reference: React.RefObject, docFunc: () => Doc | Promise | undefined, diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts index 569ad8ab4..05fb9f378 100644 --- a/src/client/util/UndoManager.ts +++ b/src/client/util/UndoManager.ts @@ -148,12 +148,15 @@ export namespace UndoManager { } }); - export function ClearTempBatch() { - tempEvents = undefined; - } export function RunInTempBatch(fn: () => T) { tempEvents = []; - return runInAction(fn); + try { + const success = runInAction(fn); + if (!success) UndoManager.UndoTempBatch(); + return success; + } finally { + tempEvents = undefined; + } } //TODO Make this return the return value export function RunInBatch(fn: () => T, batchName: string) { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 7f1023a4a..2391a21e6 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -566,7 +566,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b (collectionAcl === AclAdmin || collectionAcl === AclEdit || docAcl === AclAdmin); }); const canOpen = SelectionManager.Views().some(docView => !docView.props.Document._stayInCollection); - const closeIcon = !canDelete ? (null) : ( + const closeIcon = !canDelete ?
: ( Close} placement="top">
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 3ebcda219..14c0a18a3 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -142,13 +142,14 @@ export class KeyManager { break; case "delete": case "backspace": - if (document.activeElement?.tagName === "INPUT" || document.activeElement?.tagName === "TEXTAREA") { - return { stopPropagation: false, preventDefault: false }; + if (document.activeElement?.tagName !== "INPUT" && document.activeElement?.tagName !== "TEXTAREA") { + const selected = SelectionManager.Views().slice(); + UndoManager.RunInBatch(() => { + SelectionManager.DeselectAll(); + selected.map(dv => !dv.props.Document._stayInCollection && dv.props.removeDocument?.(dv.props.Document)); + }, "delete"); + return { stopPropagation: true, preventDefault: true }; } - - const selected = SelectionManager.Views().slice(); - UndoManager.RunInBatch(() => selected.map(dv => !dv.props.Document._stayInCollection && dv.props.removeDocument?.(dv.props.Document)), "delete"); - SelectionManager.DeselectAll(); break; case "arrowleft": UndoManager.RunInBatch(() => SelectionManager.Views().map(dv => dv.props.CollectionFreeFormDocumentView?.().nudge(-1, 0)), "nudge left"); break; case "arrowright": UndoManager.RunInBatch(() => SelectionManager.Views().map(dv => dv.props.CollectionFreeFormDocumentView?.().nudge?.(1, 0)), "nudge right"); break; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 9ae469930..f305174f1 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -211,14 +211,7 @@ export class CollectionView extends Touchable { } const first = doc instanceof Doc ? doc : doc[0]; if (!first?._stayInCollection && addDocument !== returnFalse) { - if (UndoManager.RunInTempBatch(() => this.removeDocument(doc))) { - const added = addDocument(doc); - if (!added) UndoManager.UndoTempBatch(); - else UndoManager.ClearTempBatch(); - - return added; - } - UndoManager.ClearTempBatch(); + return UndoManager.RunInTempBatch(() => this.removeDocument(doc) && addDocument(doc)); } return false; } diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index aed6302ad..00e9456a1 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -39,14 +39,14 @@ export interface TreeViewProps { containingCollection: Doc; prevSibling?: Doc; renderDepth: number; - removeDoc: ((doc: Doc | Doc[]) => boolean) | undefined; - moveDocument: DragManager.MoveFunction; dropAction: dropActionType; addDocTab: (doc: Doc, where: string) => boolean; pinToPres: (document: Doc) => void; panelWidth: () => number; panelHeight: () => number; addDocument: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean; + removeDoc: ((doc: Doc | Doc[]) => boolean) | undefined; + moveDocument: DragManager.MoveFunction; indentDocument?: (editTitle: boolean) => void; outdentDocument?: (editTitle: boolean) => void; ScreenToLocalTransform: () => Transform; @@ -263,20 +263,15 @@ export class TreeView extends React.Component { e.stopPropagation(); if (docDragData.draggedDocuments[0] === this.doc) return true; const parentAddDoc = (doc: Doc | Doc[]) => this.props.addDocument(doc, undefined, before); - let addDoc = parentAddDoc; - if (inside) { - const localAdd = (doc: Doc) => { - const added = Doc.AddDocToList(this.dataDoc, this.fieldKey, doc); - added && (doc.context = this.doc.context); - return added; - }; - addDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce( - (flg: boolean, doc) => flg && localAdd(doc), true) || parentAddDoc(doc); - } + const canAdd = !StrCast((inside ? this.props.document : this.props.containingCollection)?.freezeChildren).includes("add") || docDragData.treeViewDoc === this.props.treeView.props.Document; + const localAdd = (doc: Doc) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc) && ((doc.context = this.doc.context) || true) ? true : false; + const addDoc = !inside ? parentAddDoc : + (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc), true as boolean); const move = (!docDragData.dropAction || docDragData.dropAction === "move" || docDragData.dropAction === "same") && docDragData.moveDocument; - return docDragData.droppedDocuments.reduce((added, d) => (move ? docDragData.moveDocument?.(d, undefined, addDoc) : addDoc(d)) || added, false); + if (canAdd) { + UndoManager.RunInTempBatch(() => docDragData.droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) : addDoc(d)) || added, false)); + } } - return false; } refTransform = (ref: HTMLDivElement | undefined | null) => { @@ -401,16 +396,19 @@ export class TreeView extends React.Component { const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true); const docs = expandKey === "links" ? this.childLinks : expandKey === "annotations" ? this.childAnnos : this.childDocs; const sortKey = `${this.fieldKey}-sortCriteria`; - return
    { - if (this.props.active()) { - !this.outlineMode && (this.doc[sortKey] = - (this.doc[sortKey] === "ascending" ? "descending" : - (this.doc[sortKey] === "descending" ? "zorder" : - (this.doc[sortKey] === "zorder" ? undefined : - "ascending")))); - e.stopPropagation(); - } - }}> + let downX = 0, downY = 0; + return
      { downX = e.clientX; downY = e.clientY; }} + onClick={(e) => { + if (this.props.active() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) { + !this.outlineMode && (this.doc[sortKey] = + (this.doc[sortKey] === "ascending" ? "descending" : + (this.doc[sortKey] === "descending" ? "zorder" : + (this.doc[sortKey] === "zorder" ? undefined : + "ascending")))); + e.stopPropagation(); + } + }}> {!docs ? (null) : TreeView.GetChildElements(docs, this.props.treeView, this.layoutDoc, this.dataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move, @@ -571,7 +569,7 @@ export class TreeView extends React.Component { : { this._docRef = r ? r : undefined; - if (this._docRef && TreeView._editTitleOnLoad?.id === this.props.document[Id] && TreeView._editTitleOnLoad.parent == this.props.parentTreeView) { + if (this._docRef && TreeView._editTitleOnLoad?.id === this.props.document[Id] && TreeView._editTitleOnLoad.parent === this.props.parentTreeView) { this._docRef.select(false); this.setEditTitle(this._docRef); TreeView._editTitleOnLoad = undefined; @@ -772,7 +770,7 @@ export class TreeView extends React.Component { parentCollectionDoc: Doc | undefined, parentPrevSibling: Doc | undefined, add: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean, - remove: ((doc: Doc | Doc[]) => boolean), + remove: undefined | ((doc: Doc | Doc[]) => boolean), move: DragManager.MoveFunction, dropAction: dropActionType, addDocTab: (doc: Doc, where: string) => boolean, @@ -818,7 +816,7 @@ export class TreeView extends React.Component { newParent.treeViewOpen = true; child.context = treeView.Document; } - } + }; const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1])); const outdent = parentCollectionDoc?._viewType !== CollectionViewType.Tree ? undefined : ((editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, parentPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined)); const addDocument = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 36d14056b..4008a20b3 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -28,6 +28,7 @@ import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu"; import "./MarqueeView.scss"; import React = require("react"); import { StyleLayers } from "../../StyleProvider"; +import { TreeView } from "../TreeView"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -161,8 +162,8 @@ export class MarqueeView extends React.Component SelectionManager.SelectDoc(DocumentManager.Instance.getDocumentView(slide)!, false)); e.stopPropagation(); } else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) { FormattedTextBox.SelectOnLoadChar = FormattedTextBox.DefaultLayout && !this.props.childLayoutString ? e.key : ""; diff --git a/src/server/websocket.ts b/src/server/websocket.ts index 6850f0601..7e3c4da82 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -299,7 +299,7 @@ export namespace WebSocket { diff.diff.$set = diff.diff.$remFromSet; delete diff.diff.$remFromSet; const updatefield = Array.from(Object.keys(diff.diff.$set))[0]; const remListItems = diff.diff.$set[updatefield].fields; - const curList = (curListItems as any)?.fields?.[updatefield.replace("fields.", "")]?.fields || []; + const curList = (curListItems as any)?.fields?.[updatefield.replace("fields.", "")]?.fields.filter((f: any) => f !== null) || []; diff.diff.$set[updatefield].fields = curList?.filter((curItem: any) => !remListItems.some((remItem: any) => remItem.fieldId ? remItem.fieldId === curItem.fieldId : remItem.heading ? remItem.heading === curItem.heading : remItem === curItem)); const sendBack = diff.diff.length !== diff.diff.$set[updatefield].fields.length; delete diff.diff.length; -- cgit v1.2.3-70-g09d2 From 77b1f624f24e055c498e3104fc84227a545a05b9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 23 Feb 2021 02:22:00 -0500 Subject: clean up from last. --- src/client/views/collections/TreeView.tsx | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 00e9456a1..ec8e63b6c 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -382,7 +382,7 @@ export class TreeView extends React.Component { // if there's a sort ordering specified that can be modified on drop (eg, zorder can be modified, alphabetical can't), // then the modification would be done here const ordering = StrCast(this.doc[this.fieldKey + "-sortCriteria"]); - if (ordering === "zorder") { + if (ordering === "Z") { const docs = TreeView.sortDocs(this.childDocs || ([] as Doc[]), ordering); doc.zIndex = addBefore ? (before ? NumCast(addBefore.zIndex) - 0.5 : NumCast(addBefore.zIndex) + 0.5) : 1000; docs.push(doc); @@ -397,15 +397,13 @@ export class TreeView extends React.Component { const docs = expandKey === "links" ? this.childLinks : expandKey === "annotations" ? this.childAnnos : this.childDocs; const sortKey = `${this.fieldKey}-sortCriteria`; let downX = 0, downY = 0; - return
        { downX = e.clientX; downY = e.clientY; }} + const sortings = ["up", "down", "Z", undefined]; + const curSort = Math.max(0, sortings.indexOf(Cast(this.doc[sortKey], "string", null))); + return
          { downX = e.clientX; downY = e.clientY; e.stopPropagation(); }} onClick={(e) => { if (this.props.active() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) { - !this.outlineMode && (this.doc[sortKey] = - (this.doc[sortKey] === "ascending" ? "descending" : - (this.doc[sortKey] === "descending" ? "zorder" : - (this.doc[sortKey] === "zorder" ? undefined : - "ascending")))); + !this.outlineMode && (this.doc[sortKey] = sortings[(curSort + 1) % sortings.length]); e.stopPropagation(); } }}> @@ -461,9 +459,9 @@ export class TreeView extends React.Component {
          + checked === "x" ? "times" : + checked === "unchecked" ? "square" : + !this.treeViewOpen ? "caret-right" : "caret-down"} />
          {this.onCheckedClick ? (null) : }
@@ -701,7 +699,7 @@ export class TreeView extends React.Component { @computed get renderBorder() { const sorting = this.doc[`${this.fieldKey}-sortCriteria`]; return
+ style={{ borderColor: sorting === undefined ? undefined : sorting === "up" ? "crimson" : sorting === "down" ? "blue" : "green" }}> {!this.treeViewOpen ? (null) : this.renderContent}
; } @@ -749,10 +747,10 @@ export class TreeView extends React.Component { } }; docs.sort(function (d1, d2): 0 | 1 | -1 { - const a = (criterion === "ascending" ? d2 : d1); - const b = (criterion === "ascending" ? d1 : d2); - const first = a[criterion === "zorder" ? "zIndex" : "title"]; - const second = b[criterion === "zorder" ? "zIndex" : "title"]; + const a = (criterion === "up" ? d2 : d1); + const b = (criterion === "up" ? d1 : d2); + const first = a[criterion === "Z" ? "zIndex" : "title"]; + const second = b[criterion === "Z" ? "zIndex" : "title"]; if (typeof first === 'number' && typeof second === 'number') return (first - second) > 0 ? 1 : -1; if (typeof first === 'string' && typeof second === 'string') return sortAlphaNum(first, second); return criterion ? 1 : -1; -- cgit v1.2.3-70-g09d2 From ee2f9feea2ec70dbf5a60d2b26a61b05eca3dbf5 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 23 Feb 2021 10:23:26 -0500 Subject: cleaned up EditableView a bit --- src/client/views/EditableView.tsx | 59 +++++----------------- .../collections/CollectionMasonryViewFieldRow.tsx | 35 ++++++------- .../CollectionStackingViewFieldColumn.tsx | 33 +++++------- .../views/collections/CollectionTimeView.tsx | 32 ++++++------ src/client/views/collections/TreeView.tsx | 1 + src/client/views/nodes/KeyValuePair.tsx | 7 +-- src/client/views/nodes/LinkDescriptionPopup.tsx | 1 - src/debug/Viewer.tsx | 3 +- 8 files changed, 63 insertions(+), 108 deletions(-) (limited to 'src') diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index ed7a8265f..e2f171f9d 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -3,8 +3,6 @@ import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as Autosuggest from 'react-autosuggest'; import { ObjectField } from '../../fields/ObjectField'; -import { SchemaHeaderField } from '../../fields/SchemaHeaderField'; -import { DragManager } from '../util/DragManager'; import "./EditableView.scss"; export interface EditableProps { @@ -12,16 +10,13 @@ export interface EditableProps { * Called to get the initial value for editing * */ GetValue(): string | undefined; - /** * Called to apply changes * @param value - The string entered by the user to set the value to * @returns `true` if setting the value was successful, `false` otherwise * */ SetValue(value: string, shiftDown?: boolean, enterKey?: boolean): boolean; - OnFillDown?(value: string): void; - OnTab?(shift?: boolean): void; OnEmpty?(): void; @@ -45,15 +40,12 @@ export interface EditableProps { }; oneLine?: boolean; editing?: boolean; - onClick?: (e: React.MouseEvent) => boolean; isEditingCallback?: (isEditing: boolean) => void; menuCallback?: (x: number, y: number) => void; textCallback?: (char: string) => boolean; showMenuOnLoad?: boolean; - HeadingObject?: SchemaHeaderField | undefined; toggle?: () => void; - color?: string | undefined; - onDrop?: any; + background?: string | undefined; placeholder?: string; } @@ -64,6 +56,8 @@ export interface EditableProps { */ @observer export class EditableView extends React.Component { + private _ref = React.createRef(); + private _inputref = React.createRef(); @observable _editing: boolean = false; constructor(props: EditableProps) { @@ -71,17 +65,6 @@ export class EditableView extends React.Component { this._editing = this.props.editing ? true : false; } - // @action - // componentDidUpdate(nextProps: EditableProps) { - // // this is done because when autosuggest is turned on, the suggestions are passed in as a prop, - // // so when the suggestions are passed in, and no editing prop is passed in, it used to set it - // // to false. this will no longer do so -syip - // if (nextProps.editing && nextProps.editing !== this._editing) { - // this._editing = nextProps.editing; - // EditableView.loadId = ""; - // } - // } - @action componentDidUpdate() { if (this._editing && this.props.editing === false) { @@ -91,19 +74,10 @@ export class EditableView extends React.Component { } } - @action - componentDidMount() { - if (this._ref.current && this.props.onDrop) { - DragManager.MakeDropTarget(this._ref.current, this.props.onDrop.bind(this)); - } - } - @action componentWillUnmount() { this._inputref.current?.value && this.finalizeEdit(this._inputref.current.value, false, true, false); } - _didShow = false; - @action onKeyDown = (e: React.KeyboardEvent) => { switch (e.key) { @@ -149,7 +123,7 @@ export class EditableView extends React.Component { e.nativeEvent.stopPropagation(); if (this._ref.current && this.props.showMenuOnLoad) { this.props.menuCallback?.(this._ref.current.getBoundingClientRect().x, this._ref.current.getBoundingClientRect().y); - } else if (!this.props.onClick?.(e)) { + } else { this._editing = true; this.props.isEditingCallback?.(true); } @@ -158,7 +132,7 @@ export class EditableView extends React.Component { } @action - private finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean, enterKey: boolean) { + finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean, enterKey: boolean) { if (this.props.SetValue(value, shiftDown, enterKey)) { this._editing = false; this.props.isEditingCallback?.(false,); @@ -172,9 +146,7 @@ export class EditableView extends React.Component { } } - stopPropagation(e: React.SyntheticEvent) { - e.stopPropagation(); - } + stopPropagation(e: React.SyntheticEvent) { e.stopPropagation(); } @action setIsFocused = (value: boolean) => { @@ -183,8 +155,6 @@ export class EditableView extends React.Component { return wasFocused !== this._editing; } - _ref = React.createRef(); - _inputref = React.createRef(); renderEditor() { return this.props.autosuggestProps ? { }} /> : this.finalizeEdit(e.currentTarget.value, false, true, false)} defaultValue={this.props.GetValue()} - onKeyDown={this.onKeyDown} autoFocus={true} - onKeyPress={e => e.stopPropagation()} - onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)} - onPointerDown={this.stopPropagation} onClick={this.stopPropagation} onPointerUp={this.stopPropagation} - style={{ display: this.props.display, fontSize: this.props.fontSize, minWidth: 20 }} - placeholder={this.props.placeholder} + onKeyDown={this.onKeyDown} + onKeyPress={this.stopPropagation} onPointerDown={this.stopPropagation} onClick={this.stopPropagation} onPointerUp={this.stopPropagation} />; } @@ -225,13 +194,13 @@ export class EditableView extends React.Component { : this.renderEditor(); } - setTimeout(() => this.props.autosuggestProps?.resetValue(), 0); + setTimeout(() => this.props.autosuggestProps?.resetValue()); return this.props.contents instanceof ObjectField ? (null) :
- { - this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()} + + {this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()}
; } diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx index ff69c7d05..4bdd39194 100644 --- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx +++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx @@ -6,7 +6,7 @@ import { Doc, DocListCast, DataSym } from "../../../fields/Doc"; import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField"; import { ScriptField } from "../../../fields/ScriptField"; import { StrCast, NumCast } from "../../../fields/Types"; -import { numberRange, setupMoveUpEvents, emptyFunction } from "../../../Utils"; +import { numberRange, setupMoveUpEvents, emptyFunction, returnEmptyString } from "../../../Utils"; import { Docs } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; import { CompileScript } from "../../util/Scripting"; @@ -249,14 +249,6 @@ export class CollectionMasonryViewFieldRow extends React.Component "", - SetValue: this.addDocument, - textCallback: this.textCallback, - contents: "+ NEW", - HeadingObject: this.props.headingObject, - toggle: this.toggleVisibility, - }; const showChrome = (chromeStatus !== 'view-mode' && chromeStatus !== 'disabled'); const stackPad = showChrome ? `0px ${this.props.parent.xMargin}px` : `${this.props.parent.yMargin}px ${this.props.parent.xMargin}px 0px ${this.props.parent.xMargin}px `; return this.collapsed ? (null) : @@ -267,7 +259,12 @@ export class CollectionMasonryViewFieldRow extends React.Component - + : null }
evContents, - SetValue: this.headingChanged, - contents: evContents, - oneLine: true, - HeadingObject: this.props.headingObject, - toggle: this.toggleVisibility, - }; + const editableHeaderView = evContents} + SetValue={this.headingChanged} + contents={evContents} + oneLine={true} + toggle={this.toggleVisibility} />; return this.props.parent.props.Document.miniHeaders ?
- + {editableHeaderView}
: !this.props.headingObject ? (null) :
@@ -306,7 +301,7 @@ export class CollectionMasonryViewFieldRow extends React.Component - {noChrome ? evContents : } + {noChrome ? evContents : editableHeaderView} {noChrome || evContents === `NO ${key.toUpperCase()} VALUE` ? (null) :
: null}
} diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index cd91cbf63..857d5e1d7 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -8,7 +8,7 @@ import { RichTextField } from "../../../fields/RichTextField"; import { listSpec } from "../../../fields/Schema"; import { ComputedField, ScriptField } from "../../../fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../../fields/Types"; -import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents } from "../../../Utils"; +import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents, returnEmptyString } from "../../../Utils"; import { Docs, DocUtils } from "../../documents/Documents"; import { DocumentManager } from "../../util/DocumentManager"; import { Scripting } from "../../util/Scripting"; @@ -193,22 +193,22 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { } @computed get pivotKeyUI() { - const newEditableViewProps = { - GetValue: () => "", - SetValue: (value: any) => { - if (value?.length) { - this.layoutDoc._pivotField = value; - return true; - } - return false; - }, - showMenuOnLoad: true, - contents: ":" + StrCast(this.layoutDoc._pivotField), - toggle: this.toggleVisibility, - color: "#f1efeb" // this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; - }; return
- + { + if (value?.length) { + this.layoutDoc._pivotField = value; + return true; + } + return false; + }} + toggle={this.toggleVisibility} + background={"#f1efeb"} // this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; + contents={":" + StrCast(this.layoutDoc._pivotField)} + showMenuOnLoad={true} + display={"inline"} + menuCallback={this.menuCallback} />
; } diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index ec8e63b6c..297796b4b 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -548,6 +548,7 @@ export class TreeView extends React.Component { oneLine={true} display={"inline-block"} editing={true} + background={"#7089bb"} contents={StrCast(this.doc.title)} height={12} sizeToContent={true} diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index ce9d8bed5..ebb953dad 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -125,12 +125,9 @@ export class KeyValuePair extends React.Component { contents={contents} maxHeight={36} height={"auto"} - GetValue={() => { - return Field.toKeyValueString(props.Document, props.fieldKey); - }} + GetValue={() => Field.toKeyValueString(props.Document, props.fieldKey)} SetValue={(value: string) => - KeyValueBox.SetField(props.Document, props.fieldKey, value)}> -
+ KeyValueBox.SetField(props.Document, props.fieldKey, value)} />
diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx index 720af6c9d..30b272a9a 100644 --- a/src/client/views/nodes/LinkDescriptionPopup.tsx +++ b/src/client/views/nodes/LinkDescriptionPopup.tsx @@ -2,7 +2,6 @@ import React = require("react"); import { observer } from "mobx-react"; import "./LinkDescriptionPopup.scss"; import { observable, action } from "mobx"; -import { EditableView } from "../EditableView"; import { LinkManager } from "../../util/LinkManager"; import { TaskCompletionBox } from "./TaskCompletedBox"; diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx index bebd71dcf..ee7dd1fc1 100644 --- a/src/debug/Viewer.tsx +++ b/src/debug/Viewer.tsx @@ -138,8 +138,7 @@ class DebugViewer extends React.Component<{ field: FieldResult, setValue(value: return

Unrecognized field type

; } - return Field.toScriptString(field)} SetValue={this.props.setValue} - contents={content}>; + return Field.toScriptString(field)} SetValue={this.props.setValue} contents={content} />; } } -- cgit v1.2.3-70-g09d2 From ba120c1c8bde4d78b339b81798aaee0d7bfb2eb3 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 23 Feb 2021 14:42:42 -0500 Subject: restored export/import of collection clones. did a little cleanup of collection freeform view --- .../collectionFreeForm/CollectionFreeFormView.tsx | 150 +++++++-------------- src/fields/Doc.ts | 6 +- src/server/ApiManagers/UploadManager.ts | 23 ++-- 3 files changed, 61 insertions(+), 118 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 58288a7b1..18cf825a3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -13,7 +13,7 @@ import { ScriptField } from "../../../../fields/ScriptField"; import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; import { TraceMobx } from "../../../../fields/util"; import { GestureUtils } from "../../../../pen-gestures/GestureUtils"; -import { aggregateBounds, intersectRect, returnFalse, setupMoveUpEvents, Utils } from "../../../../Utils"; +import { aggregateBounds, intersectRect, returnFalse, setupMoveUpEvents, Utils, emptyFunction } from "../../../../Utils"; import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { DocServer } from "../../../DocServer"; import { Docs, DocUtils } from "../../../documents/Documents"; @@ -57,7 +57,6 @@ export const panZoomSchema = createSchema({ _currentTimecode: "number", _timecodeToShow: "number", _currentFrame: "number", - arrangeInit: ScriptField, _useClusters: "boolean", fitToBox: "boolean", _xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set @@ -104,19 +103,19 @@ export class CollectionFreeFormView extends CollectionSubView(); @observable _marqueeRef = React.createRef(); - @observable _focusFilters: Opt; // fields that get overriden by focus anchor - @observable _focusRangeFilters: Opt; // fields that get overriden by focus anchor + @observable _focusFilters: Opt; // docFilters that are overridden when previewing a link to an anchor which has docFilters set on it + @observable _focusRangeFilters: Opt; // docRangeFilters that are overridden when previewing a link to an anchor which has docRangeFilters set on it @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && (this.props.ContainingCollectionView?.active() || this.props.active()); } @computed get fitToContentVals() { @@ -126,10 +125,9 @@ export class CollectionFreeFormView extends CollectionSubView e.bounds && !e.bounds.z).map(e => e.bounds!), NumCast(this.layoutDoc._xPadding, 10), NumCast(this.layoutDoc._yPadding, 10)); } @computed get nativeWidth() { return this.fitToContent ? 0 : Doc.NativeWidth(this.Document); } @computed get nativeHeight() { return this.fitToContent ? 0 : Doc.NativeHeight(this.Document); } @@ -138,14 +136,15 @@ export class CollectionFreeFormView extends CollectionSubView this.freeformData()?.panX ?? NumCast(this.Document._panX); private panY = () => this.freeformData()?.panY ?? NumCast(this.Document._panY); - private zoomScaling = () => (this.freeformData()?.scale ?? NumCast(this.Document[this.scaleFieldKey], 1)) / this.parentScaling; + private zoomScaling = () => (this.freeformData()?.scale ?? NumCast(this.Document[this.scaleFieldKey], 1)); + private contentTransform = () => `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)` @computed get cachedCenteringShiftX(): number { const scaling = this.fitToContent || !this.contentScaling ? 1 : this.contentScaling; - return this.props.isAnnotationOverlay ? 0 : this.props.PanelWidth() / 2 / this.parentScaling / scaling; // shift so pan position is at center of window for non-overlay collections + return this.props.isAnnotationOverlay ? 0 : this.props.PanelWidth() / 2 / scaling; // shift so pan position is at center of window for non-overlay collections } @computed get cachedCenteringShiftY(): number { const scaling = this.fitToContent || !this.contentScaling ? 1 : this.contentScaling; - return this.props.isAnnotationOverlay ? 0 : this.props.PanelHeight() / 2 / this.parentScaling / scaling;// shift so pan position is at center of window for non-overlay collections + return this.props.isAnnotationOverlay ? 0 : this.props.PanelHeight() / 2 / scaling;// shift so pan position is at center of window for non-overlay collections } @computed get cachedGetLocalTransform(): Transform { return Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY()); @@ -157,8 +156,6 @@ export class CollectionFreeFormView extends CollectionSubView this.cachedCenteringShiftX; - private centeringShiftY = () => this.cachedCenteringShiftY; private getTransform = () => this.cachedGetTransform.copy(); private getLocalTransform = () => this.cachedGetLocalTransform.copy(); private getContainerTransform = () => this.cachedGetContainerTransform.copy(); @@ -1065,7 +1062,7 @@ export class CollectionFreeFormView extends CollectionSubView) { - const layoutDocs = this.childLayoutPairs.map(pair => pair.layout); - const initResult = this.Document.arrangeInit?.script.run({ docs: layoutDocs, collection: this.Document }, console.log); - const state = initResult?.success ? initResult.result.scriptState : undefined; - const elements = initResult?.success ? this.viewDefsToJSX(initResult.result.views) : []; - - this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map((pair, i) => { - const pos = this.getCalculatedPositions({ pair, index: i, collection: this.Document, docs: layoutDocs, state }); - poolData.set(pair.layout[Id], pos); - }); - return elements; + this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map((pair, i) => + poolData.set(pair.layout[Id], this.getCalculatedPositions({ pair, index: i, collection: this.Document }))); + return [] as ViewDefResult[]; } @computed get doInternalLayoutComputation() { TraceMobx(); - const newPool = new Map(); - const engine = this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine); - switch (engine) { + switch (this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine)) { case "pass": return { newPool, computedElementData: this.doEngineLayout(newPool, computerPassLayout) }; case "timeline": return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) }; case "pivot": return { newPool, computedElementData: this.doEngineLayout(newPool, computePivotLayout) }; @@ -1437,19 +1425,9 @@ export class CollectionFreeFormView extends CollectionSubView { - const children = typeof this.props.children === "function" ? (this.props.children as any)() as JSX.Element[] : []; - return [ - ...children, - ...this.views, - ]; - } - children = () => { - const eles: JSX.Element[] = []; - eles.push(...this.childViews()); - eles.push(); - return eles; + const children = typeof this.props.children === "function" ? (this.props.children as any)() as JSX.Element[] : []; + return [...children, ...this.views, ]; } @computed get placeholder() { @@ -1486,8 +1464,8 @@ export class CollectionFreeFormView extends CollectionSubView { const ctx = el?.getContext('2d'); if (ctx) { - const Cx = this.centeringShiftX() % renderGridSpace; - const Cy = this.centeringShiftY() % renderGridSpace; + const Cx = this.cachedCenteringShiftX % renderGridSpace; + const Cy = this.cachedCenteringShiftY % renderGridSpace; ctx.lineWidth = Math.min(1, Math.max(0.5, this.zoomScaling())); ctx.setLineDash(gridSpace > 50 ? [3, 3] : [1, 5]); ctx.clearRect(0, 0, w, h); @@ -1536,14 +1514,13 @@ export class CollectionFreeFormView extends CollectionSubView + viewDefDivClick={this.props.viewDefDivClick}> {this.children} @@ -1582,7 +1559,7 @@ export class CollectionFreeFormView extends CollectionSubView {this.Document._freeformLOD && !this.props.active() && !this.props.isAnnotationOverlay && this.props.renderDepth > 0 ? this.placeholder : this.marqueeView} - {!this.props.noOverlay ? : (null)} + {this.props.noOverlay ? (null) : }
number; - centeringShiftY: () => number; - panX: () => number; - panY: () => number; + transform: () => string; zoomScaling: () => number; viewDefDivClick?: ScriptField; children: () => JSX.Element[]; @@ -1644,67 +1618,45 @@ interface CollectionFreeFormViewPannableContentsProps { @observer class CollectionFreeFormViewPannableContents extends React.Component{ - @observable private _drag: string = ''; + @observable _drag: string = ''; //Adds event listener so knows pointer is down and moving onPointerDown = (e: React.PointerEvent): void => { e.stopPropagation(); e.preventDefault(); - const corner = e.target as any; - if (corner) this._drag = corner.id; - const rect = document.getElementById(this._drag); - if (rect) { - setupMoveUpEvents(e.target, e, this.onPointerMove, (e) => { }, (e) => { }); - } - } - - //Removes all event listeners - onPointerUp = (e: PointerEvent): void => { - e.stopPropagation(); - e.preventDefault(); - this._drag = ""; - document.removeEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); + this._drag = (e.target as any)?.id ?? ""; + document.getElementById(this._drag) && setupMoveUpEvents(e.target, e, this.onPointerMove, emptyFunction, emptyFunction); } //Adjusts the value in NodeStore @action onPointerMove = (e: PointerEvent) => { const doc = document.getElementById('resizable'); - const rect = doc!.getBoundingClientRect(); - const toNumber = (original: number, delta: number): number => { - return original + (delta * this.props.zoomScaling()); - }; + const toNumber = (original: number, delta: number) => original + (delta * this.props.zoomScaling()); if (doc) { - const height = doc.offsetHeight; - const width = doc.offsetWidth; - const top = doc.offsetTop; - const left = doc.offsetLeft; switch (this._drag) { - case "": break; case "resizer-br": - doc.style.width = toNumber(width, e.movementX) + 'px'; - doc.style.height = toNumber(height, e.movementY) + 'px'; + doc.style.width = toNumber(doc.offsetWidth, e.movementX) + 'px'; + doc.style.height = toNumber(doc.offsetHeight, e.movementY) + 'px'; break; case "resizer-bl": - doc.style.width = toNumber(width, -e.movementX) + 'px'; - doc.style.height = toNumber(height, e.movementY) + 'px'; - doc.style.left = toNumber(left, e.movementX) + 'px'; + doc.style.width = toNumber(doc.offsetWidth, -e.movementX) + 'px'; + doc.style.height = toNumber(doc.offsetHeight, e.movementY) + 'px'; + doc.style.left = toNumber(doc.offsetLeft, e.movementX) + 'px'; break; case "resizer-tr": - doc.style.width = toNumber(width, -e.movementX) + 'px'; - doc.style.height = toNumber(height, -e.movementY) + 'px'; - doc.style.top = toNumber(top, e.movementY) + 'px'; + doc.style.width = toNumber(doc.offsetWidth, -e.movementX) + 'px'; + doc.style.height = toNumber(doc.offsetHeight, -e.movementY) + 'px'; + doc.style.top = toNumber(doc.offsetTop, e.movementY) + 'px'; case "resizer-tl": - doc.style.width = toNumber(width, -e.movementX) + 'px'; - doc.style.height = toNumber(height, -e.movementY) + 'px'; - doc.style.top = toNumber(top, e.movementY) + 'px'; - doc.style.left = toNumber(left, e.movementX) + 'px'; + doc.style.width = toNumber(doc.offsetWidth, -e.movementX) + 'px'; + doc.style.height = toNumber(doc.offsetHeight, -e.movementY) + 'px'; + doc.style.top = toNumber(doc.offsetTop, e.movementY) + 'px'; + doc.style.left = toNumber(doc.offsetLeft, e.movementX) + 'px'; case "resizable": - doc.style.top = toNumber(top, e.movementY) + 'px'; - doc.style.left = toNumber(left, e.movementX) + 'px'; + doc.style.top = toNumber(doc.offsetTop, e.movementY) + 'px'; + doc.style.left = toNumber(doc.offsetLeft, e.movementX) + 'px'; } - // this.updateAll(height, width, top, left); return false; } return true; @@ -1763,16 +1715,8 @@ class CollectionFreeFormViewPannableContents extends React.Component; } - render() { - // trace(); - const freeformclass = "collectionfreeformview" + (this.props.viewDefDivClick ? "-viewDef" : "-none"); - const cenx = this.props.centeringShiftX(); - const ceny = this.props.centeringShiftY(); - const panx = -this.props.panX(); - const pany = -this.props.panY(); - const zoom = this.props.zoomScaling(); - return
{ const target = e.target as any; if (getComputedStyle(target)?.overflow === "visible") { // if collection is visible, then scrolling will mess things up since there are no scroll bars @@ -1780,7 +1724,7 @@ class CollectionFreeFormViewPannableContents extends React.Component clear && Array.from(Object.keys(self)).forEach(key => delete self[key])); - return this.___fields; - } + public [FieldsSym] = () => this[Self].___fields; // Object.keys(this).reduce((fields, key) => { fields[key] = this[key]; return fields; }, {} as any); public [WidthSym] = () => NumCast(this[SelfProxy]._width); public [HeightSym] = () => NumCast(this[SelfProxy]._height); public [ToScriptString] = () => `DOC-"${this[Self][Id]}"-`; diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts index e98498489..d6950d46a 100644 --- a/src/server/ApiManagers/UploadManager.ts +++ b/src/server/ApiManagers/UploadManager.ts @@ -142,7 +142,9 @@ export default class UploadManager extends ApiManager { const field = doc.fields[key]; if (field === undefined || field === null) { continue; } - if (field.__type === "proxy" || field.__type === "prefetch_proxy") { + if (field.__type === "Doc") { + mapFn(field); + } else if (field.__type === "proxy" || field.__type === "prefetch_proxy") { field.fieldId = getId(field.fieldId); } else if (field.__type === "script" || field.__type === "computed") { if (field.captures) { @@ -189,22 +191,23 @@ export default class UploadManager extends ApiManager { } }); const json = zip.getEntry("doc.json"); - let docs: any; try { const data = JSON.parse(json.getData().toString("utf8")); - docs = data.docs; - id = data.id; - docs = Object.keys(docs).map(key => docs[key]); + const datadocs = data.docs; + id = getId(data.id); + const docs = Object.keys(datadocs).map(key => datadocs[key]); docs.forEach(mapFn); - await Promise.all(docs.map((doc: any) => new Promise(res => Database.Instance.replace(doc.id, doc, (err, r) => { - err && console.log(err); - res(); - }, true)))); + await Promise.all(docs.map((doc: any) => new Promise(res => { + Database.Instance.replace(doc.id, doc, (err, r) => { + err && console.log(err); + res(); + }, true); + }))); } catch (e) { console.log(e); } unlink(path_2, () => { }); } SolrManager.update(); - res.send(JSON.stringify(id ? getId(id) : "error")); + res.send(JSON.stringify(id || "error")); } catch (e) { console.log(e); } resolve(); }); -- cgit v1.2.3-70-g09d2 From 684faaab165681c34fe824e1b6ac887d25b73f36 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 23 Feb 2021 17:18:14 -0500 Subject: reorg and cleanup a bit of colelctionfreeformview. minor other cleanup. --- .../collectionFreeForm/CollectionFreeFormView.tsx | 340 ++++++++++----------- src/client/views/nodes/DocumentView.tsx | 6 +- src/fields/Doc.ts | 9 +- 3 files changed, 165 insertions(+), 190 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 18cf825a3..9041d9b21 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -13,7 +13,7 @@ import { ScriptField } from "../../../../fields/ScriptField"; import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; import { TraceMobx } from "../../../../fields/util"; import { GestureUtils } from "../../../../pen-gestures/GestureUtils"; -import { aggregateBounds, intersectRect, returnFalse, setupMoveUpEvents, Utils, emptyFunction } from "../../../../Utils"; +import { aggregateBounds, emptyFunction, intersectRect, returnFalse, setupMoveUpEvents, Utils } from "../../../../Utils"; import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { DocServer } from "../../../DocServer"; import { Docs, DocUtils } from "../../../documents/Documents"; @@ -58,24 +58,20 @@ export const panZoomSchema = createSchema({ _timecodeToShow: "number", _currentFrame: "number", _useClusters: "boolean", - fitToBox: "boolean", + _viewTransition: "string", _xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set _yPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set - _viewTransition: "string", - scrollHeight: "number", - fitX: "number", - fitY: "number", - fitW: "number", - fitH: "number" + _fitToBox: "boolean", + scrollHeight: "number" // this will be set when the collection is an annotation overlay for a PDF/Webpage }); type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof collectionSchema, typeof documentSchema, typeof pageSchema]>; const PanZoomDocument = makeInterface(panZoomSchema, collectionSchema, documentSchema, pageSchema); export type collectionFreeformViewProps = { + parentActive: (outsideReaction: boolean) => boolean; forceScaling?: boolean; // whether to force scaling of content (needed by ImageBox) viewDefDivClick?: ScriptField; childPointerEvents?: boolean; - parentActive: (outsideReaction: boolean) => boolean; scaleField?: string; noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale) engineProps?: any; @@ -94,29 +90,32 @@ export class CollectionFreeFormView extends CollectionSubView = new Map(); private _clusterDistance: number = 75; private _hitCluster: number = -1; - private _layoutComputeReaction: IReactionDisposer | undefined; - private _boundsReaction: IReactionDisposer | undefined; + private _disposers: { [name: string]: IReactionDisposer } = {}; private _layoutPoolData = new ObservableMap(); private _layoutSizeData = new ObservableMap(); private _cachedPool: Map = new Map(); private _lastTap = 0; private _nudgeTime = 0; - private _thumbIdentifier?: number; + private get isAnnotationOverlay() { return this.props.isAnnotationOverlay; } + private get scaleFieldKey() { return this.props.scaleField || "_viewScale"; } + private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; } + + @observable.shallow _layoutElements: ViewDefResult[] = []; // shallow because some layout items (eg pivot labels) are just generated 'divs' and can't be frozen as observables @observable _hLines: number[] | undefined; @observable _vLines: number[] | undefined; @observable _pullCoords: number[] = [0, 0]; @observable _pullDirection: string = ""; @observable _showAnimTimeline = false; - @observable ChildDrag: DocumentView | undefined; // child document view being dragged. needed to update drop areas of groups when a group item is dragged. - - @observable.shallow _layoutElements: ViewDefResult[] = []; // shallow because some layout items (eg pivot labels) are just generated 'divs' and can't be frozen as observables @observable _clusterSets: (Doc[])[] = []; @observable _timelineRef = React.createRef(); @observable _marqueeRef = React.createRef(); @observable _focusFilters: Opt; // docFilters that are overridden when previewing a link to an anchor which has docFilters set on it @observable _focusRangeFilters: Opt; // docRangeFilters that are overridden when previewing a link to an anchor which has docRangeFilters set on it + @observable ChildDrag: DocumentView | undefined; // child document view being dragged. needed to update drop areas of groups when a group item is dragged. + @computed get views() { return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); } + @computed get backgroundEvents() { return this.props.layerProvider?.(this.layoutDoc) === false && SnappingManager.GetIsDragging(); } @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && (this.props.ContainingCollectionView?.active() || this.props.active()); } @computed get fitToContentVals() { return { @@ -131,13 +130,6 @@ export class CollectionFreeFormView extends CollectionSubView e.bounds && !e.bounds.z).map(e => e.bounds!), NumCast(this.layoutDoc._xPadding, 10), NumCast(this.layoutDoc._yPadding, 10)); } @computed get nativeWidth() { return this.fitToContent ? 0 : Doc.NativeWidth(this.Document); } @computed get nativeHeight() { return this.fitToContent ? 0 : Doc.NativeHeight(this.Document); } - private get isAnnotationOverlay() { return this.props.isAnnotationOverlay; } - private get scaleFieldKey() { return this.props.scaleField || "_viewScale"; } - private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; } - private panX = () => this.freeformData()?.panX ?? NumCast(this.Document._panX); - private panY = () => this.freeformData()?.panY ?? NumCast(this.Document._panY); - private zoomScaling = () => (this.freeformData()?.scale ?? NumCast(this.Document[this.scaleFieldKey], 1)); - private contentTransform = () => `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)` @computed get cachedCenteringShiftX(): number { const scaling = this.fitToContent || !this.contentScaling ? 1 : this.contentScaling; return this.props.isAnnotationOverlay ? 0 : this.props.PanelWidth() / 2 / scaling; // shift so pan position is at center of window for non-overlay collections @@ -156,16 +148,31 @@ export class CollectionFreeFormView extends CollectionSubView this.cachedGetTransform.copy(); - private getLocalTransform = () => this.cachedGetLocalTransform.copy(); - private getContainerTransform = () => this.cachedGetContainerTransform.copy(); - private getTransformOverlay = () => this.getContainerTransform().translate(1, 1); - private addLiveTextBox = (newBox: Doc) => { + onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick); + onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); + parentActive = (outsideReaction: boolean) => this.props.active(outsideReaction) || this.props.parentActive?.(outsideReaction) || this.backgroundActive || this.layoutDoc._viewType === CollectionViewType.Pile ? true : false; + elementFunc = () => this._layoutElements; + freeformData = (force?: boolean) => this.fitToContent || force ? this.fitToContentVals : undefined; + freeformDocFilters = () => this._focusFilters || this.docFilters(); + freeformRangeDocFilters = () => this._focusRangeFilters || this.docRangeFilters(); + panX = () => this.freeformData()?.panX ?? NumCast(this.Document._panX); + panY = () => this.freeformData()?.panY ?? NumCast(this.Document._panY); + zoomScaling = () => (this.freeformData()?.scale ?? NumCast(this.Document[this.scaleFieldKey], 1)); + contentTransform = () => `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(); + getTransformOverlay = () => this.getContainerTransform().translate(1, 1); + getActiveDocuments = () => this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout); + addLiveTextBox = (newBox: Doc) => { FormattedTextBox.SelectOnLoad = newBox[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed this.addDocument(newBox); } - - addDocument = action((newBox: Doc | Doc[]) => { + selectDocuments = (docs: Doc[]) => { + SelectionManager.DeselectAll(); + docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView)).map(dv => dv && SelectionManager.SelectView(dv, true)); + } + addDocument = (newBox: Doc | Doc[]) => { let retVal = false; if (newBox instanceof Doc) { retVal = this.props.addDocument?.(newBox) || false; @@ -191,25 +198,6 @@ export class CollectionFreeFormView extends CollectionSubView { - SelectionManager.DeselectAll(); - docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView)).map(dv => dv && SelectionManager.SelectView(dv, true)); - } - public isCurrent(doc: Doc) { - const dispTime = NumCast(doc._timecodeToShow, -1); - const endTime = NumCast(doc._timecodeToHide, dispTime + 1.5); - const curTime = NumCast(this.Document._currentTimecode, -1); - return dispTime === -1 || ((curTime - dispTime) >= -1e-4 && curTime <= endTime); - } - - public getActiveDocuments = () => { - return this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout); - } - - onExternalDrop = (e: React.DragEvent) => { - return (pt => super.onExternalDrop(e, { x: pt[0], y: pt[1] }))(this.getTransform().transformPoint(e.pageX, e.pageY)); } updateGroupBounds = () => { @@ -231,6 +219,13 @@ export class CollectionFreeFormView extends CollectionSubView= -1e-4 && curTime <= endTime); + } + @action internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData, xp: number, yp: number) { if (!this.ChildDrag && this.props.layerProvider?.(this.props.Document) !== false && this.props.Document._isGroup) return false; @@ -271,7 +266,6 @@ export class CollectionFreeFormView extends CollectionSubView { const [xp, yp] = this.getTransform().transformPoint(de.x, de.y); if (this.isAnnotationOverlay !== true && de.complete.linkDragData) return this.internalLinkDrop(e, de, de.complete.linkDragData, xp, yp); @@ -308,6 +300,10 @@ export class CollectionFreeFormView extends CollectionSubView { + return (pt => super.onExternalDrop(e, { x: pt[0], y: pt[1] }))(this.getTransform().transformPoint(e.pageX, e.pageY)); + } + pickCluster(probe: number[]) { return this.childLayoutPairs.map(pair => pair.layout).reduce((cluster, cd) => { const grouping = this.props.Document._useClusters ? NumCast(cd.cluster, -1) : NumCast(cd.group, -1); @@ -435,6 +431,16 @@ export class CollectionFreeFormView extends CollectionSubView { + if (this._hitCluster !== -1) { + !addToSel && SelectionManager.DeselectAll(); + const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.props.Document._useClusters ? NumCast(cd.cluster) : NumCast(cd.group, -1)) === this._hitCluster); + this.selectDocuments(eles); + return true; + } + return false; + } + @action onPointerDown = (e: React.PointerEvent): void => { if (e.nativeEvent.cancelBubble || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) || InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || (Doc.GetSelectedTool() === InkTool.Highlighter || Doc.GetSelectedTool() === InkTool.Pen)) { @@ -774,10 +780,7 @@ export class CollectionFreeFormView extends CollectionSubView { switch (this._pullDirection) { - case "left": - case "right": - case "top": - case "bottom": + case "left": case "right": case "top": case "bottom": CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], { title: "New Collection" }), this._pullDirection); } @@ -868,7 +871,21 @@ export class CollectionFreeFormView extends CollectionSubView { + @action + nudge = (x: number, y: number) => { + if (this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform || + this.props.ContainingCollectionDoc._panX !== undefined) { // bcz: this isn't ideal, but want to try it out... + this.setPan(NumCast(this.layoutDoc._panX) + this.props.PanelWidth() / 2 * x / this.zoomScaling(), + NumCast(this.layoutDoc._panY) + this.props.PanelHeight() / 2 * (-y) / this.zoomScaling(), "transform 500ms", true); + this._nudgeTime = Date.now(); + setTimeout(() => (Date.now() - this._nudgeTime >= 500) && (this.Document._viewTransition = undefined), 500); + return true; + } + return false; + } + + @action + bringToFront = (doc: Doc, sendToBack?: boolean) => { if (sendToBack || StrListCast(doc.layers).includes(StyleLayers.Background)) { doc.zIndex = 0; } else if (doc.isInkMask) { @@ -883,7 +900,7 @@ export class CollectionFreeFormView extends CollectionSubView new Promise(res => setTimeout(async () => res(await endFocus(didMove || didFocus)), Math.max(0, focusSpeed - (Date.now() - startTime)))) }); } } - setPanIntoView = (doc: Doc, xf: Transform, scale?: number) => { + calculatePanIntoView = (doc: Doc, xf: Transform, scale?: number) => { const pw = this.props.PanelWidth() / NumCast(this.layoutDoc._viewScale, 1); const ph = this.props.PanelHeight() / NumCast(this.layoutDoc._viewScale, 1); const pt = xf.transformPoint(NumCast(doc.x), NumCast(doc.y)); @@ -1000,43 +1018,51 @@ export class CollectionFreeFormView extends CollectionSubView this.props.childClickScript || ScriptCast(this.Document.onChildClick); - onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); - parentActive = (outsideReaction: boolean) => this.props.active(outsideReaction) || this.props.parentActive?.(outsideReaction) || this.backgroundActive || this.layoutDoc._viewType === CollectionViewType.Pile ? true : false; - getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps { - return { - addDocument: this.props.addDocument, - removeDocument: this.props.removeDocument, - moveDocument: this.props.moveDocument, - pinToPres: this.props.pinToPres, - whenActiveChanged: this.props.whenActiveChanged, - parentActive: this.parentActive, - docViewPath: this.props.docViewPath, - DataDoc: childData, - Document: childLayout, - ContainingCollectionView: this.props.CollectionView, - ContainingCollectionDoc: this.props.Document, - LayoutTemplate: childLayout.z ? undefined : this.props.childLayoutTemplate, - LayoutTemplateString: childLayout.z ? undefined : this.props.childLayoutString, - rootSelected: childData ? this.rootSelected : returnFalse, - onClick: this.onChildClickHandler, - onDoubleClick: this.onChildDoubleClickHandler, - ScreenToLocalTransform: childLayout.z ? this.getTransformOverlay : this.getTransform, - PanelWidth: childLayout[WidthSym], - PanelHeight: childLayout[HeightSym], - docFilters: this.freeformDocFilters, - docRangeFilters: this.freeformRangeDocFilters, - searchFilterDocs: this.searchFilterDocs, - focus: this.focusDocument, - styleProvider: this.getClusterColor, - layerProvider: this.props.layerProvider, - freezeDimensions: this.props.childFreezeDimensions, - dropAction: StrCast(this.props.Document.childDropAction) as dropActionType, - bringToFront: this.bringToFront, - addDocTab: this.addDocTab, - renderDepth: this.props.renderDepth + 1, - dontRegisterView: this.props.dontRegisterView, - }; + getChildDocView(entry: PoolData) { + const childLayout = entry.pair.layout; + const childData = entry.pair.data; + const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); + return ; } addDocTab = action((doc: Doc, where: string) => { @@ -1075,15 +1101,16 @@ export class CollectionFreeFormView extends CollectionSubView { - return !Array.isArray(views) ? [] : views.filter(ele => this.viewDefToJSX(ele)).map(ele => this.viewDefToJSX(ele)!); - } - onViewDefDivClick = (e: React.MouseEvent, payload: any) => { (this.props.viewDefDivClick || ScriptCast(this.props.Document.onViewDefDivClick))?.script.run({ this: this.props.Document, payload }); e.stopPropagation(); } - private viewDefToJSX(viewDef: ViewDefBounds): Opt { + + viewDefsToJSX = (views: ViewDefBounds[]) => { + return !Array.isArray(views) ? [] : views.filter(ele => this.viewDefToJSX(ele)).map(ele => this.viewDefToJSX(ele)!); + } + + viewDefToJSX(viewDef: ViewDefBounds): Opt { const { x, y, z } = viewDef; const color = StrCast(viewDef.color); const width = Cast(viewDef.width, "number"); @@ -1165,24 +1192,9 @@ export class CollectionFreeFormView extends CollectionSubView this._cachedPool.set(k[0], k[1])); const elements = computedElementData.slice(); - const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); Array.from(newPool.entries()).filter(entry => this.isCurrent(entry[1].pair.layout)).forEach(entry => elements.push({ - ele: , + ele: this.getChildDocView(entry[1]), bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica) })); @@ -1195,8 +1207,6 @@ export class CollectionFreeFormView extends CollectionSubView this._focusFilters || this.docFilters(); - freeformRangeDocFilters = () => this._focusRangeFilters || this.docRangeFilters(); @action setViewSpec = (anchor: Doc, preview: boolean) => { if (preview) { @@ -1226,16 +1236,16 @@ export class CollectionFreeFormView extends CollectionSubView this.fitToContent || force ? this.fitToContentVals : undefined; + @action componentDidMount() { super.componentDidMount?.(); this.props.setContentView?.(this); - this._layoutComputeReaction = reaction(() => this.doLayoutComputation, + this._disposers.layoutComputation = reaction(() => this.doLayoutComputation, (elements) => this._layoutElements = elements || [], { fireImmediately: true, name: "doLayout" }); if (!this.props.isAnnotationOverlay) { - this._boundsReaction = reaction(() => this.contentBounds, + this._disposers.contentBounds = reaction(() => this.contentBounds, bounds => (!this.fitToContent && this._layoutElements?.length) && setTimeout(() => { const rbounds = Cast(this.Document._renderContentBounds, listSpec("number"), [0, 0, 0, 0]); if (rbounds[0] !== bounds.x || rbounds[1] !== bounds.y || rbounds[2] !== bounds.r || rbounds[3] !== bounds.b) { @@ -1248,14 +1258,10 @@ export class CollectionFreeFormView extends CollectionSubView disposer?.()); this._marqueeRef.current?.removeEventListener("dashDragAutoScroll", this.onDragAutoScroll as any); } - @computed get views() { return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); } - elementFunc = () => this._layoutElements; - @action onCursorMove = (e: React.PointerEvent) => { // super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY)); @@ -1281,7 +1287,8 @@ export class CollectionFreeFormView extends CollectionSubView { + @undoBatch + promoteCollection = () => { const childDocs = this.childDocs.slice(); childDocs.forEach(doc => { const scr = this.getTransform().inverse().transformPoint(NumCast(doc.x), NumCast(doc.y)); @@ -1290,10 +1297,10 @@ export class CollectionFreeFormView extends CollectionSubView { + layoutDocsInGrid = () => { const docs = this.childLayoutPairs; const startX = this.Document._panX || 0; let x = startX; @@ -1311,19 +1318,14 @@ export class CollectionFreeFormView extends CollectionSubView { - Doc.toggleNativeDimensions(this.layoutDoc, 1, this.nativeWidth, this.nativeHeight); - } + toggleNativeDimensions = () => Doc.toggleNativeDimensions(this.layoutDoc, 1, this.nativeWidth, this.nativeHeight); @undoBatch @action - toggleLockTransform = (): void => { - this.layoutDoc._lockedTransform = this.layoutDoc._lockedTransform ? undefined : true; - } + toggleLockTransform = () => this.layoutDoc._lockedTransform = this.layoutDoc._lockedTransform ? undefined : true; onContextMenu = (e: React.MouseEvent) => { if (this.props.isAnnotationOverlay || this.props.Document.annotationOn || !ContextMenu.Instance) return; @@ -1430,24 +1432,6 @@ export class CollectionFreeFormView extends CollectionSubView]; } - @computed get placeholder() { - return
- {this.props.Document.title?.toString()} -
; - } - - nudge = action((x: number, y: number) => { - if (this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform || - this.props.ContainingCollectionDoc._panX !== undefined) { // bcz: this isn't ideal, but want to try it out... - this.setPan(NumCast(this.layoutDoc._panX) + this.props.PanelWidth() / 2 * x / this.zoomScaling(), - NumCast(this.layoutDoc._panY) + this.props.PanelHeight() / 2 * (-y) / this.zoomScaling(), "transform 500ms", true); - this._nudgeTime = Date.now(); - setTimeout(() => (Date.now() - this._nudgeTime >= 500) && (this.Document._viewTransition = undefined), 500); - return true; - } - return false; - }); - chooseGridSpace = (gridSpace: number): number => { const divisions = this.props.PanelWidth() / this.zoomScaling() / gridSpace + 3; return divisions < 60 ? gridSpace : this.chooseGridSpace(gridSpace * 10); @@ -1486,14 +1470,10 @@ export class CollectionFreeFormView extends CollectionSubView; } - trySelectCluster = (addToSel: boolean) => { - if (this._hitCluster !== -1) { - !addToSel && SelectionManager.DeselectAll(); - const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.props.Document._useClusters ? NumCast(cd.cluster) : NumCast(cd.group, -1)) === this._hitCluster); - this.selectDocuments(eles); - return true; - } - return false; + @computed get placeholder() { + return
+ {this.props.Document.title?.toString()} +
; } @computed get marqueeView() { @@ -1536,7 +1516,6 @@ export class CollectionFreeFormView extends CollectionSubView {this.Document._freeformLOD && !this.props.active() && !this.props.isAnnotationOverlay && this.props.renderDepth > 0 ? this.placeholder : this.marqueeView} @@ -1667,17 +1646,17 @@ class CollectionFreeFormViewPannableContents extends React.Component +
-
-
-
-
+
+
+
+
; } @@ -1697,16 +1676,13 @@ class CollectionFreeFormViewPannableContents extends React.Component{PresBox.Instance.order}
- + - + - + diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b79c1d474..e31101459 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -378,8 +378,6 @@ export class DocumentViewInternal extends DocComponent (ffview().props.CollectionFreeFormView.ChildDrag = this.props.DocumentView())); const dragData = new DragManager.DocumentDragData([this.props.Document]); const [left, top] = this.props.ScreenToLocalTransform().scale(this.ContentScale).inverse().transformPoint(0, 0); dragData.offset = this.props.ScreenToLocalTransform().scale(this.ContentScale).transformDirection(x - left, y - top); @@ -387,8 +385,10 @@ export class DocumentViewInternal extends DocComponent (ffview.ChildDrag = this.props.DocumentView())); DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: !dropAction && !this.layoutDoc.onDragStart }, - () => setTimeout(action(() => ffview && (ffview().props.CollectionFreeFormView.ChildDrag = undefined)))); // this needs to happen after the drop event is processed. + () => setTimeout(action(() => ffview && (ffview.ChildDrag = undefined)))); // this needs to happen after the drop event is processed. } } diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 4ae436083..ce5b08440 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -25,6 +25,7 @@ import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types"; import { AudioField, ImageField, PdfField, VideoField, WebField } from "./URLField"; import { deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions, updateFunction } from "./util"; import JSZip = require("jszip"); +import { prefix } from "@fortawesome/free-regular-svg-icons"; export namespace Field { export function toKeyValueString(doc: Doc, key: string): string { @@ -230,10 +231,11 @@ export class Doc extends RefField { const sameAuthor = this.author === Doc.CurrentUserEmail; if (set) { for (const key in set) { - if (!key.startsWith("fields.")) { + const fprefix = "fields."; + if (!key.startsWith(fprefix)) { continue; } - const fKey = key.substring(7); + const fKey = key.substring(fprefix.length); const fn = async () => { const value = await SerializationHelper.Deserialize(set[key]); const prev = GetEffectiveAcl(this); @@ -246,9 +248,6 @@ export class Doc extends RefField { if (prev === AclPrivate && GetEffectiveAcl(this) !== AclPrivate) { DocServer.GetRefField(this[Id], true); } - // if (prev !== AclPrivate && GetEffectiveAcl(this) === AclPrivate) { - // this[FieldsSym](true); - // } }; if (sameAuthor || fKey.startsWith("acl") || DocServer.getFieldWriteMode(fKey) !== DocServer.WriteMode.Playground) { delete this[CachedUpdates][fKey]; -- cgit v1.2.3-70-g09d2 From 5a2589c766ace01908a6b151f7170a90f425610c Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 23 Feb 2021 20:42:49 -0500 Subject: fixed pdfs so that if you activate and immediately start selecting text it works. cleaned up some more in collectionFreeFormView by improving layoutDocsInGrid --- src/client/views/MarqueeAnnotator.tsx | 60 +++++++++--------- .../collectionFreeForm/CollectionFreeFormView.tsx | 73 +++++++--------------- .../collections/collectionFreeForm/MarqueeView.tsx | 15 ++--- src/client/views/pdf/PDFViewer.tsx | 4 +- 4 files changed, 61 insertions(+), 91 deletions(-) (limited to 'src') diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index 03afbe7bf..6e8f9a2df 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -58,6 +58,36 @@ export class MarqueeAnnotator extends React.Component { this._height = this._width = 0; document.addEventListener("pointermove", this.onSelectMove); document.addEventListener("pointerup", this.onSelectEnd); + + AnchorMenu.Instance.Highlight = this.highlight; + /** + * This function is used by the AnchorMenu to create an anchor highlight and a new linked text annotation. + * It also initiates a Drag/Drop interaction to place the text annotation. + */ + AnchorMenu.Instance.StartDrag = action(async (e: PointerEvent, ele: HTMLElement) => { + e.preventDefault(); + e.stopPropagation(); + const targetCreator = () => { + const target = CurrentUserUtils.GetNewTextDoc("Note linked to " + this.props.rootDoc.title, 0, 0, 100, 100); + FormattedTextBox.SelectOnLoad = target[Id]; + return target; + }; + const anchorCreator = () => { + const annoDoc = this.highlight("rgba(173, 216, 230, 0.75)"); // hyperlink color + annoDoc.isLinkButton = true; // prevents link button from showing up --- maybe not a good thing? + this.props.addDocument(annoDoc); + return annoDoc; + }; + DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.props.rootDoc, anchorCreator, targetCreator), e.pageX, e.pageY, { + dragComplete: e => { + if (!e.aborted && e.annoDragData && e.annoDragData.annotationDocument && e.annoDragData.dropDocument && !e.linkDocument) { + e.linkDocument = DocUtils.MakeLink({ doc: e.annoDragData.annotationDocument }, { doc: e.annoDragData.dropDocument }, "Annotation"); + e.annoDragData.annotationDocument.isPushpin = e.annoDragData?.dropDocument.annotationOn === this.props.rootDoc; + } + e.linkDocument && e.annoDragData?.linkDropCallback?.(e as { linkDocument: Doc });// bcz: typescript can't figure out that this is valid even though we tested e.linkDocument + } + }); + }); } componentWillUnmount() { document.removeEventListener("pointermove", this.onSelectMove); @@ -154,36 +184,6 @@ export class MarqueeAnnotator extends React.Component { AnchorMenu.Instance.Marquee = { left: this._left, top: this._top, width: this._width, height: this._height }; } - AnchorMenu.Instance.Highlight = this.highlight; - /** - * This function is used by the AnchorMenu to create an anchor highlight and a new linked text annotation. - * It also initiates a Drag/Drop interaction to place the text annotation. - */ - AnchorMenu.Instance.StartDrag = action(async (e: PointerEvent, ele: HTMLElement) => { - e.preventDefault(); - e.stopPropagation(); - const targetCreator = () => { - const target = CurrentUserUtils.GetNewTextDoc("Note linked to " + this.props.rootDoc.title, 0, 0, 100, 100); - FormattedTextBox.SelectOnLoad = target[Id]; - return target; - }; - const anchorCreator = () => { - const annoDoc = this.highlight("rgba(173, 216, 230, 0.75)"); // hyperlink color - annoDoc.isLinkButton = true; // prevents link button from showing up --- maybe not a good thing? - this.props.addDocument(annoDoc); - return annoDoc; - }; - DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.props.rootDoc, anchorCreator, targetCreator), e.pageX, e.pageY, { - dragComplete: e => { - if (!e.aborted && e.annoDragData && e.annoDragData.annotationDocument && e.annoDragData.dropDocument && !e.linkDocument) { - e.linkDocument = DocUtils.MakeLink({ doc: e.annoDragData.annotationDocument }, { doc: e.annoDragData.dropDocument }, "Annotation"); - e.annoDragData.annotationDocument.isPushpin = e.annoDragData?.dropDocument.annotationOn === this.props.rootDoc; - } - e.linkDocument && e.annoDragData?.linkDropCallback?.(e as { linkDocument: Doc });// bcz: typescript can't figure out that this is valid even though we tested e.linkDocument - } - }); - }); - if (this._width > 10 || this._height > 10) { // configure and show the annotation/link menu if a the drag region is big enough const marquees = this.props.mainCont.getElementsByClassName("marqueeAnnotator-dragBox"); if (marquees?.length) { // copy the temporary marquee to allow for multiple selections (not currently available though). diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 9041d9b21..d9cd4fd4e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -175,9 +175,10 @@ export class CollectionFreeFormView extends CollectionSubView { let retVal = false; if (newBox instanceof Doc) { - retVal = this.props.addDocument?.(newBox) || false; - retVal && this.bringToFront(newBox); - retVal && this.updateCluster(newBox); + if (retVal = this.props.addDocument?.(newBox) || false) { + this.bringToFront(newBox); + this.updateCluster(newBox); + } } else { retVal = this.props.addDocument?.(newBox) || false; // bcz: deal with clusters @@ -267,11 +268,9 @@ export class CollectionFreeFormView extends CollectionSubView { + if (this.props.Document._isGroup) return; // groups don't pan when dragged -- instead let the event go through to allow the group itself to drag + if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) return; if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) { - if (this.props.active(true)) { - e.stopPropagation(); - } - return; - } - if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { - return; - } - if (!e.cancelBubble) { - if (this.props.Document._isGroup) return; // groups don't pan when dragged -- instead let the event go through to allow the group itself to drag + if (this.props.active(true)) e.stopPropagation(); + } else if (!e.cancelBubble) { if (Doc.GetSelectedTool() === InkTool.None) { if (this.tryDragCluster(e, this._hitCluster)) { - e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers - e.preventDefault(); document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); - return; } - (!MarqueeView.DragMarquee || e.altKey) && this.pan(e); + else this.pan(e); } e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers e.preventDefault(); @@ -821,18 +811,10 @@ export class CollectionFreeFormView extends CollectionSubView { - const docs = this.childLayoutPairs; - const startX = this.Document._panX || 0; - let x = startX; - let y = this.Document._panY || 0; - let i = 0; - const width = Math.max(...docs.map(doc => NumCast(doc.layout._width))); - const height = Math.max(...docs.map(doc => NumCast(doc.layout._height))); - docs.forEach(pair => { - pair.layout.x = x; - pair.layout.y = y; - x += width + 20; - if (++i === 6) { - i = 0; - x = startX; - y += height + 20; - } + const docs = this.childLayoutPairs.map(pair => pair.layout); + const width = Math.max(...docs.map(doc => NumCast(doc._width))) + 20; + const height = Math.max(...docs.map(doc => NumCast(doc._height))) + 20; + const dim = Math.ceil(Math.sqrt(docs.length)); + docs.forEach((doc, i) => { + doc.x = (this.Document._panX || 0) + (i % dim) * width - width * dim / 2; + doc.y = (this.Document._panY || 0) + Math.floor(i / dim) * height - height * dim / 2; }); } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 4008a20b3..e61cf83bb 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -46,7 +46,6 @@ interface MarqueeViewProps { export class MarqueeView extends React.Component { private _commandExecuted = false; - @observable public static DragMarquee = false; @observable _lastX: number = 0; @observable _lastY: number = 0; @observable _downX: number = 0; @@ -220,8 +219,8 @@ export class MarqueeView extends React.Component e.preventDefault()} onScroll={(e) => e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}> diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 7687690b2..ca6dc87ae 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -385,10 +385,12 @@ export class PDFViewer extends ViewBoxAnnotatableComponent this._marqueeing = undefined), 100); // bcz: hack .. anchor menu is setup within MarqueeAnnotator so we need to at least create the marqueeAnnotator even though we aren't using it. // clear out old marquees and initialize menu for new selection AnchorMenu.Instance.Status = "marquee"; this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove())); -- cgit v1.2.3-70-g09d2 From 953e9dacf886aa5dff7331ca1f7ba7ba7f5373dd Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 23 Feb 2021 21:46:57 -0500 Subject: cleaned up viewTransitions in CollectionFreeFormView to not write to document for transient effects. --- src/client/views/Touchable.tsx | 39 ++-------- .../collectionFreeForm/CollectionFreeFormView.tsx | 88 ++++++++++------------ .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- 3 files changed, 47 insertions(+), 82 deletions(-) (limited to 'src') diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx index bb9e108cb..789756a78 100644 --- a/src/client/views/Touchable.tsx +++ b/src/client/views/Touchable.tsx @@ -11,7 +11,6 @@ export abstract class Touchable extends React.Component { private holdMoveDisposer?: InteractionUtils.MultiTouchEventDisposer; private holdEndDisposer?: InteractionUtils.MultiTouchEventDisposer; - protected abstract _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; protected _touchDrag: boolean = false; protected prevPoints: Map = new Map(); @@ -86,19 +85,13 @@ export abstract class Touchable extends React.Component { if (!InteractionUtils.IsDragging(this.prevPoints, myTouches, 5) && !this._touchDrag) return; this._touchDrag = true; switch (myTouches.length) { - case 1: - this.handle1PointerMove(te, me); - break; - case 2: - this.handle2PointersMove(te, me); - break; + case 1: this.handle1PointerMove(te, me); break; + case 2: this.handle2PointersMove(te, me); break; } for (const pt of me.touches) { - if (pt) { - if (this.prevPoints.has(pt.identifier)) { - this.prevPoints.set(pt.identifier, pt); - } + if (pt && this.prevPoints.has(pt.identifier)) { + this.prevPoints.set(pt.identifier, pt); } } } @@ -166,7 +159,6 @@ export abstract class Touchable extends React.Component { this.removeHoldEndListeners(); this.addHoldMoveListeners(); this.addHoldEndListeners(); - } addMoveListeners = () => { @@ -174,21 +166,12 @@ export abstract class Touchable extends React.Component { document.addEventListener("dashOnTouchMove", handler); this.moveDisposer = () => document.removeEventListener("dashOnTouchMove", handler); } - - removeMoveListeners = () => { - this.moveDisposer && this.moveDisposer(); - } - addEndListeners = () => { const handler = (e: Event) => this.onTouchEnd(e, (e as CustomEvent>).detail); document.addEventListener("dashOnTouchEnd", handler); this.endDisposer = () => document.removeEventListener("dashOnTouchEnd", handler); } - removeEndListeners = () => { - this.endDisposer && this.endDisposer(); - } - addHoldMoveListeners = () => { const handler = (e: Event) => this.handle1PointerHoldMove(e, (e as CustomEvent>).detail); document.addEventListener("dashOnTouchHoldMove", handler); @@ -201,21 +184,16 @@ export abstract class Touchable extends React.Component { this.holdEndDisposer = () => document.removeEventListener("dashOnTouchHoldEnd", handler); } - removeHoldMoveListeners = () => { - this.holdMoveDisposer && this.holdMoveDisposer(); - } - - removeHoldEndListeners = () => { - this.holdEndDisposer && this.holdEndDisposer(); - } - + removeMoveListeners = () => this.moveDisposer?.(); + removeEndListeners = () => this.endDisposer?.(); + removeHoldMoveListeners = () => this.holdMoveDisposer?.(); + removeHoldEndListeners = () => this.holdEndDisposer?.(); handle1PointerHoldMove = (e: Event, me: InteractionUtils.MultiTouchEvent): void => { // e.stopPropagation(); // me.touchEvent.stopPropagation(); } - handle1PointerHoldEnd = (e: Event, me: InteractionUtils.MultiTouchEvent): void => { e.stopPropagation(); me.touchEvent.stopPropagation(); @@ -226,7 +204,6 @@ export abstract class Touchable extends React.Component { me.touchEvent.preventDefault(); } - handleHandDown = (e: React.TouchEvent) => { // e.stopPropagation(); // e.preventDefault(); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d9cd4fd4e..9fa5b8670 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -81,6 +81,7 @@ export type collectionFreeformViewProps = { export class CollectionFreeFormView extends CollectionSubView>(PanZoomDocument) { public get displayName() { return "CollectionFreeFormView(" + this.props.Document.title?.toString() + ")"; } // this makes mobx trace() statements more descriptive + private _lastNudge: any; private _lastX: number = 0; private _lastY: number = 0; private _downX: number = 0; @@ -95,13 +96,13 @@ export class CollectionFreeFormView extends CollectionSubView(); private _cachedPool: Map = new Map(); private _lastTap = 0; - private _nudgeTime = 0; private get isAnnotationOverlay() { return this.props.isAnnotationOverlay; } private get scaleFieldKey() { return this.props.scaleField || "_viewScale"; } private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; } @observable.shallow _layoutElements: ViewDefResult[] = []; // shallow because some layout items (eg pivot labels) are just generated 'divs' and can't be frozen as observables + @observable _viewTransition: number = 0; // sets the pan/zoom transform ease time- used by nudge(), focus() etc to smoothly zoom/pan. set to 0 to use document's transition time or default of 0 @observable _hLines: number[] | undefined; @observable _vLines: number[] | undefined; @observable _pullCoords: number[] = [0, 0]; @@ -324,11 +325,10 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).filter(cd => (this.props.Document._useClusters ? NumCast(cd.cluster) : NumCast(cd.group, -1)) === cluster); const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.props.CollectionView)!); - const de = new DragManager.DocumentDragData(eles); - de.moveDocument = this.props.moveDocument; const { left, top } = clusterDocs[0].getBounds() || { left: 0, top: 0 }; + const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? "alias" : undefined); + de.moveDocument = this.props.moveDocument; de.offset = this.getTransform().transformDirection(ptsParent.clientX - left, ptsParent.clientY - top); - de.dropAction = e.ctrlKey || e.altKey ? "alias" : undefined; DragManager.StartDocumentDrag(clusterDocs.map(v => v.ContentDiv!), de, ptsParent.clientX, ptsParent.clientY, { hideSource: !de.dropAction }); return true; } @@ -423,8 +423,8 @@ export class CollectionFreeFormView extends CollectionSubView s.backgroundColor); // override the cluster color with an explicitly set color on a non-background document. then override that with an explicitly set color on a background document - set && set.filter(s => !StrListCast(s.layers).includes(StyleLayers.Background)).map(s => styleProp = StrCast(s.backgroundColor)); - set && set.filter(s => StrListCast(s.layers).includes(StyleLayers.Background)).map(s => styleProp = StrCast(s.backgroundColor)); + set?.filter(s => !StrListCast(s.layers).includes(StyleLayers.Background)).map(s => styleProp = StrCast(s.backgroundColor)); + set?.filter(s => StrListCast(s.layers).includes(StyleLayers.Background)).map(s => styleProp = StrCast(s.backgroundColor)); } } //else if (doc && NumCast(doc.group, -1) !== -1) styleProp = "gray"; return styleProp; @@ -612,14 +612,10 @@ export class CollectionFreeFormView extends CollectionSubView { if ((Math.abs(e.pageX - this._downX) < 3 && Math.abs(e.pageY - this._downY) < 3)) { - if (Date.now() - this._lastTap < 300) { // reset zoom of freeform view to 1-to-1 on a double click - if (e.shiftKey) { - if (this.layoutDoc.targetScale) { - this.scaleAtPt(this.getTransform().transformPoint(e.clientX, e.clientY), 1); - } - e.stopPropagation(); - e.preventDefault(); - } + if (e.shiftKey && Date.now() - this._lastTap < 300) { // reset zoom of freeform view to 1-to-1 on a shift + double click + this.layoutDoc.targetScale && this.zoomSmoothlyAboutPt(this.getTransform().transformPoint(e.clientX, e.clientY), 1); + e.stopPropagation(); + e.preventDefault(); } this._lastTap = Date.now(); } @@ -628,7 +624,7 @@ export class CollectionFreeFormView extends CollectionSubView { const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); - this.setPan((this.Document._panX || 0) - dx, (this.Document._panY || 0) - dy, undefined, true); + this.setPan((this.Document._panX || 0) - dx, (this.Document._panY || 0) - dy, 0, true); this._lastX = e.clientX; this._lastY = e.clientY; } @@ -655,8 +651,7 @@ export class CollectionFreeFormView extends CollectionSubView) => { if (!e.cancelBubble) { const myTouches = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true); - const pt = myTouches[0]; - if (pt) { + if (myTouches[0]) { if (Doc.GetSelectedTool() === InkTool.None) { if (this.tryDragCluster(e, this._hitCluster)) { e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers @@ -665,7 +660,7 @@ export class CollectionFreeFormView extends CollectionSubView= 0.15 || localTransform.Scale > this.zoomScaling()) { const safeScale = Math.min(Math.max(0.15, localTransform.Scale), 20); this.props.Document[this.scaleFieldKey] = Math.abs(safeScale); @@ -820,7 +815,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout instanceof Doc).map(pair => pair.layout); @@ -844,7 +839,7 @@ export class CollectionFreeFormView extends CollectionSubView { + nudge = (x: number, y: number, nudgeTime: number = 500) => { if (this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform || this.props.ContainingCollectionDoc._panX !== undefined) { // bcz: this isn't ideal, but want to try it out... this.setPan(NumCast(this.layoutDoc._panX) + this.props.PanelWidth() / 2 * x / this.zoomScaling(), - NumCast(this.layoutDoc._panY) + this.props.PanelHeight() / 2 * (-y) / this.zoomScaling(), "transform 500ms", true); - this._nudgeTime = Date.now(); - setTimeout(() => (Date.now() - this._nudgeTime >= 500) && (this.Document._viewTransition = undefined), 500); + NumCast(this.layoutDoc._panY) + this.props.PanelHeight() / 2 * (-y) / this.zoomScaling(), nudgeTime, true); + this._lastNudge && clearTimeout(this._lastNudge); + this._lastNudge = setTimeout(action(() => this._viewTransition = 0), nudgeTime); return true; } return false; @@ -884,10 +879,11 @@ export class CollectionFreeFormView extends CollectionSubView this._viewTransition = 0), this._viewTransition = transitionTime); // set transition to be smooth, then reset const screenXY = this.getTransform().inverse().transformPoint(docpt[0], docpt[1]); - this.Document._viewTransition = "transform 500ms"; this.layoutDoc[this.scaleFieldKey] = scale; const newScreenXY = this.getTransform().inverse().transformPoint(docpt[0], docpt[1]); const scrDelta = { x: screenXY[0] - newScreenXY[0], y: screenXY[1] - newScreenXY[1] }; @@ -919,7 +915,7 @@ export class CollectionFreeFormView extends CollectionSubView this._viewTransition = 0); } return resetView; }; @@ -979,25 +975,24 @@ export class CollectionFreeFormView extends CollectionSubView { if (where === "inParent") { - if (doc instanceof Doc) { + ((doc instanceof Doc) ? [doc] : doc).forEach(doc => { const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y)); doc.x = pt[0]; doc.y = pt[1]; - return this.props.addDocument?.(doc) || false; - } else { - (doc as any as Doc[]).forEach(doc => { - const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y)); - doc.x = pt[0]; - doc.y = pt[1]; - }); - return this.props.addDocument?.(doc) || false; - } + }); + return this.props.addDocument?.(doc) || false; } if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { this.dataDoc[this.props.fieldKey] = doc instanceof Doc ? doc : new List(doc as any as Doc[]); @@ -1072,10 +1060,10 @@ export class CollectionFreeFormView extends CollectionSubView {this.children} diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index e61cf83bb..9e442a8c8 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -38,7 +38,7 @@ interface MarqueeViewProps { addLiveTextDocument: (doc: Doc) => void; isSelected: () => boolean; trySelectCluster: (addToSel: boolean) => boolean; - nudge?: (x: number, y: number) => boolean; + nudge?: (x: number, y: number, nudgeTime?: number) => boolean; ungroup?: () => void; setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void; } -- cgit v1.2.3-70-g09d2 From 2cddc1cd6012a1c71c919124f640ce1d04593ec8 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 23 Feb 2021 22:36:52 -0500 Subject: removed _renderContentBounds and updated miniMap view. --- src/client/views/collections/TabDocView.tsx | 186 ++++++++++++--------- .../collectionFreeForm/CollectionFreeFormView.tsx | 10 +- src/client/views/nodes/DocumentView.tsx | 2 +- 3 files changed, 105 insertions(+), 93 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index c1a1a6f04..c7eb9ef48 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -9,7 +9,6 @@ import * as ReactDOM from 'react-dom'; import { DataSym, Doc, DocListCast, DocListCastAsync, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; import { Id } from '../../../fields/FieldSymbols'; import { FieldId } from "../../../fields/RefField"; -import { listSpec } from '../../../fields/Schema'; import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { TraceMobx } from '../../../fields/util'; import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, Utils } from "../../../Utils"; @@ -55,13 +54,7 @@ export class TabDocView extends React.Component { @computed get layoutDoc() { return this._document && Doc.Layout(this._document); } @computed get tabColor() { return StrCast(this._document?._backgroundColor, StrCast(this._document?.backgroundColor, DefaultStyleProvider(this._document, undefined, StyleProp.BackgroundColor))); } - @computed get renderBounds() { - const bounds = this._document ? Cast(this._document._renderContentBounds, listSpec("number"), [0, 0, this.returnMiniSize(), this.returnMiniSize()]) : [0, 0, 0, 0]; - const xbounds = bounds[2] - bounds[0]; - const ybounds = bounds[3] - bounds[1]; - const dim = Math.max(xbounds, ybounds); - return { l: bounds[0] + xbounds / 2 - dim / 2, t: bounds[1] + ybounds / 2 - dim / 2, cx: bounds[0] + xbounds / 2, cy: bounds[1] + ybounds / 2, dim }; - } + get stack() { return (this.props as any).glContainer.parent.parent; } get tab() { return (this.props as any).glContainer.tab; } @@ -290,76 +283,9 @@ export class TabDocView extends React.Component { } } - childLayoutTemplate = () => Cast(this._document?.childLayoutTemplate, Doc, null); - returnMiniSize = () => NumCast(this._document?._miniMapSize, 150); - miniDown = (e: React.PointerEvent) => { - const doc = this._document; - const miniSize = this.returnMiniSize(); - doc && setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - doc._panX = clamp(NumCast(doc._panX) + delta[0] / miniSize * this.renderBounds.dim, this.renderBounds.l, this.renderBounds.l + this.renderBounds.dim); - doc._panY = clamp(NumCast(doc._panY) + delta[1] / miniSize * this.renderBounds.dim, this.renderBounds.t, this.renderBounds.t + this.renderBounds.dim); - return false; - }), emptyFunction, emptyFunction); - } getCurrentFrame = () => { return NumCast(Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex].presentationTargetDoc, Doc, null)._currentFrame); } - renderMiniMap() { - const miniWidth = this.PanelWidth() / NumCast(this._document?._viewScale, 1) / this.renderBounds.dim * 100; - const miniHeight = this.PanelHeight() / NumCast(this._document?._viewScale, 1) / this.renderBounds.dim * 100; - const miniLeft = 50 + (NumCast(this._document?._panX) - this.renderBounds.cx) / this.renderBounds.dim * 100 - miniWidth / 2; - const miniTop = 50 + (NumCast(this._document?._panY) - this.renderBounds.cy) / this.renderBounds.dim * 100 - miniHeight / 2; - const miniSize = this.returnMiniSize(); - return <> -
- -
-
-
-
- - {"toggle minimap"}
}> -
e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} - style={{ background: DefaultStyleProvider(this._document, undefined, StyleProp.BackgroundColor) }} > - -
- - ; - } @action focusFunc = (doc: Doc, options?: DocFocusOptions) => { const vals = (!options?.originalTarget || options?.originalTarget === this._document) && this.view?.ComponentView?.freeformData?.(true); @@ -402,6 +328,10 @@ export class TabDocView extends React.Component { } } } + miniMapColor = () => this.tabColor; + miniPanelWidth = () => this.PanelWidth(); + miniPanelHeight = () => this.PanelHeight(); + tabView = () => this._view; @computed get layerProvider() { return this._document && DefaultLayerProvider(this._document); } @computed get docView() { TraceMobx(); @@ -431,14 +361,18 @@ export class TabDocView extends React.Component { docViewPath={returnEmptyDoclist} bringToFront={emptyFunction} pinToPres={TabDocView.PinDoc} /> - {this._document._viewType !== CollectionViewType.Freeform ? (null) : - <>{this._document.hideMinimap ? (null) : this.renderMiniMap()} - {"toggle minimap"}
}> -
e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} > - -
- - } + + {"toggle minimap"}
}> +
e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} > + +
+ ; } @@ -454,4 +388,90 @@ export class TabDocView extends React.Component {
); } +} + +interface TabMinimapViewProps { + document: Doc; + tabView: () => DocumentView | undefined; + addDocTab: (doc: Doc, where: string) => boolean; + PanelWidth: () => number; + PanelHeight: () => number; + background: () => string; +} +@observer +export class TabMinimapView extends React.Component { + @computed get renderBounds() { + const bounds = this.props.tabView()?.ComponentView?.freeformData?.()?.bounds ?? { x: 0, y: 0, r: this.returnMiniSize(), b: this.returnMiniSize() }; + const xbounds = bounds.r - bounds.x; + const ybounds = bounds.b - bounds.y; + const dim = Math.max(xbounds, ybounds); + return { l: bounds.x + xbounds / 2 - dim / 2, t: bounds.y + ybounds / 2 - dim / 2, cx: bounds.x + xbounds / 2, cy: bounds.y + ybounds / 2, dim }; + } + childLayoutTemplate = () => Cast(this.props.document.childLayoutTemplate, Doc, null); + returnMiniSize = () => NumCast(this.props.document._miniMapSize, 150); + miniDown = (e: React.PointerEvent) => { + const doc = this.props.document; + const miniSize = this.returnMiniSize(); + doc && setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { + doc._panX = clamp(NumCast(doc._panX) + delta[0] / miniSize * this.renderBounds.dim, this.renderBounds.l, this.renderBounds.l + this.renderBounds.dim); + doc._panY = clamp(NumCast(doc._panY) + delta[1] / miniSize * this.renderBounds.dim, this.renderBounds.t, this.renderBounds.t + this.renderBounds.dim); + return false; + }), emptyFunction, emptyFunction); + } + render() { + const miniWidth = this.props.PanelWidth() / NumCast(this.props.document._viewScale, 1) / this.renderBounds.dim * 100; + const miniHeight = this.props.PanelHeight() / NumCast(this.props.document._viewScale, 1) / this.renderBounds.dim * 100; + const miniLeft = 50 + (NumCast(this.props.document._panX) - this.renderBounds.cx) / this.renderBounds.dim * 100 - miniWidth / 2; + const miniTop = 50 + (NumCast(this.props.document._panY) - this.renderBounds.cy) / this.renderBounds.dim * 100 - miniHeight / 2; + const miniSize = this.returnMiniSize(); + return this.props.document._viewType !== CollectionViewType.Freeform || this.props.document.hideMinimap ? (null) : <> +
+ +
+
+
+
+ + {"toggle minimap"}
}> +
e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this.props.document.hideMinimap = !this.props.document.hideMinimap; })} + style={{ background: DefaultStyleProvider(this.props.document, undefined, StyleProp.BackgroundColor) }} > + +
+ + ; + } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 9fa5b8670..ba89579cd 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -120,6 +120,7 @@ export class CollectionFreeFormView extends CollectionSubView this.doLayoutComputation, (elements) => this._layoutElements = elements || [], { fireImmediately: true, name: "doLayout" }); - if (!this.props.isAnnotationOverlay) { - this._disposers.contentBounds = reaction(() => this.contentBounds, - bounds => (!this.fitToContent && this._layoutElements?.length) && setTimeout(() => { - const rbounds = Cast(this.Document._renderContentBounds, listSpec("number"), [0, 0, 0, 0]); - if (rbounds[0] !== bounds.x || rbounds[1] !== bounds.y || rbounds[2] !== bounds.r || rbounds[3] !== bounds.b) { - this.Document._renderContentBounds = new List([bounds.x, bounds.y, bounds.r, bounds.b]); - } - })); - } this._marqueeRef.current?.addEventListener("dashDragAutoScroll", this.onDragAutoScroll as any); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e31101459..5dfb3e99b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -83,7 +83,7 @@ export interface DocComponentView { forward?: () => boolean; url?: () => string; submitURL?: (url: string) => boolean; - freeformData?: (force?: boolean) => Opt<{ panX: number, panY: number, scale: number }>; + freeformData?: (force?: boolean) => Opt<{ panX: number, panY: number, scale: number, bounds: { x: number, y: number, r: number, b: number } }>; } export interface DocumentViewSharedProps { renderDepth: number; -- cgit v1.2.3-70-g09d2 From 69fe731b5de047684dc31deff84590de34bba0b5 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 23 Feb 2021 22:56:24 -0500 Subject: minimap cleanup --- src/client/views/collections/TabDocView.tsx | 65 +++++++++++------------------ 1 file changed, 24 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index c7eb9ef48..9ddc13644 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -45,17 +45,15 @@ export class TabDocView extends React.Component { _mainCont: HTMLDivElement | null = null; _tabReaction: IReactionDisposer | undefined; @observable _activated: boolean = false; - - @observable private _panelWidth = 0; - @observable private _panelHeight = 0; - @observable private _isActive: boolean = false; - @observable private _document: Doc | undefined; - @observable private _view: DocumentView | undefined; + @observable _panelWidth = 0; + @observable _panelHeight = 0; + @observable _isActive: boolean = false; + @observable _document: Doc | undefined; + @observable _view: DocumentView | undefined; @computed get layoutDoc() { return this._document && Doc.Layout(this._document); } @computed get tabColor() { return StrCast(this._document?._backgroundColor, StrCast(this._document?.backgroundColor, DefaultStyleProvider(this._document, undefined, StyleProp.BackgroundColor))); } - get stack() { return (this.props as any).glContainer.parent.parent; } get tab() { return (this.props as any).glContainer.tab; } get view() { return this._view; } @@ -214,19 +212,6 @@ export class TabDocView extends React.Component { } } - /** - * Adds a document to the presentation view - **/ - @undoBatch - @action - public static UnpinDoc(doc: Doc) { - const curPres = CurrentUserUtils.ActivePresentation; - if (curPres) { - const ind = DocListCast(curPres.data).findIndex((val) => Doc.AreProtosEqual(val, doc)); - ind !== -1 && Doc.RemoveDocFromList(curPres, "data", DocListCast(curPres.data)[ind]); - } - } - componentDidMount() { const selected = () => SelectionManager.Views().some(v => v.props.Document === this._document); new _global.ResizeObserver(action((entries: any) => { @@ -313,25 +298,9 @@ export class TabDocView extends React.Component { } PanelWidth = () => this._panelWidth; PanelHeight = () => this._panelHeight; - - static miniStyleProvider = (doc: Opt, props: Opt, property: string): any => { - if (doc) { - switch (property.split(":")[0]) { - default: return DefaultStyleProvider(doc, props, property); - case StyleProp.PointerEvents: return "none"; - case StyleProp.DocContents: - const background = doc.type === DocumentType.PDF ? "red" : doc.type === DocumentType.IMG ? "blue" : doc.type === DocumentType.RTF ? "orange" : - doc.type === DocumentType.VID ? "purple" : doc.type === DocumentType.WEB ? "yellow" : "gray"; - return doc.type === DocumentType.COL ? - undefined : -
; - } - } - } miniMapColor = () => this.tabColor; - miniPanelWidth = () => this.PanelWidth(); - miniPanelHeight = () => this.PanelHeight(); tabView = () => this._view; + @computed get layerProvider() { return this._document && DefaultLayerProvider(this._document); } @computed get docView() { TraceMobx(); @@ -363,8 +332,8 @@ export class TabDocView extends React.Component { pinToPres={TabDocView.PinDoc} /> @@ -400,6 +369,20 @@ interface TabMinimapViewProps { } @observer export class TabMinimapView extends React.Component { + static miniStyleProvider = (doc: Opt, props: Opt, property: string): any => { + if (doc) { + switch (property.split(":")[0]) { + default: return DefaultStyleProvider(doc, props, property); + case StyleProp.PointerEvents: return "none"; + case StyleProp.DocContents: + const background = doc.type === DocumentType.PDF ? "red" : doc.type === DocumentType.IMG ? "blue" : doc.type === DocumentType.RTF ? "orange" : + doc.type === DocumentType.VID ? "purple" : doc.type === DocumentType.WEB ? "yellow" : "gray"; + return doc.type === DocumentType.COL ? + undefined : +
; + } + } + } @computed get renderBounds() { const bounds = this.props.tabView()?.ComponentView?.freeformData?.()?.bounds ?? { x: 0, y: 0, r: this.returnMiniSize(), b: this.returnMiniSize() }; const xbounds = bounds.r - bounds.x; @@ -424,7 +407,7 @@ export class TabMinimapView extends React.Component { const miniLeft = 50 + (NumCast(this.props.document._panX) - this.renderBounds.cx) / this.renderBounds.dim * 100 - miniWidth / 2; const miniTop = 50 + (NumCast(this.props.document._panY) - this.renderBounds.cy) / this.renderBounds.dim * 100 - miniHeight / 2; const miniSize = this.returnMiniSize(); - return this.props.document._viewType !== CollectionViewType.Freeform || this.props.document.hideMinimap ? (null) : <> + return this.props.document.type !== DocumentType.COL || this.props.document._viewType !== CollectionViewType.Freeform || this.props.document.hideMinimap ? (null) : <>
{ renderDepth={0} whenActiveChanged={emptyFunction} focus={DocUtils.DefaultFocus} - styleProvider={TabDocView.miniStyleProvider} + styleProvider={TabMinimapView.miniStyleProvider} layerProvider={undefined} addDocTab={this.props.addDocTab} pinToPres={TabDocView.PinDoc} -- cgit v1.2.3-70-g09d2 From 667e0a8cfc12a86e953f0382a36254ff9afbdcf3 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 23 Feb 2021 23:24:30 -0500 Subject: fixes for toggling minimap icon display/behavior. --- src/client/views/collections/TabDocView.tsx | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 9ddc13644..80ddf2f48 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -337,7 +337,7 @@ export class TabDocView extends React.Component { background={this.miniMapColor} document={this._document} tabView={this.tabView} /> - {"toggle minimap"}
}> + {"toggle minimap"}
}>
e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} >
@@ -384,7 +384,8 @@ export class TabMinimapView extends React.Component { } } @computed get renderBounds() { - const bounds = this.props.tabView()?.ComponentView?.freeformData?.()?.bounds ?? { x: 0, y: 0, r: this.returnMiniSize(), b: this.returnMiniSize() }; + const bounds = this.props.tabView()?.ComponentView?.freeformData?.(true)?.bounds; + if (!bounds) return undefined; const xbounds = bounds.r - bounds.x; const ybounds = bounds.b - bounds.y; const dim = Math.max(xbounds, ybounds); @@ -394,20 +395,22 @@ export class TabMinimapView extends React.Component { returnMiniSize = () => NumCast(this.props.document._miniMapSize, 150); miniDown = (e: React.PointerEvent) => { const doc = this.props.document; + const renderBounds = this.renderBounds ?? { l: 0, r: 0, t: 0, b: 0, dim: 1 }; const miniSize = this.returnMiniSize(); doc && setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - doc._panX = clamp(NumCast(doc._panX) + delta[0] / miniSize * this.renderBounds.dim, this.renderBounds.l, this.renderBounds.l + this.renderBounds.dim); - doc._panY = clamp(NumCast(doc._panY) + delta[1] / miniSize * this.renderBounds.dim, this.renderBounds.t, this.renderBounds.t + this.renderBounds.dim); + doc._panX = clamp(NumCast(doc._panX) + delta[0] / miniSize * renderBounds.dim, renderBounds.l, renderBounds.l + renderBounds.dim); + doc._panY = clamp(NumCast(doc._panY) + delta[1] / miniSize * renderBounds.dim, renderBounds.t, renderBounds.t + renderBounds.dim); return false; }), emptyFunction, emptyFunction); } render() { + if (!this.renderBounds) return (null); const miniWidth = this.props.PanelWidth() / NumCast(this.props.document._viewScale, 1) / this.renderBounds.dim * 100; const miniHeight = this.props.PanelHeight() / NumCast(this.props.document._viewScale, 1) / this.renderBounds.dim * 100; const miniLeft = 50 + (NumCast(this.props.document._panX) - this.renderBounds.cx) / this.renderBounds.dim * 100 - miniWidth / 2; const miniTop = 50 + (NumCast(this.props.document._panY) - this.renderBounds.cy) / this.renderBounds.dim * 100 - miniHeight / 2; const miniSize = this.returnMiniSize(); - return this.props.document.type !== DocumentType.COL || this.props.document._viewType !== CollectionViewType.Freeform || this.props.document.hideMinimap ? (null) : <> + return this.props.document.hideMinimap ? (null) :
{
-
- - {"toggle minimap"}
}> -
e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this.props.document.hideMinimap = !this.props.document.hideMinimap; })} - style={{ background: DefaultStyleProvider(this.props.document, undefined, StyleProp.BackgroundColor) }} > - -
- - ; +
; } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 477fa6b85e24046edbebc44b49aba8c286558cd0 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 24 Feb 2021 10:45:37 -0500 Subject: fixed carouself view which wasn't displaying vertically oriented documents. cleaned up collectionTime script to not capture variables (causing doc's to be create) --- src/client/views/collections/CollectionCarousel3DView.scss | 1 - src/client/views/collections/CollectionCarousel3DView.tsx | 10 +++++----- src/client/views/collections/CollectionTimeView.tsx | 5 ++--- .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 4 +--- 5 files changed, 9 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionCarousel3DView.scss b/src/client/views/collections/CollectionCarousel3DView.scss index 652293ed6..5c8b491eb 100644 --- a/src/client/views/collections/CollectionCarousel3DView.scss +++ b/src/client/views/collections/CollectionCarousel3DView.scss @@ -9,7 +9,6 @@ position: absolute; top: 15%; height: 60%; - width: 100%; align-items: center; transition: transform 0.3s cubic-bezier(0.455, 0.03, 0.515, 0.955); diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 9b1e3b80d..c5a05da00 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -40,7 +40,7 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume @computed get content() { const currentIndex = NumCast(this.layoutDoc._itemIndex); const displayDoc = (childPair: { layout: Doc, data: Doc }) => { - const script = ScriptField.MakeScript("child._showCaption = 'caption'", { child: Doc.name }, { child: childPair.layout }); + const script = ScriptField.MakeScript("this._showCaption = 'caption'", { this: Doc.name }); const onChildClick = script && (() => script); return + { opacity: '1', transform: 'scale(1.3)', width: this.panelWidth() } : + { opacity: '0.5', transform: 'scale(0.6)', userSelect: 'none', width: this.panelWidth() }}> {displayDoc(childPair)}
); })); @@ -166,10 +166,10 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume render() { const index = NumCast(this.layoutDoc._itemIndex); - const translateX = 33 * (1 - index); + const translateX = this.panelWidth() * (1 - index); return
-
+
{this.content}
{this.props.Document._chromeStatus !== "replaced" ? this.buttons : (null)} diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 857d5e1d7..1f6322997 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -62,11 +62,10 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { async componentDidMount() { this.props.setContentView?.(this); - const detailView = (await DocCastAsync(this.props.Document.childClickedOpenTemplateView)) || DocUtils.findTemplate("detailView", StrCast(this.rootDoc.type), ""); + //const detailView = (await DocCastAsync(this.props.Document.childClickedOpenTemplateView)) || DocUtils.findTemplate("detailView", StrCast(this.rootDoc.type), ""); ///const childText = "const alias = getAlias(self); switchView(alias, detailView); alias.dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; - const childText = "openInLightbox(self, shiftKey); "; runInAction(() => { - this._childClickedScript = ScriptField.MakeScript(childText, { this: Doc.name, shiftKey: "boolean" }, { detailView: detailView! }); + this._childClickedScript = ScriptField.MakeScript("openInLightbox(self, shiftKey)", { this: Doc.name, shiftKey: "boolean" });//, { detailView: detailView! }); this._viewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" }); }); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ba89579cd..96ef7af01 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1199,7 +1199,7 @@ export class CollectionFreeFormView extends CollectionSubView([]); + proto.docFilters = ObjectField.MakeCopy(this.layoutDoc.docFilters as ObjectField) || new List([]); if (Cast(this.dataDoc[this.props.fieldKey + "-annotations"], listSpec(Doc), null) !== undefined) { Cast(this.dataDoc[this.props.fieldKey + "-annotations"], listSpec(Doc), []).push(anchor); } else { diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index da7ed9ac7..ce54bf57f 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -109,9 +109,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp private _ignoreScroll = false; @computed get _recording() { return this.dataDoc?.audioState === "recording"; } - set _recording(value) { - this.dataDoc.audioState = value ? "recording" : undefined; - } + set _recording(value) { this.dataDoc.audioState = value ? "recording" : undefined; } public static FocusedBox: FormattedTextBox | undefined; public static SelectOnLoad = ""; -- cgit v1.2.3-70-g09d2 From 58adadeaaf97c57a15d42fea86e75180fc3b2c14 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 24 Feb 2021 12:24:25 -0500 Subject: fixed layerProviders for treeViews to return true. fixed sidebar annotations for text to add/remove from correct field. --- src/client/views/DocComponent.tsx | 14 +++++++------- src/client/views/collections/CollectionTreeView.tsx | 2 +- src/client/views/collections/TreeView.tsx | 11 +++++++---- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 12 +++++++----- 4 files changed, 22 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index b800ba777..ef1228976 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -156,15 +156,15 @@ export function ViewBoxAnnotatableComponent

boolean): boolean { - return Doc.AreProtosEqual(this.props.Document, targetCollection) ? true : this.removeDocument(doc) ? addDocument(doc) : false; + moveDocument(doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean, annotationKey?: string): boolean { + return Doc.AreProtosEqual(this.props.Document, targetCollection) ? true : this.removeDocument(doc, annotationKey) ? addDocument(doc) : false; } @action.bound - addDocument(doc: Doc | Doc[]): boolean { + addDocument(doc: Doc | Doc[], annotationKey?: string): boolean { const docs = doc instanceof Doc ? [doc] : doc; docs.map(doc => doc.context = Doc.GetProto(doc).annotationOn = this.props.Document); const targetDataDoc = this.props.Document[DataSym]; - const docList = DocListCast(targetDataDoc[this.annotationKey]); + const docList = DocListCast(targetDataDoc[annotationKey ?? this.annotationKey]); const added = docs.filter(d => !docList.includes(d)); const effectiveAcl = GetEffectiveAcl(this.dataDoc); @@ -184,12 +184,12 @@ export function ViewBoxAnnotatableComponent

Doc.AddDocToList(targetDataDoc, this.annotationKey, doc)); + added.map(doc => Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc)); } else { added.map(doc => doc.context = this.props.Document); - (targetDataDoc[this.annotationKey] as List).push(...added); - targetDataDoc[this.annotationKey + "-lastModified"] = new DateField(new Date(Date.now())); + (targetDataDoc[annotationKey ?? this.annotationKey] as List).push(...added); + targetDataDoc[(annotationKey ?? this.annotationKey) + "-lastModified"] = new DateField(new Date(Date.now())); } } } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index a12de0320..146b3cd37 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -205,7 +205,7 @@ export class CollectionTreeView extends CollectionSubView this.addDoc(doc, relativeTo, before); const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument?.(d, target, addDoc) || false; return TreeView.GetChildElements(this.treeChildren, this, this.doc, this.props.DataDoc, this.props.fieldKey, this.props.ContainingCollectionDoc, undefined, addDoc, this.remove, - moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.styleProvider, this.props.ScreenToLocalTransform, + moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.styleProvider, returnTrue, this.props.ScreenToLocalTransform, this.outerXf, this.active, this.panelWidth, this.props.renderDepth, () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeViewHideHeaderFields), BoolCast(this.doc.treeViewPreventOpen), [], this.props.onCheckedClick, this.onChildClick, this.props.treeViewSkipFields, true, this.whenActiveChanged, this.props.dontRegisterView || Cast(this.props.Document.dontRegisterChildViews, "boolean", null), this); diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 297796b4b..dbd05f37a 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -52,6 +52,7 @@ export interface TreeViewProps { ScreenToLocalTransform: () => Transform; dontRegisterView?: boolean; styleProvider?: StyleProviderFunc | undefined; + layerProvider?: undefined | ((doc: Doc, assign?: boolean) => boolean); outerXf: () => { translateX: number, translateY: number }; treeView: CollectionTreeView; parentKey: string; @@ -327,7 +328,7 @@ export class TreeView extends React.Component { const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true); contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] : DocListCast(contents), this.props.treeView, doc, undefined, key, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move, - this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.titleStyleProvider, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, + this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.titleStyleProvider, this.props.layerProvider, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen, [...this.props.renderedIds, doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenActiveChanged, this.props.dontRegisterView, this); } else { @@ -410,7 +411,7 @@ export class TreeView extends React.Component { {!docs ? (null) : TreeView.GetChildElements(docs, this.props.treeView, this.layoutDoc, this.dataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move, - StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.props.pinToPres, this.titleStyleProvider, this.props.ScreenToLocalTransform, + StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.props.pinToPres, this.titleStyleProvider, this.props.layerProvider, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen, [...this.props.renderedIds, this.doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenActiveChanged, this.props.dontRegisterView, this)} ; @@ -578,7 +579,7 @@ export class TreeView extends React.Component { DataDoc={undefined} scriptContext={this} styleProvider={this.titleStyleProvider} - layerProvider={undefined} + layerProvider={this.props.layerProvider} docViewPath={returnEmptyDoclist} treeViewDoc={this.props.treeView.props.Document} addDocument={undefined} @@ -671,7 +672,7 @@ export class TreeView extends React.Component { renderDepth={this.props.renderDepth + 1} rootSelected={returnTrue} styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider} - layerProvider={undefined} + layerProvider={this.props.layerProvider} docViewPath={this.props.treeView.props.docViewPath} docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} @@ -775,6 +776,7 @@ export class TreeView extends React.Component { addDocTab: (doc: Doc, where: string) => boolean, pinToPres: (document: Doc) => void, styleProvider: undefined | StyleProviderFunc, + layerProvider: undefined | ((doc: Doc, assign?: boolean) => boolean), screenToLocalXf: () => Transform, outerXf: () => { translateX: number, translateY: number }, active: (outsideReaction?: boolean) => boolean, @@ -838,6 +840,7 @@ export class TreeView extends React.Component { removeDoc={StrCast(containingCollection.freezeChildren).includes("remove") ? undefined : remove} addDocument={addDocument} styleProvider={styleProvider} + layerProvider={layerProvider} panelWidth={rowWidth} panelHeight={rowHeight} dontRegisterView={dontRegisterView} diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index ce54bf57f..b4fbda9f4 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -105,7 +105,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp private _disposers: { [name: string]: IReactionDisposer } = {}; private _dropDisposer?: DragManager.DragDropDisposer; private _recordingStart: number = 0; - private _pause: boolean = false; private _ignoreScroll = false; @computed get _recording() { return this.dataDoc?.audioState === "recording"; } @@ -1649,6 +1648,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp sidebarContentScaling = () => (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); fitToBox = () => this.props.Document._fitToBox; + sidebarAddDocument = (doc: Doc | Doc[]) => this.addDocument(doc, this.SidebarKey); + sidebarMoveDocument = (doc: Doc | Doc[], targetCollection: Doc, addDocument: (doc: Doc | Doc[]) => boolean) => this.moveDocument(doc, targetCollection, addDocument, this.SidebarKey); + sidebarRemDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, this.SidebarKey); @computed get sidebarCollection() { const collectionProps: SubCollectionViewProps & collectionFreeformViewProps = { ...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit, @@ -1660,16 +1662,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp yMargin: 0, chromeStatus: "enabled", scaleField: this.SidebarKey + "-scale", - isAnnotationOverlay: true, + isAnnotationOverlay: false, fieldKey: this.SidebarKey, fitContentsToDoc: this.fitToBox, select: emptyFunction, active: this.annotationsActive, scaling: this.sidebarContentScaling, whenActiveChanged: this.whenActiveChanged, - removeDocument: this.removeDocument, - moveDocument: this.moveDocument, - addDocument: this.addDocument, + removeDocument: this.sidebarRemDocument, + moveDocument: this.sidebarMoveDocument, + addDocument: this.sidebarAddDocument, CollectionView: undefined, ScreenToLocalTransform: this.sidebarScreenToLocal, renderDepth: this.props.renderDepth + 1, -- cgit v1.2.3-70-g09d2 From 3410e107435410a5635a70f12ee05e2d874ff01c Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 24 Feb 2021 22:04:31 -0500 Subject: cleaned up DocumentView's contentView api to be more general. fixed screenToLocal for freeformView's whenb _fitToBox is set. moved webBox menu items out of CollectionMenu and into WebBox using the contentView API. --- src/client/views/collections/CollectionMenu.tsx | 57 +--------------------- .../collectionFreeForm/CollectionFreeFormView.scss | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 18 +++---- src/client/views/nodes/DocumentView.tsx | 17 +++---- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 47 ++++++++++++++++++ 7 files changed, 68 insertions(+), 77 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 423c94005..591b4161e 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -560,7 +560,6 @@ export class CollectionFreeFormViewChrome extends React.Component; } - - onWebUrlDrop = (e: React.DragEvent) => { - const { dataTransfer } = e; - const html = dataTransfer.getData("text/html"); - const uri = dataTransfer.getData("text/uri-list"); - const url = uri || html || this.webBoxUrl || ""; - const newurl = url.startsWith(window.location.origin) ? - url.replace(window.location.origin, this.webBoxUrl?.match(/http[s]?:\/\/[^\/]*/)?.[0] || "") : url; - this.submitWebUrl(newurl); - e.stopPropagation(); - } - onWebUrlValueKeyDown = (e: React.KeyboardEvent) => { - e.key === "Enter" && this.submitWebUrl(this._keyInput.current!.value); - e.stopPropagation(); - } - submitWebUrl = (url: string) => this.selectedDocumentView?.ComponentView?.submitURL?.(url); - webUrlForward = () => this.selectedDocumentView?.ComponentView?.forward?.(); - webUrlBack = () => this.selectedDocumentView?.ComponentView?.back?.(); - - private _keyInput = React.createRef(); - - @computed get urlEditor() { - return ( -

e.preventDefault()} > - e.preventDefault()} - onKeyDown={this.onWebUrlValueKeyDown} - onClick={(e) => { - this._keyInput.current!.select(); - e.stopPropagation(); - }} - ref={this._keyInput} - /> -
- - - -
-
- ); - } - - @observable viewType = this.selectedDoc?._viewType; render() { @@ -811,9 +758,7 @@ export class CollectionFreeFormViewChrome extends React.Component : null} - {!this.props.isOverlay || this.document.type !== DocumentType.WEB || this.isText || this.props.isDoc ? (null) : - this.urlEditor - } + {!this.selectedDocumentView?.ComponentView?.menuControls ? (null) : this.selectedDocumentView?.ComponentView?.menuControls?.()} {!this.isText ? <> {this.drawButtons} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index a05c25c9b..eb0538c41 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -191,7 +191,7 @@ .collectionfreeformview-container { // touch action none means that the browser will handle none of the touch actions. this allows us to implement our own actions. touch-action: none; - + transform-origin: top left; .collectionfreeformview-placeholder { background: gray; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 96ef7af01..92c09ff3f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -69,7 +69,7 @@ type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof collectionSch const PanZoomDocument = makeInterface(panZoomSchema, collectionSchema, documentSchema, pageSchema); export type collectionFreeformViewProps = { parentActive: (outsideReaction: boolean) => boolean; - forceScaling?: boolean; // whether to force scaling of content (needed by ImageBox) + annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox) viewDefDivClick?: ScriptField; childPointerEvents?: boolean; scaleField?: string; @@ -157,10 +157,11 @@ export class CollectionFreeFormView extends CollectionSubView this.fitToContent || force ? this.fitToContentVals : undefined; freeformDocFilters = () => this._focusFilters || this.docFilters(); freeformRangeDocFilters = () => this._focusRangeFilters || this.docRangeFilters(); + reverseNativeScaling = () => this.fitToContent ? true : false; panX = () => this.freeformData()?.panX ?? NumCast(this.Document._panX); panY = () => this.freeformData()?.panY ?? NumCast(this.Document._panY); zoomScaling = () => (this.freeformData()?.scale ?? NumCast(this.Document[this.scaleFieldKey], 1)); - contentTransform = () => `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)` + contentTransform = () => `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(); @@ -1274,11 +1275,11 @@ export class CollectionFreeFormView extends CollectionSubView Doc.toggleNativeDimensions(this.layoutDoc, 1, this.nativeWidth, this.nativeHeight); + toggleNativeDimensions = () => Doc.toggleNativeDimensions(this.layoutDoc, 1, this.nativeWidth, this.nativeHeight) @undoBatch @action - toggleLockTransform = () => this.layoutDoc._lockedTransform = this.layoutDoc._lockedTransform ? undefined : true; + toggleLockTransform = () => this.layoutDoc._lockedTransform = this.layoutDoc._lockedTransform ? undefined : true onContextMenu = (e: React.MouseEvent) => { if (this.props.isAnnotationOverlay || this.props.Document.annotationOn || !ContextMenu.Instance) return; @@ -1462,7 +1463,7 @@ export class CollectionFreeFormView extends CollectionSubView {this.Document._freeformLOD && !this.props.active() && !this.props.isAnnotationOverlay && this.props.renderDepth > 0 ? this.placeholder : this.marqueeView} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5dfb3e99b..ec2c77a82 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -76,14 +76,13 @@ export type DocAfterFocusFunc = (notFocused: boolean) => Promise export type DocFocusFunc = (doc: Doc, options?: DocFocusOptions) => void; export type StyleProviderFunc = (doc: Opt, props: Opt, property: string) => any; export interface DocComponentView { - getAnchor?: () => Doc; + getAnchor?: () => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) scrollFocus?: (doc: Doc, smooth: boolean) => Opt; // returns the duration of the focus - setViewSpec?: (anchor: Doc, preview: boolean) => void; - back?: () => boolean; - forward?: () => boolean; - url?: () => string; - submitURL?: (url: string) => boolean; - freeformData?: (force?: boolean) => Opt<{ panX: number, panY: number, scale: number, bounds: { x: number, y: number, r: number, b: number } }>; + setViewSpec?: (anchor: Doc, preview: boolean) => void; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document + reverseNativeScaling?: () => boolean; // DocumentView's setup screenToLocal based on the doc having a nativeWidth/Height. However, some content views (e.g., FreeFormView w/ fitToBox set) may ignore the native dimensions so this flags the DocumentView to not do Nativre scaling. + menuControls?: any; // controls to display in the top menu bar when the document is selected. + // this is kind of hacky since it's not really a generic interface. need to think about how to do this better (it's used to fit a tab's contents to view when shown in a lightbox and to setup the minimap) + freeformData?: (force?: boolean) => Opt<{ panX: number, panY: number, scale: number, bounds: { x: number, y: number, r: number, b: number } }>; // the content bounds, pan position and zoom scale of a content view (typically for FreeformViews) } export interface DocumentViewSharedProps { renderDepth: number; @@ -990,8 +989,8 @@ export class DocumentView extends React.Component { @computed get docViewPath() { return this.props.docViewPath ? [...this.props.docViewPath(), this] : [this]; } @computed get layoutDoc() { return Doc.Layout(this.Document, this.props.LayoutTemplate?.()); } - @computed get nativeWidth() { return returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions)); } - @computed get nativeHeight() { return returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions) || 0); } + @computed get nativeWidth() { return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions)); } + @computed get nativeHeight() { return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions) || 0); } @computed get nativeScaling() { if (this.nativeWidth && (this.layoutDoc?._fitWidth || this.props.PanelHeight() / this.nativeHeight > this.props.PanelWidth() / this.nativeWidth)) { return this.props.PanelWidth() / this.nativeWidth; // width-limited or fitWidth diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 728e5e02f..4c3031ae2 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -381,7 +381,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent = React.createRef(); private _iframeIndicatorRef = React.createRef(); private _iframeDragRef = React.createRef(); + private _keyInput = React.createRef(); private _ignoreScroll = false; private _initialScroll: Opt; @observable private _marqueeing: number[] | undefined; @@ -262,6 +263,52 @@ export class WebBox extends ViewBoxAnnotatableComponent this.urlEditor; + onWebUrlDrop = (e: React.DragEvent) => { + const { dataTransfer } = e; + const html = dataTransfer.getData("text/html"); + const uri = dataTransfer.getData("text/uri-list"); + const url = uri || html || this._url || ""; + const newurl = url.startsWith(window.location.origin) ? + url.replace(window.location.origin, this._url?.match(/http[s]?:\/\/[^\/]*/)?.[0] || "") : url; + this.submitURL(newurl); + e.stopPropagation(); + } + onWebUrlValueKeyDown = (e: React.KeyboardEvent) => { + e.key === "Enter" && this.submitURL(this._keyInput.current!.value); + e.stopPropagation(); + } + + @computed get urlEditor() { + return ( +
e.preventDefault()} > + e.preventDefault()} + onKeyDown={this.onWebUrlValueKeyDown} + onClick={(e) => { + this._keyInput.current!.select(); + e.stopPropagation(); + }} + ref={this._keyInput} + /> +
+ + + +
+
+ ); + } + editToggleBtn() { return {`${this.props.Document.isAnnotating ? "Exit" : "Enter"} annotation mode`}
}>
Date: Thu, 25 Feb 2021 01:25:36 -0500 Subject: cleaned up DoccomponentView to just have general api fields. fixed lightbox to animate back properly & shinkwrap. --- src/client/views/LightboxView.tsx | 34 +++++++++------------- src/client/views/collections/TabDocView.tsx | 8 ++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 14 +++++---- src/client/views/nodes/DocumentView.tsx | 5 ++-- 4 files changed, 28 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index e967a5b07..1b21bd073 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -13,7 +13,7 @@ import { SelectionManager } from '../util/SelectionManager'; import { Transform } from '../util/Transform'; import { TabDocView } from './collections/TabDocView'; import "./LightboxView.scss"; -import { DocumentView } from './nodes/DocumentView'; +import { DocumentView, ViewAdjustment } from './nodes/DocumentView'; import { DefaultStyleProvider } from './StyleProvider'; interface LightboxViewProps { @@ -103,8 +103,7 @@ export class LightboxView extends React.Component { [...DocListCast(doc[Doc.LayoutFieldKey(doc)]), ...DocListCast(doc[Doc.LayoutFieldKey(doc) + "-annotations"]), ...(LightboxView._future ?? []) - ] - .sort((a: Doc, b: Doc) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow))); + ].sort((a: Doc, b: Doc) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow))); } docFilters = () => LightboxView._docFilters || []; addDocTab = LightboxView.AddDocTab; @@ -113,8 +112,8 @@ export class LightboxView extends React.Component { const target = LightboxView._docTarget = LightboxView._future?.pop(); const docView = target && DocumentManager.Instance.getLightboxDocumentView(target); if (docView && target) { - docView.focus(target, { willZoom: true, scale: 0.9 }); - if (LightboxView._history?.lastElement().target !== target) LightboxView._history?.push({ doc, target: LightboxView._docTarget }); + docView.focus(target, { originalTarget: target, willZoom: true, scale: 0.9 }); + if (LightboxView._history?.lastElement().target !== target) LightboxView._history?.push({ doc, target }); } else { if (!target && LightboxView.path.length) { const saved = LightboxView._savedState; @@ -149,16 +148,14 @@ export class LightboxView extends React.Component { return; } const { doc, target } = LightboxView._history?.lastElement(); - const docView = target && DocumentManager.Instance.getLightboxDocumentView(target); - if (docView && target) { - LightboxView._doc = doc; - LightboxView._docTarget = target || doc; - if (LightboxView._future?.lastElement() !== previous.target || previous.doc) LightboxView._future?.push(previous.target || previous.doc); - docView.focus(target, { willZoom: true, scale: 0.9 }); - } else { - LightboxView._doc = doc; - LightboxView._docTarget = target || doc; - } + const docView = DocumentManager.Instance.getLightboxDocumentView(target || doc); + const focusSpeed = 1000; + doc._viewTransition = `transform ${focusSpeed}ms`; + LightboxView._doc = doc; + LightboxView._docTarget = target || doc; + docView?.focus(doc, { willZoom: true, scale: 0.9 }); + setTimeout(() => doc._viewTransition = undefined, focusSpeed); + if (LightboxView._future?.lastElement() !== previous.target || previous.doc) LightboxView._future?.push(previous.target || previous.doc); LightboxView._tourMap = DocListCast(LightboxView._docTarget?.links).map(link => { const opp = LinkManager.getOppositeAnchor(link, LightboxView._docTarget!); return opp?.TourMap ? opp : undefined; @@ -208,11 +205,8 @@ export class LightboxView extends React.Component { { LightboxView._docView = r !== null ? r : undefined; setTimeout(action(() => { - const vals = r?.ComponentView?.freeformData?.(); - if (vals && r) { - r.layoutDoc._panX = vals.panX; - r.layoutDoc._panY = vals.panY; - r.layoutDoc._viewScale = vals.scale; + if (r && LightboxView._docTarget === r.props.Document) { + r.ComponentView?.shrinkWrap?.(); } r && (LightboxView._docTarget = undefined); })); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 80ddf2f48..3f8794665 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -273,12 +273,10 @@ export class TabDocView extends React.Component { } @action focusFunc = (doc: Doc, options?: DocFocusOptions) => { - const vals = (!options?.originalTarget || options?.originalTarget === this._document) && this.view?.ComponentView?.freeformData?.(true); - if (vals && this._document) { + const shrinkwrap = options?.originalTarget === this._document && this.view?.ComponentView?.shrinkWrap; + if (shrinkwrap && this._document) { const focusSpeed = 1000; - this._document._panX = vals.panX; - this._document._panY = vals.panY; - this._document._viewScale = vals.scale; + shrinkwrap(); this._document._viewTransition = `transform ${focusSpeed}ms`; setTimeout(action(() => { this._document!._viewTransition = undefined; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 92c09ff3f..dfca2ba07 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -120,9 +120,7 @@ export class CollectionFreeFormView extends CollectionSubView this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); parentActive = (outsideReaction: boolean) => this.props.active(outsideReaction) || this.props.parentActive?.(outsideReaction) || this.backgroundActive || this.layoutDoc._viewType === CollectionViewType.Pile ? true : false; elementFunc = () => this._layoutElements; + shrinkWrap = () => { + const vals = this.fitToContentVals; + this.layoutDoc._panX = vals.bounds.cx; + this.layoutDoc._panY = vals.bounds.cy; + this.layoutDoc._viewScale = vals.scale; + } freeformData = (force?: boolean) => this.fitToContent || force ? this.fitToContentVals : undefined; freeformDocFilters = () => this._focusFilters || this.docFilters(); freeformRangeDocFilters = () => this._focusRangeFilters || this.docRangeFilters(); reverseNativeScaling = () => this.fitToContent ? true : false; - panX = () => this.freeformData()?.panX ?? NumCast(this.Document._panX); - panY = () => this.freeformData()?.panY ?? NumCast(this.Document._panY); + panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document._panX); + panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document._panY); zoomScaling = () => (this.freeformData()?.scale ?? NumCast(this.Document[this.scaleFieldKey], 1)); contentTransform = () => `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`; getTransform = () => this.cachedGetTransform.copy(); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ec2c77a82..01d799255 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -80,9 +80,8 @@ export interface DocComponentView { scrollFocus?: (doc: Doc, smooth: boolean) => Opt; // returns the duration of the focus setViewSpec?: (anchor: Doc, preview: boolean) => void; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document reverseNativeScaling?: () => boolean; // DocumentView's setup screenToLocal based on the doc having a nativeWidth/Height. However, some content views (e.g., FreeFormView w/ fitToBox set) may ignore the native dimensions so this flags the DocumentView to not do Nativre scaling. - menuControls?: any; // controls to display in the top menu bar when the document is selected. - // this is kind of hacky since it's not really a generic interface. need to think about how to do this better (it's used to fit a tab's contents to view when shown in a lightbox and to setup the minimap) - freeformData?: (force?: boolean) => Opt<{ panX: number, panY: number, scale: number, bounds: { x: number, y: number, r: number, b: number } }>; // the content bounds, pan position and zoom scale of a content view (typically for FreeformViews) + shrinkWrap?: () => boolean; // requests a document to display all of its contents with no white space. currently only implemented (needed?) for freeform views + menuControls?: () => JSX.Element; // controls to display in the top menu bar when the document is selected. } export interface DocumentViewSharedProps { renderDepth: number; -- cgit v1.2.3-70-g09d2 From c4c3764397eb1ab12c93ea3e07483b436e87d736 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 25 Feb 2021 11:50:54 -0500 Subject: overhaul of state preservation in lightboxview when going back/forward/reopening a doc/etc --- src/client/views/LightboxView.tsx | 101 +++++++++++++-------- .../collectionFreeForm/CollectionFreeFormView.tsx | 13 +-- src/client/views/nodes/DocumentView.tsx | 3 +- 3 files changed, 71 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index 1b21bd073..babc518ff 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable } from 'mobx'; +import { action, computed, observable, trace } from 'mobx'; import { observer } from 'mobx-react'; import "normalize.css"; import * as React from 'react'; @@ -28,32 +28,33 @@ export class LightboxView extends React.Component { @computed public static get LightboxDoc() { return this._doc; } @observable private static _doc: Opt; @observable private static _docTarget: Opt; - @observable private static _tourMap: Opt = []; // list of all tours available from the current target @observable private static _docFilters: string[] = []; // filters - private static _savedState: Opt<{ panX: Opt, panY: Opt, scale: Opt, transition: Opt }>; + @observable private static _tourMap: Opt = []; // list of all tours available from the current target + private static _savedState: Opt<{ panX: Opt, panY: Opt, scale: Opt }>; private static _history: Opt<{ doc: Doc, target?: Doc }[]> = []; private static _future: Opt = []; private static _docView: Opt; - static path: { doc: Opt, target: Opt, history: Opt<{ doc: Doc, target?: Doc }[]>, future: Opt, saved: Opt<{ panX: Opt, panY: Opt, scale: Opt, transition: Opt }> }[] = []; + static path: { doc: Opt, target: Opt, history: Opt<{ doc: Doc, target?: Doc }[]>, future: Opt, saved: Opt<{ panX: Opt, panY: Opt, scale: Opt }> }[] = []; @action public static SetLightboxDoc(doc: Opt, target?: Doc, future?: Doc[]) { + if (this.LightboxDoc && this.LightboxDoc !== doc && this._savedState) { + this.LightboxDoc._panX = this._savedState.panX; + this.LightboxDoc._panY = this._savedState.panY; + this.LightboxDoc._viewScale = this._savedState.scale; + this.LightboxDoc._viewTransition = undefined; + } if (!doc) { this._docFilters && (this._docFilters.length = 0); - if (this.LightboxDoc) { - this.LightboxDoc._panX = this._savedState?.panX; - this.LightboxDoc._panY = this._savedState?.panY; - this.LightboxDoc._viewScale = this._savedState?.scale; - this.LightboxDoc._viewTransition = this._savedState?.transition; - } this._future = this._history = []; } else { TabDocView.PinDoc(doc, { hidePresBox: true }); this._history ? this._history.push({ doc, target }) : this._history = [{ doc, target }]; - this._savedState = { - panX: Cast(doc._panX, "number", null), - panY: Cast(doc._panY, "number", null), - scale: Cast(doc._viewScale, "number", null), - transition: Cast(doc._viewTransition, "string", null) - }; + if (doc !== LightboxView.LightboxDoc) { + this._savedState = { + panX: Cast(doc._panX, "number", null), + panY: Cast(doc._panY, "number", null), + scale: Cast(doc._viewScale, "number", null), + }; + } } if (future) { this._future = future.slice().sort((a, b) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow)).sort((a, b) => DocListCast(a.links).length - DocListCast(b.links).length); @@ -92,6 +93,7 @@ export class LightboxView extends React.Component { } // adds a cookie to the lightbox view - the cookie becomes part of a filter which will display any documents whose cookie metadata field matches this cookie + @action public static SetCookie(cookie: string) { if (this.LightboxDoc && cookie) { this._docFilters = (f => this._docFilters ? [this._docFilters.push(f) as any, this._docFilters][1] : [f])(`cookies:${cookie}:provide`); @@ -117,11 +119,11 @@ export class LightboxView extends React.Component { } else { if (!target && LightboxView.path.length) { const saved = LightboxView._savedState; - if (LightboxView.LightboxDoc) { - LightboxView.LightboxDoc._panX = saved?.panX; - LightboxView.LightboxDoc._panY = saved?.panY; - LightboxView.LightboxDoc._viewScale = saved?.scale; - LightboxView.LightboxDoc._viewTransition = saved?.transition; + if (LightboxView.LightboxDoc && saved) { + LightboxView.LightboxDoc._panX = saved.panX; + LightboxView.LightboxDoc._panY = saved.panY; + LightboxView.LightboxDoc._viewScale = saved.scale; + LightboxView.LightboxDoc._viewTransition = undefined; } const pop = LightboxView.path.pop(); if (pop) { @@ -149,12 +151,17 @@ export class LightboxView extends React.Component { } const { doc, target } = LightboxView._history?.lastElement(); const docView = DocumentManager.Instance.getLightboxDocumentView(target || doc); - const focusSpeed = 1000; - doc._viewTransition = `transform ${focusSpeed}ms`; - LightboxView._doc = doc; - LightboxView._docTarget = target || doc; - docView?.focus(doc, { willZoom: true, scale: 0.9 }); - setTimeout(() => doc._viewTransition = undefined, focusSpeed); + if (docView) { + LightboxView._docTarget = undefined; + const focusSpeed = 1000; + doc._viewTransition = `transform ${focusSpeed}ms`; + if (!target) docView.ComponentView?.shrinkWrap?.(); + else docView.focus(target, { willZoom: true, scale: 0.9 }); + setTimeout(() => doc._viewTransition = undefined, focusSpeed); + } + else { + LightboxView.SetLightboxDoc(doc, target); + } if (LightboxView._future?.lastElement() !== previous.target || previous.doc) LightboxView._future?.push(previous.target || previous.doc); LightboxView._tourMap = DocListCast(LightboxView._docTarget?.links).map(link => { const opp = LinkManager.getOppositeAnchor(link, LightboxView._docTarget!); @@ -185,6 +192,8 @@ export class LightboxView extends React.Component { setTimeout(LightboxView.Next); } + future = () => LightboxView._future; + tourMap = () => LightboxView._tourMap; fitToBox = () => LightboxView._docTarget === LightboxView.LightboxDoc; render() { let downx = 0, downy = 0; @@ -204,11 +213,13 @@ export class LightboxView extends React.Component { }}> { LightboxView._docView = r !== null ? r : undefined; - setTimeout(action(() => { - if (r && LightboxView._docTarget === r.props.Document) { - r.ComponentView?.shrinkWrap?.(); - } - r && (LightboxView._docTarget = undefined); + r && setTimeout(action(() => { + const target = LightboxView._docTarget; + const doc = LightboxView._doc; + const targetView = target && DocumentManager.Instance.getLightboxDocumentView(target); + if (doc === r.props.Document && (!target || target === doc)) r.ComponentView?.shrinkWrap?.(); + else target && targetView?.focus(target, { willZoom: true, scale: 0.9, instant: true }); + LightboxView._docTarget = undefined; })); })} Document={LightboxView.LightboxDoc} @@ -246,13 +257,25 @@ export class LightboxView extends React.Component { e.stopPropagation(); LightboxView.Next(); })} - {this.navBtn("50%", 0, 0, "chevron-down", - () => LightboxView.LightboxDoc && LightboxView._future?.length ? "" : "none", e => { - e.stopPropagation(); - this.stepInto(); - }, - StrCast(LightboxView._tourMap?.lastElement()?.TourMap) - )} +
; } +} +interface LightboxTourBtnProps { + navBtn: (left: Opt, bottom: Opt, top: number, icon: string, display: () => string, click: (e: React.MouseEvent) => void, color?: string) => JSX.Element; + tourMap: () => Opt; + future: () => Opt; + stepInto: () => void; +} +@observer +export class LightboxTourBtn extends React.Component { + render() { + return this.props.navBtn("50%", 0, 0, "chevron-down", + () => LightboxView.LightboxDoc && this.props.future()?.length ? "" : "none", e => { + e.stopPropagation(); + this.props.stepInto(); + }, + StrCast(this.props.tourMap()?.lastElement()?.TourMap) + ) + } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index dfca2ba07..4040362d8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -914,7 +914,6 @@ export class CollectionFreeFormView extends CollectionSubView this._viewTransition = 0); } return resetView; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 01d799255..e58aaba65 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -71,6 +71,7 @@ export interface DocFocusOptions { scale?: number; // percent of containing frame to zoom into document afterFocus?: DocAfterFocusFunc; // function to call after focusing on a document docTransform?: Transform; // when a document can't be panned and zoomed within its own container (say a group), then we need to continue to move up the render hierarchy to find something that can pan and zoom. when this happens the docTransform must accumulate all the transforms of each level of the hierarchy + instant?: boolean; // whether focus should happen instantly (as opposed to smooth zoom) } export type DocAfterFocusFunc = (notFocused: boolean) => Promise; export type DocFocusFunc = (doc: Doc, options?: DocFocusOptions) => void; @@ -80,7 +81,7 @@ export interface DocComponentView { scrollFocus?: (doc: Doc, smooth: boolean) => Opt; // returns the duration of the focus setViewSpec?: (anchor: Doc, preview: boolean) => void; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document reverseNativeScaling?: () => boolean; // DocumentView's setup screenToLocal based on the doc having a nativeWidth/Height. However, some content views (e.g., FreeFormView w/ fitToBox set) may ignore the native dimensions so this flags the DocumentView to not do Nativre scaling. - shrinkWrap?: () => boolean; // requests a document to display all of its contents with no white space. currently only implemented (needed?) for freeform views + shrinkWrap?: () => void; // requests a document to display all of its contents with no white space. currently only implemented (needed?) for freeform views menuControls?: () => JSX.Element; // controls to display in the top menu bar when the document is selected. } export interface DocumentViewSharedProps { -- cgit v1.2.3-70-g09d2 From 17ee7f6f1f61a079ec79b71aebc65abfd72ec32a Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 25 Feb 2021 13:38:31 -0500 Subject: added an aliases toggle to file system --- src/client/util/DocumentManager.ts | 12 +++++++++++- src/client/views/collections/TreeView.tsx | 11 ++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 67e05f8d0..637e219d5 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -10,6 +10,8 @@ import { LightboxView } from '../views/LightboxView'; import { DocumentView, ViewAdjustment } from '../views/nodes/DocumentView'; import { Scripting } from './Scripting'; import { CurrentUserUtils } from './CurrentUserUtils'; +import { TabDocView } from '../views/collections/TabDocView'; +import { UndoManager } from './UndoManager'; export class DocumentManager { @@ -219,4 +221,12 @@ export class DocumentManager { } } -Scripting.addGlobal(function DocFocus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, { willZoom: true })); }); \ No newline at end of file +Scripting.addGlobal(function DocFocus(doc: any) { + const dv = DocumentManager.Instance.getDocumentView(doc); + if (dv && dv?.props.Document === doc) dv.props.focus(doc, { willZoom: true }); + else { + const context = Cast(doc.context, Doc, null); + CollectionDockingView.AddSplit(context || doc, "right") && context && + setTimeout(() => DocumentManager.Instance.getDocumentView(Doc.GetProto(doc))?.focus(doc)); + } +}); \ No newline at end of file diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index dbd05f37a..ac19a3591 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -115,11 +115,11 @@ export class TreeView extends React.Component { @computed get fieldKey() { TraceMobx(); const splits = StrCast(Doc.LayoutField(this.doc)).split("fieldKey={\'"); return splits.length > 1 ? splits[1].split("\'")[0] : "data"; } @computed get childDocs() { TraceMobx(); return this.childDocList(this.fieldKey); } @computed get childLinks() { return this.childDocList("links"); } + @computed get childAliases() { return this.childDocList("aliases"); } @computed get childAnnos() { return this.childDocList(this.fieldKey + "-annotations"); } @computed get selected() { return SelectionManager.Views().length && SelectionManager.Views()[0].props.Document === this.props.document; } childDocList(field: string) { - if (this.fileSysMode && !this.doc.isFolder) return [] as Doc[]; const layout = Doc.LayoutField(this.doc) instanceof Doc ? Doc.LayoutField(this.doc) as Doc : undefined; return ((this.props.dataDoc ? DocListCastOrNull(this.props.dataDoc[field]) : undefined) || // if there's a data doc for an expanded template, use it's data field (layout ? DocListCastOrNull(layout[field]) : undefined) || // else if there's a layout doc, display it's fields @@ -376,7 +376,7 @@ export class TreeView extends React.Component { @computed get renderContent() { TraceMobx(); const expandKey = this.treeViewExpandedView; - if (["links", "annotations", this.fieldKey].includes(expandKey)) { + if (["links", "annotations", "aliases", this.fieldKey].includes(expandKey)) { const key = expandKey === "annotations" ? this.fieldKey + "-annotations" : expandKey; const remDoc = (doc: Doc | Doc[]) => this.remove(doc, key); const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => { @@ -395,7 +395,7 @@ export class TreeView extends React.Component { return added; }; const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true); - const docs = expandKey === "links" ? this.childLinks : expandKey === "annotations" ? this.childAnnos : this.childDocs; + const docs = expandKey === "aliases" ? this.childAliases : expandKey === "links" ? this.childLinks : expandKey === "annotations" ? this.childAnnos : this.childDocs; const sortKey = `${this.fieldKey}-sortCriteria`; let downX = 0, downY = 0; const sortings = ["up", "down", "Z", undefined]; @@ -422,7 +422,7 @@ export class TreeView extends React.Component {
; } - return
    {this.renderEmbeddedDocument(false)}
; + return
    {this.renderEmbeddedDocument(false)}
; // "layout" } get onCheckedClick() { return this.doc.type === DocumentType.COL ? undefined : this.props.onCheckedClick?.() ?? ScriptCast(this.doc.onCheckedClick); } @@ -477,7 +477,8 @@ export class TreeView extends React.Component { { if (this.fileSysMode) { - this.doc.treeViewExpandedView = this.doc.isFolder ? this.fieldKey : this.treeViewExpandedView === "layout" ? "fields" : "layout"; + this.doc.treeViewExpandedView = this.doc.isFolder ? this.fieldKey : this.treeViewExpandedView === "layout" ? "fields" : + this.treeViewExpandedView === "fields" ? "aliases" : "layout"; } else if (this.treeViewOpen) { this.doc.treeViewExpandedView = this.treeViewLockExpandedView ? this.doc.treeViewExpandedView : this.treeViewExpandedView === this.fieldKey ? (Doc.UserDoc().noviceMode || this.outlineMode ? "layout" : "fields") : -- cgit v1.2.3-70-g09d2