From cfa31b87f1c2a6597ed3cfb6a777126c58ace665 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 2 Aug 2022 16:28:18 -0400
Subject: Adjusted ScriptFields to have a rawScript, and updated ScrptingBoxes
 to create a scriptField even for scripts that don't compile.  Updated
 CurrentUserUtils setup functions for clicks.   Fixed TemplateMenu to work
 again.

---
 src/client/views/nodes/ScriptingBox.tsx | 85 ++++++++++++++++++---------------
 1 file changed, 47 insertions(+), 38 deletions(-)

(limited to 'src/client/views/nodes/ScriptingBox.tsx')

diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
index 05ff40f22..1c9b0bc0e 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -6,7 +6,7 @@ import { Doc } from '../../../fields/Doc';
 import { List } from '../../../fields/List';
 import { listSpec } from '../../../fields/Schema';
 import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
+import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { TraceMobx } from '../../../fields/util';
 import { returnEmptyString } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
@@ -60,6 +60,14 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
 
     constructor(props: any) {
         super(props);
+        if (!this.compileParams.length) {
+            const params = ScriptCast(this.rootDoc[this.props.fieldKey])?.script.options.params as { [key: string]: any };
+            if (params) {
+                this.compileParams = Array.from(Object.keys(params))
+                    .filter(p => !p.startsWith('_'))
+                    .map(key => key + ':' + params[key]);
+            }
+        }
     }
 
     // vars included in fields that store parameters types and names and the script itself
@@ -70,30 +78,30 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
         return this.compileParams.map(p => p.split(':')[1].trim());
     }
     @computed({ keepAlive: true }) get rawScript() {
-        return StrCast(this.dataDoc[this.props.fieldKey + '-rawScript'], '');
+        return ScriptCast(this.rootDoc[this.fieldKey])?.script.originalScript ?? '';
     }
     @computed({ keepAlive: true }) get functionName() {
-        return StrCast(this.dataDoc[this.props.fieldKey + '-functionName'], '');
+        return StrCast(this.rootDoc[this.props.fieldKey + '-functionName'], '');
     }
     @computed({ keepAlive: true }) get functionDescription() {
-        return StrCast(this.dataDoc[this.props.fieldKey + '-functionDescription'], '');
+        return StrCast(this.rootDoc[this.props.fieldKey + '-functionDescription'], '');
     }
     @computed({ keepAlive: true }) get compileParams() {
-        return Cast(this.dataDoc[this.props.fieldKey + '-params'], listSpec('string'), []);
+        return Cast(this.rootDoc[this.props.fieldKey + '-params'], listSpec('string'), []);
     }
 
     set rawScript(value) {
-        this.dataDoc[this.props.fieldKey + '-rawScript'] = value;
+        Doc.SetInPlace(this.rootDoc, this.props.fieldKey, new ScriptField(undefined, undefined, value), true);
     }
     set functionName(value) {
-        this.dataDoc[this.props.fieldKey + '-functionName'] = value;
+        Doc.SetInPlace(this.rootDoc, this.props.fieldKey + '-functionName', value, true);
     }
     set functionDescription(value) {
-        this.dataDoc[this.props.fieldKey + '-functionDescription'] = value;
+        Doc.SetInPlace(this.rootDoc, this.props.fieldKey + '-functionDescription', value, true);
     }
 
     set compileParams(value) {
-        this.dataDoc[this.props.fieldKey + '-params'] = new List<string>(value);
+        Doc.SetInPlace(this.rootDoc, this.props.fieldKey + '-params', new List<string>(value), true);
     }
 
     getValue(result: any, descrip: boolean) {
@@ -107,8 +115,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
 
     @action
     componentDidMount() {
-        this.rawScript = ScriptCast(this.dataDoc[this.props.fieldKey])?.script?.originalScript ?? this.rawScript;
-
+        this.rawText = this.rawScript;
         const observer = new _global.ResizeObserver(
             action((entries: any) => {
                 const area = document.querySelector('textarea');
@@ -171,13 +178,13 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
         const params: ScriptParam = {};
         this.compileParams.forEach(p => (params[p.split(':')[0].trim()] = p.split(':')[1].trim()));
 
-        const result = CompileScript(this.rawScript, {
+        const result = CompileScript(this.rawText, {
             editable: true,
             transformer: DocumentIconContainer.getTransformer(),
             params,
             typecheck: false,
         });
-        this.dataDoc[this.fieldKey] = result.compiled ? new ScriptField(result) : undefined;
+        Doc.SetInPlace(this.rootDoc, this.fieldKey, result.compiled ? new ScriptField(result, undefined, this.rawText) : new ScriptField(undefined, undefined, this.rawText), true);
         this.onError(result.compiled ? undefined : result.errors);
         return result.compiled;
     };
@@ -187,9 +194,9 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
     onRun = () => {
         if (this.onCompile()) {
             const bindings: { [name: string]: any } = {};
-            this.paramsNames.forEach(key => (bindings[key] = this.dataDoc[key]));
+            this.paramsNames.forEach(key => (bindings[key] = this.rootDoc[key]));
             // binds vars so user doesnt have to refer to everything as self.<var>
-            ScriptCast(this.dataDoc[this.fieldKey], null)?.script.run({ self: this.rootDoc, this: this.layoutDoc, ...bindings }, this.onError);
+            ScriptCast(this.rootDoc[this.fieldKey], null)?.script.run({ self: this.rootDoc, this: this.layoutDoc, ...bindings }, this.onError);
         }
     };
 
@@ -257,14 +264,14 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
     // sets field of the corresponding field key (param name) to be dropped document
     @action
     onDrop = (e: Event, de: DragManager.DropEvent, fieldKey: string) => {
-        this.dataDoc[fieldKey] = de.complete.docDragData?.droppedDocuments[0];
+        Doc.SetInPlace(this.rootDoc, fieldKey, de.complete.docDragData?.droppedDocuments[0], true);
         e.stopPropagation();
     };
 
     // deletes a param from all areas in which it is stored
     @action
     onDelete = (num: number) => {
-        this.dataDoc[this.paramsNames[num]] = undefined;
+        Doc.SetInPlace(this.rootDoc, this.paramsNames[num], undefined, true);
         this.compileParams.splice(num, 1);
         return true;
     };
@@ -274,7 +281,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
     viewChanged = (e: React.ChangeEvent, name: string) => {
         //@ts-ignore
         const val = e.target.selectedOptions[0].value;
-        this.dataDoc[name] = val[0] === 'S' ? val.substring(1) : val[0] === 'N' ? parseInt(val.substring(1)) : val.substring(1) === 'true';
+        Doc.SetInPlace(this.rootDoc, name, val[0] === 'S' ? val.substring(1) : val[0] === 'N' ? parseInt(val.substring(1)) : val.substring(1) === 'true', true);
     };
 
     // creates a copy of the script document
@@ -330,8 +337,8 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                     maxHeight={72}
                     height={35}
                     fontSize={14}
-                    contents={this.dataDoc[parameter]?.title ?? 'undefined'}
-                    GetValue={() => this.dataDoc[parameter]?.title ?? 'undefined'}
+                    contents={StrCast(DocCast(this.rootDoc[parameter])?.title, 'undefined')}
+                    GetValue={() => StrCast(DocCast(this.rootDoc[parameter])?.title, 'undefined')}
                     SetValue={action((value: string) => {
                         const script = CompileScript(value, {
                             addReturn: true,
@@ -341,7 +348,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                         const results = script.compiled && script.run();
                         if (results && results.success) {
                             this._errorMessage = '';
-                            this.dataDoc[parameter] = results.result;
+                            Doc.SetInPlace(this.rootDoc, parameter, results.result, true);
                             return true;
                         }
                         this._errorMessage = 'invalid document';
@@ -354,7 +361,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
 
     // rendering when a string's value can be set in applied UI
     renderBasicType(parameter: string, isNum: boolean) {
-        const strVal = isNum ? NumCast(this.dataDoc[parameter]).toString() : StrCast(this.dataDoc[parameter]);
+        const strVal = isNum ? NumCast(this.rootDoc[parameter]).toString() : StrCast(this.rootDoc[parameter]);
         return (
             <div className="scriptingBox-paramInputs" style={{ overflowY: 'hidden' }}>
                 <EditableView
@@ -368,7 +375,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                         const setValue = isNum ? parseInt(value) : value;
                         if (setValue !== undefined && setValue !== ' ') {
                             this._errorMessage = '';
-                            this.dataDoc[parameter] = setValue;
+                            Doc.SetInPlace(this.rootDoc, parameter, setValue, true);
                             return true;
                         }
                         this._errorMessage = 'invalid input';
@@ -389,7 +396,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                             className="scriptingBox-viewPicker"
                             onPointerDown={e => e.stopPropagation()}
                             onChange={e => this.viewChanged(e, parameter)}
-                            value={typeof this.dataDoc[parameter] === 'string' ? 'S' + StrCast(this.dataDoc[parameter]) : typeof this.dataDoc[parameter] === 'number' ? 'N' + NumCast(this.dataDoc[parameter]) : 'B' + BoolCast(this.dataDoc[parameter])}>
+                            value={typeof this.rootDoc[parameter] === 'string' ? 'S' + StrCast(this.rootDoc[parameter]) : typeof this.rootDoc[parameter] === 'number' ? 'N' + NumCast(this.rootDoc[parameter]) : 'B' + BoolCast(this.rootDoc[parameter])}>
                             {types.map(type => (
                                 <option className="scriptingBox-viewOption" value={(typeof type === 'string' ? 'S' : typeof type === 'number' ? 'N' : 'B') + type}>
                                     {' '}
@@ -442,7 +449,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
 
     @action
     handleFunc(pos: number) {
-        const scriptString = this.rawScript.slice(0, pos - 2);
+        const scriptString = this.rawText.slice(0, pos - 2);
         this._currWord = scriptString.split(' ')[scriptString.split(' ').length - 1];
         this._suggestions = [StrCast(this._scriptingParams[this._currWord])];
         return this._suggestions;
@@ -474,7 +481,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
     }
 
     getSuggestedParams(pos: number) {
-        const firstScript = this.rawScript.slice(0, pos);
+        const firstScript = this.rawText.slice(0, pos);
         const indexP = firstScript.lastIndexOf('.');
         const indexS = firstScript.lastIndexOf(' ');
         const func = firstScript.slice((indexP > indexS ? indexP : indexS) + 1, firstScript.length + 1);
@@ -494,8 +501,9 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
 
     @action
     keyHandler(e: any, pos: number) {
+        e.stopPropagation();
         if (this._lastChar === 'Enter') {
-            this.rawScript = this.rawScript + ' ';
+            this.rawText = this.rawText + ' ';
         }
         if (e.key === '(') {
             this.suggestionPos();
@@ -504,7 +512,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
             this._scriptSuggestedParams = this.getSuggestedParams(pos);
 
             if (this._scriptParamsText !== undefined && this._scriptParamsText.length > 0) {
-                if (this.rawScript[pos - 2] !== '(') {
+                if (this.rawText[pos - 2] !== '(') {
                     this._paramSuggestion = true;
                 }
             }
@@ -515,22 +523,22 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                 if (this._lastChar === '(') {
                     this._paramSuggestion = false;
                 } else if (this._lastChar === ')') {
-                    if (this.rawScript.slice(0, this.rawScript.length - 1).split('(').length - 1 > this.rawScript.slice(0, this.rawScript.length - 1).split(')').length - 1) {
+                    if (this.rawText.slice(0, this.rawText.length - 1).split('(').length - 1 > this.rawText.slice(0, this.rawText.length - 1).split(')').length - 1) {
                         if (this._scriptParamsText.length > 0) {
                             this._paramSuggestion = true;
                         }
                     }
                 }
-            } else if (this.rawScript.split('(').length - 1 <= this.rawScript.split(')').length - 1) {
+            } else if (this.rawText.split('(').length - 1 <= this.rawText.split(')').length - 1) {
                 this._paramSuggestion = false;
             }
         }
-        this._lastChar = e.key === 'Backspace' ? this.rawScript[this.rawScript.length - 2] : e.key;
+        this._lastChar = e.key === 'Backspace' ? this.rawText[this.rawText.length - 2] : e.key;
 
         if (this._paramSuggestion) {
             const parameters = this._scriptParamsText.split(',');
-            const index = this.rawScript.lastIndexOf('(');
-            const enteredParams = this.rawScript.slice(index, this.rawScript.length);
+            const index = this.rawText.lastIndexOf('(');
+            const enteredParams = this.rawText.slice(index, this.rawText.length);
             const splitEntered = enteredParams.split(',');
             const numEntered = splitEntered.length;
 
@@ -564,15 +572,16 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
     handlePosChange(number: any) {
         this._caretPos = number;
         if (this._caretPos === 0) {
-            this.rawScript = ' ' + this.rawScript;
+            this.rawText = ' ' + this.rawText;
         } else if (this._spaced) {
             this._spaced = false;
-            if (this.rawScript[this._caretPos - 1] === ' ') {
-                this.rawScript = this.rawScript.slice(0, this._caretPos - 1) + this.rawScript.slice(this._caretPos, this.rawScript.length);
+            if (this.rawText[this._caretPos - 1] === ' ') {
+                this.rawText = this.rawText.slice(0, this._caretPos - 1) + this.rawText.slice(this._caretPos, this.rawText.length);
             }
         }
     }
 
+    @observable rawText: string = '';
     @computed({ keepAlive: true }) get renderScriptingBox() {
         TraceMobx();
         return (
@@ -583,8 +592,8 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                     placeholder="write your script here"
                     onFocus={this.onFocus}
                     onBlur={() => this._overlayDisposer?.()}
-                    onChange={(e: any) => (this.rawScript = e.target.value)}
-                    value={this.rawScript}
+                    onChange={action((e: any) => (this.rawText = e.target.value))}
+                    value={this.rawText}
                     movePopupAsYouType={true}
                     loadingComponent={() => <span>Loading</span>}
                     trigger={{
-- 
cgit v1.2.3-70-g09d2

