diff options
Diffstat (limited to 'src/client/views/DocumentDecorations.tsx')
-rw-r--r-- | src/client/views/DocumentDecorations.tsx | 128 |
1 files changed, 62 insertions, 66 deletions
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index e9c4d9cc5..2a44a9739 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -10,7 +10,6 @@ import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Field, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, DocData } from '../../fields/DocSymbols'; import { InkField } from '../../fields/InkField'; -import { RichTextField } from '../../fields/RichTextField'; import { ScriptField } from '../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { GetEffectiveAcl } from '../../fields/util'; @@ -33,7 +32,9 @@ import { CollectionFreeFormView } from './collections/collectionFreeForm'; import { Colors } from './global/globalEnums'; import { DocumentView, OpenWhereMod } from './nodes/DocumentView'; import { ImageBox } from './nodes/ImageBox'; +import { KeyValueBox } from './nodes/KeyValueBox'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; +import { identity } from 'lodash'; interface DocumentDecorationsProps { PanelWidth: number; @@ -57,7 +58,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora @observable _showNothing = true; @observable private _accumulatedTitle = ''; - @observable private _titleControlString: string = '#title'; + @observable private _titleControlString: string = '$title'; @observable private _editingTitle = false; @observable private _hidden = false; @observable private _isRotating: boolean = false; @@ -73,11 +74,18 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora DocumentDecorations.Instance = this; document.addEventListener('pointermove', // show decorations whenever pointer moves outside of selection bounds. action(e => { + let inputting = false; + if (this._titleControlString.startsWith('$')) { + const titleFieldKey = this._titleControlString.substring(1); + if (SelectionManager.Views[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)); - (this._showNothing = !(this.Bounds.x !== Number.MAX_VALUE && // + (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 ))); })); // prettier-ignore @@ -111,9 +119,9 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora @action titleBlur = () => { - if (this._accumulatedTitle.startsWith('#') || this._accumulatedTitle.startsWith('=')) { + if (this._accumulatedTitle.startsWith('$')) { this._titleControlString = this._accumulatedTitle; - } else if (this._titleControlString.startsWith('#')) { + } else if (this._titleControlString.startsWith('$')) { if (this._accumulatedTitle.startsWith('-->#')) { SelectionManager.Docs.forEach(doc => (doc[DocData].onViewMounted = ScriptField.MakeScript(`updateTagsCollection(this)`))); } @@ -124,33 +132,8 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora SelectionManager.Views.forEach(d => { if (titleFieldKey === 'title') { d.dataDoc.title_custom = !this._accumulatedTitle.startsWith('-'); - if (StrCast(d.Document.title).startsWith('@') && !this._accumulatedTitle.startsWith('@')) { - Doc.RemFromMyPublished(d.Document); - } - if (!StrCast(d.Document.title).startsWith('@') && this._accumulatedTitle.startsWith('@')) { - Doc.AddToMyPublished(d.Document); - } - } - //@ts-ignore - const titleField = +this._accumulatedTitle == this._accumulatedTitle ? +this._accumulatedTitle : this._accumulatedTitle; - - if (titleField.toString().startsWith('<this>')) { - const title = titleField.toString().replace(/<this>\.?/, ''); - const curKey = Doc.LayoutFieldKey(d.Document); - if (curKey !== title) { - if (title) { - if (d.dataDoc[title] === undefined || d.dataDoc[title] instanceof RichTextField || typeof d.dataDoc[title] === 'string') { - d.Document.layout_fieldKey = `layout_${title}`; - d.Document[`layout_${title}`] = FormattedTextBox.LayoutString(title); - d.Document[`${title}_nativeWidth`] = d.Document[`${title}_nativeHeight`] = 0; - } - } else { - d.Document.layout_fieldKey = undefined; - } - } - } else { - Doc.SetInPlace(d.Document, titleFieldKey, titleField, true); } + KeyValueBox.SetField(d.Document, titleFieldKey, this._accumulatedTitle); }), 'edit title' ); @@ -181,7 +164,8 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora e => this.onBackgroundMove(true, e), emptyFunction, action(e => { - !this._editingTitle && (this._accumulatedTitle = this._titleControlString.startsWith('#') ? this.selectionTitle : this._titleControlString); + const selected = SelectionManager.Views.length === 1 ? SelectionManager.Docs[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); }) @@ -323,7 +307,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora SelectionManager.Docs.map(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`; + doc._layout_borderRounding = `${radius}px`; }); return false; }, @@ -354,8 +338,8 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora const newloccentern = seldocview.screenToContentsTransform().transformPoint(rotCenter[0], rotCenter[1]); const newlocenter = [newloccentern[0] - NumCast(seldocview.layoutDoc._width) / 2, newloccentern[1] - NumCast(seldocview.layoutDoc._height) / 2]; const final = Utils.rotPt(newlocenter[0], newlocenter[1], -(NumCast(seldocview.Document._rotation) / 180) * Math.PI); - seldocview.Document.rotation_centerX = final.x / NumCast(seldocview.layoutDoc._width); - seldocview.Document.rotation_centerY = final.y / NumCast(seldocview.layoutDoc._height); + seldocview.Document._rotation_centerX = final.x / NumCast(seldocview.layoutDoc._width); + seldocview.Document._rotation_centerY = final.y / NumCast(seldocview.layoutDoc._height); }; @action @@ -368,8 +352,10 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora (e: PointerEvent, down: number[], delta: number[]) => // return false to keep getting events this.setRotateCenter(seldocview, [this.rotCenter[0] + delta[0], this.rotCenter[1] + delta[1]]) as any as boolean, action(e => (this._isRotating = false)), // upEvent - action(e => (seldocview.Document.rotation_centerX = seldocview.Document.rotation_centerY = 0)) + action(e => (seldocview.Document._rotation_centerX = seldocview.Document._rotation_centerY = 0)), + true ); // prettier-ignore + e.stopPropagation(); }; @action @@ -441,9 +427,13 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora SnappingManager.SetIsResizing(SelectionManager.Docs.lastElement()); // 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(); - this._resizeHdlId = e.currentTarget.className; + const id = (this._resizeHdlId = e.currentTarget.className); + const pad = id.includes('Left') || id.includes('Right') ? Number(getComputedStyle(e.target as any).width.replace('px', '')) / 2 : 0; const bounds = e.currentTarget.getBoundingClientRect(); - this._offset = { x: this._resizeHdlId.toLowerCase().includes('left') ? bounds.right - e.clientX : bounds.left - e.clientX, y: this._resizeHdlId.toLowerCase().includes('top') ? bounds.bottom - e.clientY : bounds.top - e.clientY }; + this._offset = { + x: id.toLowerCase().includes('left') ? bounds.right - e.clientX - pad : bounds.left - e.clientX + pad, // + y: id.toLowerCase().includes('top') ? bounds.bottom - e.clientY - pad : bounds.top - e.clientY + pad, + }; this._resizeUndo = UndoManager.StartBatch('drag resizing'); this._snapPt = { x: e.pageX, y: e.pageY }; SelectionManager.Views.forEach(docView => docView.CollectionFreeFormView?.dragStarting(false, false)); @@ -514,7 +504,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora // // determines if anything being dragged directly or via a group has a fixed aspect ratio (in which case we resize uniformly) // - hasFixedAspect = (doc: Doc): boolean => (doc.isGroup ? DocListCast(doc.data).some(this.hasFixedAspect) : !BoolCast(doc.layout_nativeDimEditable)); + hasFixedAspect = (doc: Doc): boolean => (doc.isGroup ? DocListCast(doc.data).some(this.hasFixedAspect) : !BoolCast(doc._layout_nativeDimEditable)); // // resize a single DocumentView about the specified reference point, possibly setting/updating the native dimensions of the Doc @@ -533,9 +523,9 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora const [initWidth, initHeight] = [NumCast(doc._width, 1), NumCast(doc._height)]; const modifyNativeDim = - (opts.ctrlKey && doc.layout_nativeDimEditable) || // e.g., PDF or web page - (doc.layout_reflowHorizontal && opts.dragHdl !== 'bottom' && opts.dragHdl !== 'top') || // eg rtf or some web pages - (doc.layout_reflowVertical && (opts.dragHdl === 'bottom' || opts.dragHdl === 'top' || opts.ctrlKey)); // eg rtf, web, pdf + (opts.ctrlKey && doc._layout_nativeDimEditable) || // e.g., PDF or web page + (doc._layout_reflowHorizontal && opts.dragHdl !== 'bottom' && opts.dragHdl !== 'top') || // eg rtf or some web pages + (doc._layout_reflowVertical && (opts.dragHdl === 'bottom' || opts.dragHdl === 'top' || opts.ctrlKey)); // eg rtf, web, pdf if (nwidth && nheight && !modifyNativeDim) { // eg., dragging right resizer on PDF -- enforce native dimensions because not expliclty overridden with ctrl or bottom resize drag scale.x === 1 ? (scale.x = scale.y) : (scale.y = scale.x); @@ -545,7 +535,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora const setData = Doc.NativeWidth(doc[DocData]) === doc.nativeWidth; doc.nativeWidth = scale.x * Doc.NativeWidth(doc); if (setData) Doc.SetNativeWidth(doc[DocData], NumCast(doc.nativeWidth)); - if (doc.layout_reflowVertical && !NumCast(doc.nativeHeight)) { + if (doc._layout_reflowVertical && !NumCast(doc.nativeHeight)) { doc._nativeHeight = (initHeight / initWidth) * nwidth; // initializes the nativeHeight for a PDF } } @@ -562,7 +552,13 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora doc.y = NumCast(doc.y) + deltaY; doc._layout_modificationDate = new DateField(); - scale.y !== 1 && (doc._layout_autoHeight = undefined); + if (scale.y !== 1) { + docView.layoutDoc._layout_autoHeight = undefined; + if (docView.layoutDoc._layout_autoHeight) { + // if autoHeight is still on because of a prototype + docView.layoutDoc._layout_autoHeight = false; // then don't inherit, but explicitly set it to false + } + } } }; @@ -597,7 +593,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora this._resizeUndo?.end(); // detect layout_autoHeight gesture and apply - SelectionManager.Docs.forEach(doc => NumCast(doc._height) < 20 && (doc._layout_autoHeight = true)); + SelectionManager.Views.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. this._inkDragDocs .map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] })) @@ -616,11 +612,8 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora get selectionTitle(): string { if (SelectionManager.Views.length === 1) { const selected = SelectionManager.Views[0]; - if (this._titleControlString.startsWith('=')) { - return ScriptField.MakeFunction(this._titleControlString.substring(1), { doc: Doc.name })?.script.run({ self: selected.Document, this: selected.layoutDoc }, console.log).result?.toString() || ''; - } - if (this._titleControlString.startsWith('#')) { - return Field.toString(selected.Document[this._titleControlString.substring(1)] as Field) || '-unset-'; + if (this._titleControlString.startsWith('$')) { + return Field.toJavascriptString(selected.Document[this._titleControlString.substring(1)] as Field) || '-unset-'; } return this._accumulatedTitle; } @@ -632,7 +625,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora if (lastView) { const invXf = lastView.screenToContentsTransform().inverse(); const seldoc = lastView.layoutDoc; - const loccenter = Utils.rotPt(NumCast(seldoc.rotation_centerX) * NumCast(seldoc._width), NumCast(seldoc.rotation_centerY) * NumCast(seldoc._height), invXf.Rotate); + const loccenter = Utils.rotPt(NumCast(seldoc._rotation_centerX) * NumCast(seldoc._width), NumCast(seldoc._rotation_centerY) * NumCast(seldoc._height), invXf.Rotate); return invXf.transformPoint(loccenter.x + NumCast(seldoc._width) / 2, loccenter.y + NumCast(seldoc._height) / 2); } return this._rotCenter; @@ -725,21 +718,24 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora ) : null; const titleArea = this._editingTitle ? ( - <input - ref={this._keyinput} - className="documentDecorations-title" - type="text" - name="dynbox" - autoComplete="on" - value={hideTitle ? '' : this._accumulatedTitle} - onBlur={action((e: React.FocusEvent) => { - this._editingTitle = false; - !hideTitle && this.titleBlur(); - })} - onChange={action(e => !hideTitle && (this._accumulatedTitle = e.target.value))} - onKeyDown={hideTitle ? emptyFunction : this.titleEntered} - onPointerDown={e => e.stopPropagation()} - /> + <> + {r - x < 150 ? null : <span>{this._titleControlString + ':'}</span>} + <input + ref={this._keyinput} + className="documentDecorations-title" + type="text" + name="dynbox" + autoComplete="on" + value={hideTitle ? '' : this._accumulatedTitle} + onBlur={action((e: React.FocusEvent) => { + this._editingTitle = false; + this.titleBlur(); + })} + onChange={action(e => !hideTitle && (this._accumulatedTitle = e.target.value))} + onKeyDown={hideTitle ? emptyFunction : this.titleEntered} + onPointerDown={e => e.stopPropagation()} + /> + </> ) : ( <div className="documentDecorations-title" key="title"> {hideTitle ? null : ( |