diff options
author | bobzel <zzzman@gmail.com> | 2024-03-28 11:38:56 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2024-03-28 11:38:56 -0400 |
commit | 1b592f74a7df8f6dd7b2881032725f26aedff403 (patch) | |
tree | 900179f9218af09932b061b55c5153fa9575f13e /src | |
parent | 52bd492747cf169df7bcdecdbdbb353d45b19734 (diff) |
fixed keyvaluebox to show props document, never the doc in the fieldKey slot. changed computedFIelds to do mobx caching. changed text boxes to do updating from templates based on a fieldKey_autoUpdate flag combined with modification timestamps. enabled comparison box to work with text fields in addition to docs.
Diffstat (limited to 'src')
-rw-r--r-- | src/client/util/Scripting.ts | 9 | ||||
-rw-r--r-- | src/client/views/InkControlPtHandles.tsx | 85 | ||||
-rw-r--r-- | src/client/views/PropertiesButtons.tsx | 4 | ||||
-rw-r--r-- | src/client/views/nodes/ComparisonBox.tsx | 6 | ||||
-rw-r--r-- | src/client/views/nodes/KeyValueBox.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBox.tsx | 31 | ||||
-rw-r--r-- | src/fields/Doc.ts | 2 | ||||
-rw-r--r-- | src/fields/ScriptField.ts | 22 |
8 files changed, 90 insertions, 71 deletions
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index f5e162d16..31222aa50 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -88,15 +88,10 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an } const result = compiledFunction.apply(thisParam, params).apply(thisParam, argsArray); - if (batch) { - batch.end(); - } - + batch?.end(); return { success: true, result }; } catch (error) { - if (batch) { - batch.end(); - } + batch?.end(); onError?.(script + ' ' + error); return { success: false, error, result: errorVal }; } diff --git a/src/client/views/InkControlPtHandles.tsx b/src/client/views/InkControlPtHandles.tsx index 31b13d2c8..01d52135a 100644 --- a/src/client/views/InkControlPtHandles.tsx +++ b/src/client/views/InkControlPtHandles.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { action, observable } from 'mobx'; +import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import { Doc } from '../../fields/Doc'; import { ControlPoint, InkData, PointData } from '../../fields/InkField'; @@ -13,6 +13,7 @@ import { Colors } from './global/globalEnums'; import { InkingStroke } from './InkingStroke'; import { InkStrokeProperties } from './InkStrokeProperties'; import { SnappingManager } from '../util/SnappingManager'; +import { ObservableReactComponent } from './ObservableReactComponent'; export interface InkControlProps { inkDoc: Doc; @@ -24,10 +25,15 @@ export interface InkControlProps { } @observer -export class InkControlPtHandles extends React.Component<InkControlProps> { +export class InkControlPtHandles extends ObservableReactComponent<InkControlProps> { @observable private _overControl = -1; get docView() { - return this.props.inkView.DocumentView?.(); + return this._props.inkView.DocumentView?.(); + } + + constructor(props: InkControlProps) { + super(props); + makeObservable(this); } componentDidMount() { @@ -42,51 +48,51 @@ export class InkControlPtHandles extends React.Component<InkControlProps> { */ @action onControlDown = (e: React.PointerEvent, controlIndex: number): void => { - const ptFromScreen = this.props.inkView.ptFromScreen; + const ptFromScreen = this._props.inkView.ptFromScreen; if (ptFromScreen) { const order = controlIndex % 4; - const handleIndexA = ((order === 3 ? controlIndex - 1 : controlIndex - 2) + this.props.inkCtrlPoints.length) % this.props.inkCtrlPoints.length; - const handleIndexB = (order === 3 ? controlIndex + 2 : controlIndex + 1) % this.props.inkCtrlPoints.length; - const brokenIndices = Cast(this.props.inkDoc.brokenInkIndices, listSpec('number')); + const handleIndexA = ((order === 3 ? controlIndex - 1 : controlIndex - 2) + this._props.inkCtrlPoints.length) % this._props.inkCtrlPoints.length; + const handleIndexB = (order === 3 ? controlIndex + 2 : controlIndex + 1) % this._props.inkCtrlPoints.length; + const brokenIndices = Cast(this._props.inkDoc.brokenInkIndices, listSpec('number')); const wasSelected = InkStrokeProperties.Instance._currentPoint === controlIndex; if (!wasSelected) InkStrokeProperties.Instance._currentPoint = -1; - const origInk = this.props.inkCtrlPoints.slice(); + const origInk = this._props.inkCtrlPoints.slice(); setupMoveUpEvents( this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('drag ink ctrl pt'); + if (!this._props.inkView.controlUndo) this._props.inkView.controlUndo = UndoManager.StartBatch('drag ink ctrl pt'); const inkMoveEnd = ptFromScreen({ X: delta[0], Y: delta[1] }); const inkMoveStart = ptFromScreen({ X: 0, Y: 0 }); this.docView && InkStrokeProperties.Instance.moveControlPtHandle(this.docView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex, origInk); return false; }), action(() => { - if (this.props.inkView.controlUndo && this.docView) { + if (this._props.inkView.controlUndo && this.docView) { InkStrokeProperties.Instance.snapControl(this.docView, controlIndex); } - this.props.inkView.controlUndo?.end(); - this.props.inkView.controlUndo = undefined; + this._props.inkView.controlUndo?.end(); + this._props.inkView.controlUndo = undefined; UndoManager.FilterBatches(['data', 'x', 'y', 'width', 'height']); }), action((e: PointerEvent, doubleTap: boolean | undefined) => { - const equivIndex = controlIndex === 0 ? this.props.inkCtrlPoints.length - 1 : controlIndex === this.props.inkCtrlPoints.length - 1 ? 0 : controlIndex; + const equivIndex = controlIndex === 0 ? this._props.inkCtrlPoints.length - 1 : controlIndex === this._props.inkCtrlPoints.length - 1 ? 0 : controlIndex; if (doubleTap || e.button === 2) { if (!brokenIndices?.includes(equivIndex) && !brokenIndices?.includes(controlIndex)) { if (brokenIndices) brokenIndices.push(controlIndex); - else this.props.inkDoc.brokenInkIndices = new List<number>([controlIndex]); + else this._props.inkDoc.brokenInkIndices = new List<number>([controlIndex]); } else { if (brokenIndices?.includes(equivIndex)) { - if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('make smooth'); + if (!this._props.inkView.controlUndo) this._props.inkView.controlUndo = UndoManager.StartBatch('make smooth'); this.docView && InkStrokeProperties.Instance.snapHandleTangent(this.docView, equivIndex, handleIndexA, handleIndexB); } if (equivIndex !== controlIndex && brokenIndices?.includes(controlIndex)) { - if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('make smooth'); + if (!this._props.inkView.controlUndo) this._props.inkView.controlUndo = UndoManager.StartBatch('make smooth'); this.docView && InkStrokeProperties.Instance.snapHandleTangent(this.docView, controlIndex, handleIndexA, handleIndexB); } } - this.props.inkView.controlUndo?.end(); - this.props.inkView.controlUndo = undefined; + this._props.inkView.controlUndo?.end(); + this._props.inkView.controlUndo = undefined; } this.changeCurrPoint(controlIndex); }), @@ -126,14 +132,14 @@ export class InkControlPtHandles extends React.Component<InkControlProps> { render() { // Accessing the current ink's data and extracting all control points. - const scrData = this.props.screenCtrlPoints; + const scrData = this._props.screenCtrlPoints; const sreenCtrlPoints: ControlPoint[] = []; for (let i = 0; i <= scrData.length - 4; i += 4) { sreenCtrlPoints.push({ ...scrData[i], I: i }); sreenCtrlPoints.push({ ...scrData[i + 3], I: i + 3 }); } - const inkData = this.props.inkCtrlPoints; + const inkData = this._props.inkCtrlPoints; const inkCtrlPts: ControlPoint[] = []; for (let i = 0; i <= inkData.length - 4; i += 4) { inkCtrlPts.push({ ...inkData[i], I: i }); @@ -141,23 +147,23 @@ export class InkControlPtHandles extends React.Component<InkControlProps> { } const closed = InkingStroke.IsClosed(inkData); - const nearestScreenPt = this.props.nearestScreenPt(); + const nearestScreenPt = this._props.nearestScreenPt(); const TagType = (broken?: boolean) => (broken ? 'rect' : 'circle'); const hdl = (control: { X: number; Y: number; I: number }, scale: number, color: string) => { - const broken = Cast(this.props.inkDoc.brokenInkIndices, listSpec('number'))?.includes(control.I); + const broken = Cast(this._props.inkDoc.brokenInkIndices, listSpec('number'))?.includes(control.I); const Tag = TagType((control.I === 0 || control.I === inkData.length - 1) && !closed) as keyof JSX.IntrinsicElements; return ( <Tag key={control.I.toString() + scale} - x={control.X - this.props.screenSpaceLineWidth * 2 * scale} - y={control.Y - this.props.screenSpaceLineWidth * 2 * scale} + x={control.X - this._props.screenSpaceLineWidth * 2 * scale} + y={control.Y - this._props.screenSpaceLineWidth * 2 * scale} cx={control.X} cy={control.Y} - r={this.props.screenSpaceLineWidth * 2 * scale} - opacity={this.props.inkView.controlUndo ? 0.35 : 1} - height={this.props.screenSpaceLineWidth * 4 * scale} - width={this.props.screenSpaceLineWidth * 4 * scale} - strokeWidth={this.props.screenSpaceLineWidth / 2} + r={this._props.screenSpaceLineWidth * 2 * scale} + opacity={this._props.inkView.controlUndo ? 0.35 : 1} + height={this._props.screenSpaceLineWidth * 4 * scale} + width={this._props.screenSpaceLineWidth * 4 * scale} + strokeWidth={this._props.screenSpaceLineWidth / 2} stroke={Colors.MEDIUM_BLUE} fill={broken ? Colors.MEDIUM_BLUE : color} onPointerDown={(e: React.PointerEvent) => this.onControlDown(e, control.I)} @@ -170,7 +176,7 @@ export class InkControlPtHandles extends React.Component<InkControlProps> { }; return ( <svg> - {!nearestScreenPt ? null : <circle key={'npt'} cx={nearestScreenPt.X} cy={nearestScreenPt.Y} r={this.props.screenSpaceLineWidth * 2} fill={'#00007777'} stroke={'#00007777'} strokeWidth={0} pointerEvents="none" />} + {!nearestScreenPt ? null : <circle key={'npt'} cx={nearestScreenPt.X} cy={nearestScreenPt.Y} r={this._props.screenSpaceLineWidth * 2} fill={'#00007777'} stroke={'#00007777'} strokeWidth={0} pointerEvents="none" />} {sreenCtrlPoints.map(control => hdl(control, this._overControl !== control.I ? 1 : 3 / 2, Colors.WHITE))} </svg> ); @@ -185,10 +191,15 @@ export interface InkEndProps { endPt: () => PointData; } @observer -export class InkEndPtHandles extends React.Component<InkEndProps> { +export class InkEndPtHandles extends ObservableReactComponent<InkEndProps> { @observable _overStart: boolean = false; @observable _overEnd: boolean = false; + constructor(props: InkEndProps) { + super(props); + makeObservable(this); + } + _throttle = 0; // need to throttle dragging since the position may change when the control points change. this allows the stroke to settle so that we don't get increasingly bad jitter @action dragRotate = (e: React.PointerEvent, pt1: () => { X: number; Y: number }, pt2: () => { X: number; Y: number }) => { @@ -198,7 +209,7 @@ export class InkEndPtHandles extends React.Component<InkEndProps> { e, action(e => { if (this._throttle++ % 2 !== 0) return false; - if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('stretch ink'); + if (!this._props.inkView.controlUndo) this._props.inkView.controlUndo = UndoManager.StartBatch('stretch ink'); // compute stretch factor by finding scaling along axis between start and end points const p1 = pt1(); const p2 = pt2(); @@ -216,8 +227,8 @@ export class InkEndPtHandles extends React.Component<InkEndProps> { }), action(() => { SnappingManager.SetIsDragging(false); - this.props.inkView.controlUndo?.end(); - this.props.inkView.controlUndo = undefined; + this._props.inkView.controlUndo?.end(); + this._props.inkView.controlUndo = undefined; UndoManager.FilterBatches(['stroke', 'x', 'y', 'width', 'height']); }), returnFalse @@ -230,7 +241,7 @@ export class InkEndPtHandles extends React.Component<InkEndProps> { key={key} cx={pt.X} cy={pt.Y} - r={this.props.screenSpaceLineWidth * 2} + r={this._props.screenSpaceLineWidth * 2} fill={this._overStart ? '#aaaaaa' : '#99999977'} stroke={'#00007777'} strokeWidth={0} @@ -242,8 +253,8 @@ export class InkEndPtHandles extends React.Component<InkEndProps> { ); return ( <svg> - {hdl('start', this.props.startPt(), e => this.dragRotate(e, this.props.startPt, this.props.endPt))} - {hdl('end', this.props.endPt(), e => this.dragRotate(e, this.props.endPt, this.props.startPt))} + {hdl('start', this._props.startPt(), e => this.dragRotate(e, this._props.startPt, this._props.endPt))} + {hdl('end', this._props.endPt(), e => this.dragRotate(e, this._props.endPt, this._props.startPt))} </svg> ); } diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 02f288a68..517a80d63 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -87,7 +87,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { containerDoc._isLightbox = !containerDoc._isLightbox; //containerDoc._xPadding = containerDoc._yPadding = containerDoc._isLightbox ? 10 : undefined; const containerContents = DocListCast(dv.dataDoc[Doc.LayoutFieldKey(containerDoc)]); - //dv.Docuemnt.onClick = ScriptField.MakeScript('{self.data = undefined; documentView.select(false)}', { documentView: 'any' }); + //dv.Docuemnt.onClick = ScriptField.MakeScript('{this.data = undefined; documentView.select(false)}', { documentView: 'any' }); containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.link_displayLine = false))); }); } @@ -219,7 +219,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { // containerDoc._isLightbox = !containerDoc._isLightbox; // //containerDoc._xPadding = containerDoc._yPadding = containerDoc._isLightbox ? 10 : undefined; // const containerContents = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]); - // //dv.Document.onClick = ScriptField.MakeScript('{self.data = undefined; documentView.select(false)}', { documentView: 'any' }); + // //dv.Document.onClick = ScriptField.MakeScript('{this.data = undefined; documentView.select(false)}', { documentView: 'any' }); // containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.layout_linkDisplay = false))); // }); // } diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 59d99b371..9ffdc350d 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -69,8 +69,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() action((e, doubleTap) => { if (doubleTap) { this._isAnyChildContentActive = true; - if (!this.dataDoc[this.fieldKey + '_1']) this.dataDoc[this.fieldKey + '_1'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc); - if (!this.dataDoc[this.fieldKey + '_2']) this.dataDoc[this.fieldKey + '_2'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc); + if (!this.dataDoc[this.fieldKey + '_1'] && !this.dataDoc[this.fieldKey]) this.dataDoc[this.fieldKey + '_1'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc); + if (!this.dataDoc[this.fieldKey + '_2'] && !this.dataDoc[this.fieldKey + '_alternate']) this.dataDoc[this.fieldKey + '_2'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc); } }), false, @@ -131,8 +131,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() return false; }; - whenChildContentsActiveChanged = action((isActive: boolean) => (this._isAnyChildContentActive = isActive)); - closeDown = (e: React.PointerEvent, which: string) => { setupMoveUpEvents( this, diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 78e4435ce..31a2367fc 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -55,7 +55,7 @@ export class KeyValueBox extends ObservableReactComponent<FieldViewProps> { @observable _splitPercentage = 50; get fieldDocToLayout() { - return this._props.fieldKey ? DocCast(this._props.Document[this._props.fieldKey], DocCast(this._props.Document)) : this._props.Document; + return DocCast(this._props.Document); } @action diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index d25101844..f06e5fad0 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -21,7 +21,7 @@ import { List } from '../../../../fields/List'; import { PrefetchProxy } from '../../../../fields/Proxy'; import { RichTextField } from '../../../../fields/RichTextField'; import { ComputedField } from '../../../../fields/ScriptField'; -import { BoolCast, Cast, DocCast, FieldValue, NumCast, RTFCast, ScriptCast, StrCast } from '../../../../fields/Types'; +import { BoolCast, Cast, DateCast, DocCast, FieldValue, NumCast, RTFCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util'; import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, DivWidth, emptyFunction, numberRange, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils'; import { gptAPICall, GPTCallType } from '../../../apis/gpt/GPT'; @@ -349,6 +349,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB const prevData = Cast(this.layoutDoc[this.fieldKey], RichTextField, null); // the actual text in the text box const templateData = this.Document !== this.layoutDoc ? prevData : undefined; // the default text stored in a layout template const protoData = Cast(Cast(dataDoc.proto, Doc, null)?.[this.fieldKey], RichTextField, null); // the default text inherited from a prototype + const layoutData = this.layoutDoc.isTemplateDoc ? Cast(this.layoutDoc[this.fieldKey], RichTextField, null) : undefined; // the default text inherited from a prototype const effectiveAcl = GetEffectiveAcl(dataDoc); const removeSelection = (json: string | undefined) => json?.replace(/"selection":.*/, ''); @@ -369,22 +370,20 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB if (this._applyingChange !== this.fieldKey && (force || textChange || removeSelection(newJson) !== removeSelection(prevData?.Data))) { this._applyingChange = this.fieldKey; textChange && (dataDoc[this.fieldKey + '_modificationDate'] = new DateField(new Date(Date.now()))); - if ((!prevData && !protoData) || newText || (!newText && !protoData)) { + if ((!prevData && !protoData && !layoutData) || newText || (!newText && !protoData && !layoutData)) { // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended) if (force || ((this._finishingLink || this._props.isContentActive() || this._inDrop) && (textChange || removeSelection(newJson) !== removeSelection(prevData?.Data)))) { const numstring = NumCast(dataDoc[this.fieldKey], null); - dataDoc[this.fieldKey] = numstring !== undefined ? Number(newText) : newText || DocCast(dataDoc.proto)?.[this.fieldKey] === undefined ? new RichTextField(newJson, newText) : undefined; - + dataDoc[this.fieldKey] = + numstring !== undefined ? Number(newText) : newText || (DocCast(dataDoc.proto)?.[this.fieldKey] === undefined && this.layoutDoc[this.fieldKey] === undefined) ? new RichTextField(newJson, newText) : undefined; textChange && ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.Document, text: newText }); this._applyingChange = ''; // turning this off here allows a Doc to retrieve data from template if noTemplate below is changed to false - dataDoc[this.fieldKey + '_noTemplate'] = newText ? true : false; // mark the data field as being split from the template if it has been edited unchanged = false; } } else { // if we've deleted all the text in a note driven by a template, then restore the template data dataDoc[this.fieldKey] = undefined; - this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse((protoData || prevData).Data))); - dataDoc[this.fieldKey + '_noTemplate'] = undefined; // mark the data field as not being split from any template it might have + this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse((layoutData ?? protoData ?? prevData).Data))); ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, text: newText }); unchanged = false; } @@ -958,6 +957,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB const options = cm.findByDescription('Options...'); const optionItems = options && 'subitems' in options ? options.subitems : []; + optionItems.push({ description: `Toggle auto update from template`, event: () => (this.dataDoc[this.fieldKey + '_autoUpdate'] = !this.dataDoc[this.fieldKey + '_autoUpdate']), icon: 'star' }); optionItems.push({ description: `Generate Dall-E Image`, event: () => this.generateImage(), icon: 'star' }); optionItems.push({ description: `Ask GPT-3`, event: () => this.askGPT(), icon: 'lightbulb' }); this._props.renderDepth && @@ -1244,9 +1244,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB ); this._disposers.editorState = reaction( () => { - const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc?.proto), this.fieldKey) ? DocCast(this.layoutDoc?.proto) : this?.dataDoc; - const whichDoc = !this.dataDoc || !this.layoutDoc ? undefined : dataDoc?.[this.fieldKey + '_noTemplate'] || !this.layoutDoc[this.fieldKey] ? dataDoc : this.layoutDoc; - return !whichDoc ? undefined : { data: Cast(whichDoc[this.fieldKey], RichTextField, null), str: Field.toString(DocCast(whichDoc[this.fieldKey]) ?? StrCast(whichDoc[this.fieldKey])) }; + const protoData = DocCast(this.dataDoc.proto)?.[this.fieldKey]; + const dataData = this.dataDoc[this.fieldKey]; + const layoutData = Doc.AreProtosEqual(this.layoutDoc, this.dataDoc) ? undefined : this.layoutDoc[this.fieldKey]; + const dataTime = dataData ? DateCast(this.dataDoc[this.fieldKey + '_modificationDate'])?.date.getTime() ?? 0 : 0; + const layoutTime = layoutData && this.dataDoc[this.fieldKey + '_autoUpdate'] ? DateCast(DocCast(this.layoutDoc)[this.fieldKey + '_modificationDate'])?.date.getTime() ?? 0 : 0; + const protoTime = protoData && this.dataDoc[this.fieldKey + '_autoUpdate'] ? DateCast(DocCast(this.dataDoc.proto)[this.fieldKey + '_modificationDate'])?.date.getTime() ?? 0 : 0; + const recentData = dataTime >= layoutTime ? (protoTime >= dataTime ? protoData : dataData) : layoutTime >= protoTime ? layoutData : protoData; + const whichData = recentData ?? (this.layoutDoc.isTemplateDoc ? layoutData : protoData) ?? protoData; + return !whichData ? undefined : { data: RTFCast(whichData), str: Field.toString(DocCast(whichData) ?? StrCast(whichData)) }; }, incomingValue => { if (this._editorView && this._applyingChange !== this.fieldKey) { @@ -1256,11 +1262,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB this._editorView.updateState(EditorState.fromJSON(this.config, updatedState)); this.tryUpdateScrollHeight(); } - } else { + } else if (this._editorView.state.doc.textContent !== incomingValue?.str) { selectAll(this._editorView.state, tx => this._editorView?.dispatch(tx.insertText(incomingValue?.str ?? ''))); } } - } + }, + { fireImmediately: true } ); this._disposers.search = reaction( diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index bdf600475..200896e25 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -48,7 +48,7 @@ export namespace Field { const valFunc = (field: Field): string => { const res = field instanceof ComputedField && showComputedValue - ? field._lastComputedResult + ? field.value(doc) : field instanceof ComputedField ? `:=${field.script.originalScript.replace(/dashCallChat\(_setCacheResult_, this, `(.*)`\)/, '(($1))')}` : field instanceof ScriptField diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index 9021c8896..8b51088b2 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -198,14 +198,22 @@ export class ComputedField extends ScriptField { } _lastComputedResult: FieldResult; - value = computedFn((doc: Doc) => this._valueOutsideReaction(doc)); - _valueOutsideReaction = (doc: Doc) => { - this._lastComputedResult = - this._cachedResult ?? (this.script.compiled && this.script.run({ this: doc, self: doc, value: '', _setCacheResult_: this.setCacheResult, _last_: this._lastComputedResult, _readOnly_: true }, console.log).result); - return this._lastComputedResult; - }; + value = (doc:Doc) => (this._lastComputedResult = this._cachedResult ?? + computedFn((doc: Doc) => + this.script.compiled && + this.script.run( { + this: doc, + //value: '', + _setCacheResult_: this.setCacheResult, + _last_: this._lastComputedResult, + _readOnly_: true, + }, + console.log + ).result + )(doc) + ); // prettier-ignore - [ToValue](doc: Doc) { if (ComputedField.useComputed) return { value: this._valueOutsideReaction(doc) }; } // prettier-ignore + [ToValue](doc: Doc) { if (ComputedField.useComputed) return { value: this.value(doc) }; } // prettier-ignore [Copy](): ObjectField { return new ComputedField(this.script, this.setterscript, this.rawscript); } // prettier-ignore public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Doc | string | number | boolean }, setterscript?: string) { |