diff options
Diffstat (limited to 'src/client/views/DocumentDecorations.tsx')
-rw-r--r-- | src/client/views/DocumentDecorations.tsx | 117 |
1 files changed, 54 insertions, 63 deletions
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index ef493fb69..432b02782 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -17,9 +17,7 @@ import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { GetEffectiveAcl } from '../../fields/util'; import { DocumentType } from '../documents/DocumentTypes'; import { Docs } from '../documents/Documents'; -import { DocumentManager } from '../util/DocumentManager'; import { DragManager } from '../util/DragManager'; -import { SelectionManager } from '../util/SelectionManager'; import { SettingsManager } from '../util/SettingsManager'; import { SnappingManager } from '../util/SnappingManager'; import { UndoManager } from '../util/UndoManager'; @@ -81,14 +79,14 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora let inputting = false; if (this._titleControlString.startsWith('$')) { const titleFieldKey = this._titleControlString.substring(1); - if (SelectionManager.Views[0]?.Document[titleFieldKey] !== this._accumulatedTitle) { + if (DocumentView.Selected()[0]?.Document[titleFieldKey] !== this._accumulatedTitle) { inputting = true; } } const center = {x: (this.Bounds.x+this.Bounds.r)/2, y: (this.Bounds.y+this.Bounds.b)/2}; const {x,y} = Utils.rotPt(e.clientX - center.x, e.clientY - center.y, - NumCast(SelectionManager.Views.lastElement()?.screenToViewTransform().Rotate)); + NumCast(DocumentView.Selected().lastElement()?.screenToViewTransform().Rotate)); (this._showNothing = !inputting && !DocumentButtonBar.Instance?._tooltipOpen && !(this.Bounds.x !== Number.MAX_VALUE && // (this.Bounds.x > center.x+x || this.Bounds.r < center.x+x || this.Bounds.y > center.y+y || this.Bounds.b < center.y+y ))); @@ -110,7 +108,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora @computed get Bounds() { return (SnappingManager.IsLinkFollowing || SnappingManager.ExploreMode) ? { x: 0, y: 0, r: 0, b: 0 } - : SelectionManager.Views + : DocumentView.Selected() .filter(dv => dv._props.renderDepth > 0) .map(dv => dv.getBounds) .reduce((bounds, rect) => !rect ? bounds @@ -127,7 +125,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora this._titleControlString = this._accumulatedTitle; } else if (this._titleControlString.startsWith('$')) { if (this._accumulatedTitle.startsWith('-->#')) { - SelectionManager.Docs.forEach(doc => { + DocumentView.SelectedDocs().forEach(doc => { doc[DocData].onViewMounted = ScriptField.MakeScript(`updateTagsCollection(this)`); }); } @@ -135,11 +133,11 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora UndoManager.RunInBatch( () => titleFieldKey && - SelectionManager.Views.forEach(d => { + DocumentView.Selected().forEach(dv => { if (titleFieldKey === 'title') { - d.dataDoc.title_custom = !this._accumulatedTitle.startsWith('-'); + dv.dataDoc.title_custom = !this._accumulatedTitle.startsWith('-'); } - KeyValueBox.SetField(d.Document, titleFieldKey, this._accumulatedTitle); + KeyValueBox.SetField(dv.Document, titleFieldKey, this._accumulatedTitle); }), 'edit title' ); @@ -154,7 +152,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora }; onContainerDown = (e: React.PointerEvent) => { - const effectiveLayoutAcl = GetEffectiveAcl(SelectionManager.Views[0].Document); + const effectiveLayoutAcl = GetEffectiveAcl(DocumentView.Selected()[0].Document); if (effectiveLayoutAcl === AclAdmin || effectiveLayoutAcl === AclEdit || effectiveLayoutAcl === AclAugment) { setupMoveUpEvents(this, e, moveEv => this.onBackgroundMove(true, moveEv), emptyFunction, emptyFunction); e.stopPropagation(); @@ -162,7 +160,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora }; onTitleDown = (e: React.PointerEvent) => { - const effectiveLayoutAcl = GetEffectiveAcl(SelectionManager.Views[0].Document); + const effectiveLayoutAcl = GetEffectiveAcl(DocumentView.SelectedDocs()[0]); if (effectiveLayoutAcl === AclAdmin || effectiveLayoutAcl === AclEdit || effectiveLayoutAcl === AclAugment) { setupMoveUpEvents( this, @@ -170,7 +168,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora moveEv => this.onBackgroundMove(true, moveEv), emptyFunction, action(() => { - const selected = SelectionManager.Views.length === 1 ? SelectionManager.Docs[0] : undefined; + const selected = DocumentView.SelectedDocs().length === 1 ? DocumentView.SelectedDocs()[0] : undefined; !this._editingTitle && (this._accumulatedTitle = this._titleControlString.startsWith('$') ? (selected && Field.toKeyValueString(selected, this._titleControlString.substring(1))) || '-unset-' : this._titleControlString); this._editingTitle = true; this._keyinput.current && setTimeout(this._keyinput.current.focus); @@ -186,19 +184,16 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora }; @action onBackgroundMove = (dragTitle: boolean, e: PointerEvent): boolean => { - const dragDocView = SelectionManager.Views[0]; + const dragDocView = DocumentView.Selected()[0]; const effectiveLayoutAcl = GetEffectiveAcl(dragDocView.Document); if (effectiveLayoutAcl !== AclAdmin && effectiveLayoutAcl !== AclEdit && effectiveLayoutAcl !== AclAugment) { return false; } const containers = new Set<Doc | undefined>(); - SelectionManager.Views.forEach(v => containers.add(DocCast(v.Document.embedContainer))); + DocumentView.Selected().forEach(v => containers.add(DocCast(v.Document.embedContainer))); if (containers.size > 1) return false; const { left, top } = dragDocView.getBounds || { left: 0, top: 0 }; - const dragData = new DragManager.DocumentDragData( - SelectionManager.Views.map(dv => dv.Document), - dragDocView._props.dropAction - ); + const dragData = new DragManager.DocumentDragData(DocumentView.SelectedDocs(), dragDocView._props.dropAction); dragData.offset = dragDocView.screenToContentsTransform().transformDirection(e.x - left, e.y - top); dragData.moveDocument = dragDocView._props.moveDocument; dragData.removeDocument = dragDocView._props.removeDocument; @@ -206,7 +201,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora dragData.canEmbed = dragTitle; this._hidden = true; DragManager.StartDocumentDrag( - SelectionManager.Views.map(dv => dv.ContentDiv!), + DocumentView.Selected().map(dv => dv.ContentDiv!), dragData, e.x, e.y, @@ -223,7 +218,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora _deleteAfterIconify = false; _iconifyBatch: UndoManager.Batch | undefined; onCloseClick = (forceDeleteOrIconify: boolean | undefined) => { - const views = SelectionManager.Views.filter(v => v && v._props.renderDepth > 0); + const views = DocumentView.Selected().filter(v => v && v._props.renderDepth > 0); if (forceDeleteOrIconify === false && this._iconifyBatch) return; this._deleteAfterIconify = !!(forceDeleteOrIconify || this._iconifyBatch); let iconifyingCount = views.length; @@ -239,7 +234,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora iconView._props.removeDocument?.(iconView.Document); } }); - views.forEach(SelectionManager.DeselectView); + views.forEach(DocumentView.DeselectView); } this._iconifyBatch?.end(); this._iconifyBatch = undefined; @@ -258,53 +253,49 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora }; onMaximizeDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, () => DragManager.StartWindowDrag?.(e, [SelectionManager.Views.lastElement().Document]) ?? false, emptyFunction, this.onMaximizeClick, false, false); + setupMoveUpEvents(this, e, () => DragManager.StartWindowDrag?.(e, [DocumentView.SelectedDocs().lastElement()]) ?? false, emptyFunction, this.onMaximizeClick, false, false); e.stopPropagation(); }; onMaximizeClick = (e: any): void => { - const selectedDocs = SelectionManager.Views; + const selectedDocs = DocumentView.SelectedDocs(); if (selectedDocs.length) { if (e.ctrlKey) { // open an embedding in a new tab with Ctrl Key - CollectionDockingView.AddSplit(Doc.BestEmbedding(selectedDocs[0].Document), OpenWhereMod.right); + CollectionDockingView.AddSplit(Doc.BestEmbedding(selectedDocs[0]), OpenWhereMod.right); } else if (e.shiftKey) { // open centered in a new workspace with Shift Key - const embedding = Doc.MakeEmbedding(selectedDocs[0].Document); + const embedding = Doc.MakeEmbedding(selectedDocs[0]); embedding.embedContainer = undefined; embedding.x = -NumCast(embedding._width) / 2; embedding.y = -NumCast(embedding._height) / 2; CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([embedding], { title: 'Tab for ' + embedding.title }), OpenWhereMod.right); } else if (e.altKey) { // open same document in new tab - CollectionDockingView.ToggleSplit(selectedDocs[0].Document, OpenWhereMod.right); + CollectionDockingView.ToggleSplit(selectedDocs[0], OpenWhereMod.right); } else { - let openDoc = selectedDocs[0].Document; + let openDoc = selectedDocs[0]; if (openDoc.layout_fieldKey === 'layout_icon') { openDoc = Doc.GetEmbeddings(openDoc).find(embedding => !embedding.embedContainer) ?? Doc.MakeEmbedding(openDoc); Doc.deiconifyView(openDoc); } - LightboxView.Instance.SetLightboxDoc( - openDoc, - undefined, - selectedDocs.slice(1).map(view => view.Document) - ); + LightboxView.Instance.SetLightboxDoc(openDoc, undefined, selectedDocs.slice(1)); } } - SelectionManager.DeselectAll(); + DocumentView.DeselectAll(); }; onIconifyClick = (): void => { - SelectionManager.Views.forEach(dv => dv?.iconify()); - SelectionManager.DeselectAll(); + DocumentView.Selected().forEach(dv => dv?.iconify()); + DocumentView.DeselectAll(); }; - onSelectContainerDocClick = () => SelectionManager.Views?.[0]?.containerViewPath?.().lastElement()?.select(false); + onSelectContainerDocClick = () => DocumentView.Selected()?.[0]?.containerViewPath?.().lastElement()?.select(false); /** * sets up events when user clicks on the border radius editor */ @action onRadiusDown = (e: React.PointerEvent): void => { - SnappingManager.SetIsResizing(SelectionManager.Docs.lastElement()?.[Id]); + SnappingManager.SetIsResizing(DocumentView.SelectedDocs().lastElement()?.[Id]); this._isRounding = true; this._resizeUndo = UndoManager.StartBatch('DocDecs set radius'); setupMoveUpEvents( @@ -314,7 +305,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora const [x, y] = [this.Bounds.x + 3, this.Bounds.y + 3]; const maxDist = Math.min((this.Bounds.r - this.Bounds.x) / 2, (this.Bounds.b - this.Bounds.y) / 2); const dist = moveEv.clientX < x && moveEv.clientY < y ? 0 : Math.sqrt((moveEv.clientX - x) * (moveEv.clientX - x) + (moveEv.clientY - y) * (moveEv.clientY - y)); - SelectionManager.Docs.forEach(doc => { + DocumentView.SelectedDocs().forEach(doc => { const docMax = Math.min(NumCast(doc.width) / 2, NumCast(doc.height) / 2); const radius = Math.min(1, dist / maxDist) * docMax; // set radius based on ratio of drag distance to half diagonal distance of bounding box doc._layout_borderRounding = `${radius}px`; @@ -339,7 +330,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora e, returnFalse, // don't care about move or up event, emptyFunction, // just care about whether we get a click event - () => UndoManager.RunInBatch(() => SelectionManager.Docs.forEach(doc => Doc.toggleLockedPosition(doc)), 'toggleBackground') + () => UndoManager.RunInBatch(() => DocumentView.Selected().forEach(dv => Doc.toggleLockedPosition(dv.Document)), 'toggleBackground') ); e.stopPropagation(); }; @@ -356,7 +347,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora @action onRotateCenterDown = (e: React.PointerEvent): void => { this._isRotating = true; - const seldocview = SelectionManager.Views[0]; + const seldocview = DocumentView.Selected()[0]; setupMoveUpEvents( this, e, @@ -374,11 +365,11 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora this._isRotating = true; const rcScreen = { X: this.rotCenter[0], Y: this.rotCenter[1] }; const rotateUndo = UndoManager.StartBatch('drag rotation'); - const selectedInk = SelectionManager.Views.filter(i => i.ComponentView instanceof InkingStroke); + const selectedInk = DocumentView.Selected().filter(i => i.ComponentView instanceof InkingStroke); const centerPoint = this.rotCenter.slice(); const infos = new Map<Doc, { unrotatedDocPos: { x: number; y: number }; startRotCtr: { x: number; y: number }; accumRot: number }>(); - const seldocview = SelectionManager.Views[0]; - SelectionManager.Views.forEach(dv => { + const seldocview = DocumentView.Selected()[0]; + DocumentView.Selected().forEach(dv => { const accumRot = (NumCast(dv.Document._rotation) / 180) * Math.PI; const localRotCtr = dv.screenToViewTransform().transformPoint(rcScreen.X, rcScreen.Y); const localRotCtrOffset = [localRotCtr[0] - NumCast(dv.Document.width) / 2, localRotCtr[1] - NumCast(dv.Document.height) / 2]; @@ -387,7 +378,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora infos.set(dv.Document, { unrotatedDocPos, startRotCtr, accumRot }); }); const infoRot = (angle: number, isAbs = false) => { - SelectionManager.Views.forEach( + DocumentView.Selected().forEach( action(dv => { const { unrotatedDocPos, startRotCtr, accumRot } = infos.get(dv.Document)!; const endRotCtr = Utils.rotPt(startRotCtr.x, startRotCtr.y, isAbs ? angle : accumRot + angle); @@ -437,7 +428,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora @action onPointerDown = (e: React.PointerEvent): void => { - SnappingManager.SetIsResizing(SelectionManager.Docs.lastElement()?.[Id]); // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them + SnappingManager.SetIsResizing(DocumentView.Selected().lastElement()?.Document[Id]); // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction); e.stopPropagation(); const id = (this._resizeHdlId = e.currentTarget.className); @@ -449,7 +440,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora }; this._resizeUndo = UndoManager.StartBatch('drag resizing'); this._snapPt = { x: e.pageX, y: e.pageY }; - SelectionManager.Views.forEach(docView => CollectionFreeFormView.from(docView)?.dragStarting(false, false)); + DocumentView.Selected().forEach(docView => CollectionFreeFormView.from(docView)?.dragStarting(false, false)); }; projectDragToAspect = (e: PointerEvent, docView: DocumentView, fixedAspect: number) => { @@ -467,7 +458,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora return project([e.clientX + this._offset.x, e.clientY + this._offset.y], tl, [tl[0] + fixedAspect, tl[1] + 1]); }; onPointerMove = (e: PointerEvent): boolean => { - const first = SelectionManager.Views[0]; + const first = DocumentView.Selected()[0]; const effectiveAcl = GetEffectiveAcl(first.Document); if (!(effectiveAcl === AclAdmin || effectiveAcl === AclEdit || effectiveAcl === AclAugment)) return false; if (!first) return false; @@ -484,10 +475,10 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora !this._interactionLock && runInAction(async () => { // resize selected docs if we're not in the middle of a resize (ie, throttle input events to frame rate) this._interactionLock = true; this._snapPt = thisPt; - e.ctrlKey && (SelectionManager.Views.forEach(docView => !Doc.NativeHeight(docView.Document) && docView.toggleNativeDimensions())); - const hasFixedAspect = SelectionManager.Docs.some(this.hasFixedAspect); + e.ctrlKey && (DocumentView.Selected().forEach(docView => !Doc.NativeHeight(docView.Document) && docView.toggleNativeDimensions())); + const hasFixedAspect = DocumentView.Selected().map(dv => dv.Document).some(this.hasFixedAspect); const scaleAspect = {x:scale.x === 1 && hasFixedAspect ? scale.y : scale.x, y: scale.x !== 1 && hasFixedAspect ? scale.x : scale.y}; - SelectionManager.Views.forEach(docView => + DocumentView.Selected().forEach(docView => this.resizeView(docView, refPt, scaleAspect, { dragHdl, ctrlKey:e.ctrlKey })); // prettier-ignore await new Promise<any>(res => { setTimeout(() => { res(this._interactionLock = undefined)})}); }); // prettier-ignore @@ -526,7 +517,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora const doc = docView.Document; if (doc.isGroup) { DocListCast(doc.data) - .map(member => DocumentManager.Instance.getDocumentView(member, docView)!) + .map(member => DocumentView.getDocumentView(member, docView)!) .forEach(member => this.resizeView(member, refPt, scale, opts)); doc.xPadding = NumCast(doc.xPadding) * scale.x; doc.yPadding = NumCast(doc.yPadding) * scale.y; @@ -607,7 +598,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora this._resizeUndo?.end(); // detect layout_autoHeight gesture and apply - SelectionManager.Views.forEach(view => { + DocumentView.Selected().forEach(view => { NumCast(view.Document._height) < 20 && (view.layoutDoc._layout_autoHeight = true); }); // need to change points for resize, or else rotation/control points will fail. @@ -626,18 +617,18 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora @computed get selectionTitle(): string { - if (SelectionManager.Views.length === 1) { - const selected = SelectionManager.Views[0]; + if (DocumentView.Selected().length === 1) { + const selected = DocumentView.Selected()[0]; if (this._titleControlString.startsWith('$')) { return Field.toJavascriptString(selected.Document[this._titleControlString.substring(1)] as FieldType) || '-unset-'; } return this._accumulatedTitle; } - return SelectionManager.Views.length > 1 ? '-multiple-' : '-unset-'; + return DocumentView.Selected().length > 1 ? '-multiple-' : '-unset-'; } @computed get rotCenter() { - const lastView = SelectionManager.Views.lastElement(); + const lastView = DocumentView.Selected().lastElement(); if (lastView) { const invXf = lastView.screenToContentsTransform().inverse(); const seldoc = lastView.layoutDoc; @@ -649,7 +640,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora render() { const { b, r, x, y } = this.Bounds; - const seldocview = SelectionManager.Views.lastElement(); + const seldocview = DocumentView.Selected().lastElement(); if (SnappingManager.IsDragging || r - x < 1 || x === Number.MAX_VALUE || !seldocview || this._hidden || isNaN(r) || isNaN(b) || isNaN(x) || isNaN(y)) { setTimeout( action(() => { @@ -678,7 +669,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora hideDecorations || seldocview._props.hideOpenButton || seldocview.Document.layout_hideOpenButton || - SelectionManager.Views.some(docView => docView.Document._dragOnlyWithinContainer || docView.Document.isGroup || docView.Document.layout_hideOpenButton) || + DocumentView.Selected().some(docView => docView.Document._dragOnlyWithinContainer || docView.Document.isGroup || docView.Document.layout_hideOpenButton) || this._isRounding || this._isRotating; const hideDeleteButton = @@ -688,7 +679,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora this._isRotating || seldocview._props.hideDeleteButton || seldocview.Document.hideDeleteButton || - SelectionManager.Views.some(docView => { + DocumentView.Selected().some(docView => { const collectionAcl = docView.containerViewPath?.()?.lastElement() ? GetEffectiveAcl(docView.containerViewPath?.().lastElement().dataDoc) : AclEdit; return collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.Document) !== AclAdmin; }); @@ -703,7 +694,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora const bounds = this.ClippedBounds; const useLock = bounds.r - bounds.x > 135; const useRotation = !hideResizers && seldocview.Document.type !== DocumentType.EQUATION && CollectionFreeFormDocumentView.from(seldocview); // when do we want an object to not rotate? - const rotation = SelectionManager.Views.length === 1 ? seldocview.screenToContentsTransform().inverse().RotateDeg : 0; + const rotation = DocumentView.Selected().length === 1 ? seldocview.screenToContentsTransform().inverse().RotateDeg : 0; // Radius constants const useRounding = seldocview.ComponentView instanceof ImageBox || seldocview.ComponentView instanceof FormattedTextBox || seldocview.ComponentView instanceof CollectionFreeFormView; @@ -773,7 +764,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora ); const centery = hideTitle ? 0 : this._titleHeight; const transformOrigin = `${50}% calc(50% + ${centery / 2}px)`; - const freeformDoc = SelectionManager.Views.some(v => CollectionFreeFormDocumentView.from(v)); + const freeformDoc = DocumentView.Selected().some(v => CollectionFreeFormDocumentView.from(v)); return ( <div className="documentDecorations" style={{ display: this._showNothing && !freeformDoc ? 'none' : undefined }}> <div @@ -786,7 +777,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora transformOrigin, background: SnappingManager.ShiftKey ? undefined : 'yellow', pointerEvents: SnappingManager.ShiftKey || SnappingManager.IsResizing ? 'none' : 'all', - display: SelectionManager.Views.length <= 1 || hideDecorations ? 'none' : undefined, + display: DocumentView.Selected().length <= 1 || hideDecorations ? 'none' : undefined, transform: `rotate(${rotation}deg)`, }} onPointerDown={this.onBackgroundDown} @@ -843,7 +834,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora style={{ transform: `translate(${-this._resizeBorderWidth / 2 + 10}px, ${this._resizeBorderWidth + bounds.b - bounds.y + this._titleHeight}px) `, }}> - <DocumentButtonBar views={() => SelectionManager.Views} /> + <DocumentButtonBar views={() => DocumentView.Selected()} /> </div> )} </div> |