diff options
-rw-r--r-- | src/client/documents/DocumentTypes.ts | 1 | ||||
-rw-r--r-- | src/client/documents/Documents.ts | 12 | ||||
-rw-r--r-- | src/client/util/ScriptManager.ts | 63 | ||||
-rw-r--r-- | src/client/util/Scripting.ts | 9 | ||||
-rw-r--r-- | src/client/views/nodes/ScriptingBox.tsx | 39 |
5 files changed, 113 insertions, 11 deletions
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index 06d35038a..7ba21b2f6 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -34,5 +34,6 @@ export enum DocumentType { COMPARISON = "comparison", // before/after view with slider (view of 2 images) LINKDB = "linkdb", // database of links ??? why do we have this + SCRIPTDB = "scriptdb", // database of scripts RECOMMENDATION = "recommendation", // view of a recommendation }
\ No newline at end of file diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 38fe04534..27fbbc433 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -262,6 +262,11 @@ export namespace Docs { layout: { view: EmptyBox, dataField: defaultDataKey }, options: { childDropAction: "alias", title: "Global Link Database" } }], + [DocumentType.SCRIPTDB, { + data: new List<Doc>(), + layout: { view: EmptyBox, dataField: defaultDataKey }, + options: { childDropAction: "alias", title: "Global Script Database" } + }], [DocumentType.SCRIPTING, { layout: { view: ScriptingBox, dataField: defaultDataKey } }], @@ -361,6 +366,13 @@ export namespace Docs { } /** + * A collection of all scripts in the database + */ + export function MainScriptDocument() { + return Prototypes.get(DocumentType.SCRIPTDB); + } + + /** * This is a convenience method that is used to initialize * prototype documents for the first time. * diff --git a/src/client/util/ScriptManager.ts b/src/client/util/ScriptManager.ts new file mode 100644 index 000000000..5bddb44ca --- /dev/null +++ b/src/client/util/ScriptManager.ts @@ -0,0 +1,63 @@ +import { Doc, DocListCast } from "../../fields/Doc"; +import { List } from "../../fields/List"; +import { Docs } from "../documents/Documents"; +import { Scripting, ScriptParam } from "./Scripting"; +import { StrCast } from "../../fields/Types"; + + +export class ScriptManager { + + private static _instance: ScriptManager; + public static get Instance(): ScriptManager { + return this._instance || (this._instance = new this()); + } + private constructor() { + } + + public get ScriptManagerDoc(): Doc | undefined { + return Docs.Prototypes.MainScriptDocument(); + } + + public getAllScripts(): Doc[] { + const sdoc = ScriptManager.Instance.ScriptManagerDoc; + if (sdoc) { + const docs = DocListCast(sdoc.data); + return docs; + } + return []; + } + + public addScript(scriptDoc: Doc): boolean { + const scriptList = ScriptManager.Instance.getAllScripts(); + scriptList.push(scriptDoc); + if (ScriptManager.Instance.ScriptManagerDoc) { + ScriptManager.Instance.ScriptManagerDoc.data = new List<Doc>(scriptList); + return true; + } + return false; + } + + public deleteScript(scriptDoc: Doc): boolean { + const scriptList = ScriptManager.Instance.getAllScripts(); + const index = ScriptManager.Instance.getAllScripts().indexOf(scriptDoc); + if (index > -1) { + scriptList.splice(index, 1); + if (ScriptManager.Instance.ScriptManagerDoc) { + ScriptManager.Instance.ScriptManagerDoc.data = new List<Doc>(scriptList); + return true; + } + } + return false; + } +} + +const scriptList = ScriptManager.Instance.getAllScripts(); + +scriptList.forEach((scriptDoc: Doc) => { + + const p = scriptDoc.compileParams?.reduce((o: ScriptParam, p: string) => { o[p] = "any"; return o; }, {} as ScriptParam); + const f = new Function(...Array.from(Object.keys(p)), StrCast(scriptDoc.rawScript)); + + Scripting.addGlobal(f, StrCast(scriptDoc.description), StrCast(p), StrCast(scriptDoc.name)); + +});
\ No newline at end of file diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 817e6b29d..5619b22b0 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -51,8 +51,9 @@ export namespace Scripting { export function addGlobal(name: string, global: any): void; export function addGlobal(global: { name: string }, decription?: string, params?: any): void; + export function addGlobal(global: { name: string }, decription?: string, params?: any, name?: any): void; - export function addGlobal(nameOrGlobal: any, global?: any, params?: any) { + export function addGlobal(nameOrGlobal: any, global?: any, params?: any, name?: any) { let n: any; let obj: any; @@ -61,12 +62,16 @@ export namespace Scripting { n = nameOrGlobal; obj = global; } else { - n = nameOrGlobal.name; obj = [nameOrGlobal]; obj.push(global); if (params) { obj.push(params); } + if (name) { + n = name; + } else { + n = nameOrGlobal.name; + } } } else if (nameOrGlobal && typeof nameOrGlobal.name === "string") { n = nameOrGlobal.name; diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index 149640c07..6f94ae8f9 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -22,6 +22,7 @@ const _global = (window /* browser */ || global /* node */) as any; import ReactTextareaAutocomplete from "@webscopeio/react-textarea-autocomplete"; import "@webscopeio/react-textarea-autocomplete/style.css"; +import { ScriptManager } from "../../util/ScriptManager"; const ScriptingSchema = createSchema({}); @@ -184,23 +185,30 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<FieldViewProps, Sc this.dataDoc.documentText = this.rawScript; this.dataDoc.data = result.compiled ? new ScriptField(result) : undefined; this.onError(result.compiled ? undefined : result.errors); + if (result.compiled) { + return true; + } else { + return false; + } } // checks if the script compiles and then runs the script @action onRun = () => { - this.onCompile(); - const bindings: { [name: string]: any } = {}; - this.paramsNames.forEach(key => bindings[key] = this.dataDoc[key]); - // binds vars so user doesnt have to refer to everything as self.<var> - ScriptCast(this.dataDoc.data, null)?.script.run({ self: this.rootDoc, this: this.layoutDoc, ...bindings }, this.onError); + if (this.onCompile()) { + const bindings: { [name: string]: any } = {}; + this.paramsNames.forEach(key => bindings[key] = this.dataDoc[key]); + // binds vars so user doesnt have to refer to everything as self.<var> + ScriptCast(this.dataDoc.data, null)?.script.run({ self: this.rootDoc, this: this.layoutDoc, ...bindings }, this.onError); + } } // checks if the script compiles and switches to applied UI @action onApply = () => { - this.onCompile(); - this._applied = true; + if (this.onCompile()) { + this._applied = true; + } } @action @@ -208,6 +216,17 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<FieldViewProps, Sc this._applied = false; } + @action + onSave = () => { + if (this.onCompile()) { + this.dataDoc.funcName = "testingTitle"; + this.dataDoc.descripition = "description test"; + ScriptManager.Instance.addScript(this.dataDoc); + } else { + this._errorMessage = "Can not save script, does not compile"; + } + } + // overlays document numbers (ex. d32) over all documents when clicked on onFocus = () => { this._overlayDisposer?.(); @@ -653,8 +672,10 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<FieldViewProps, Sc renderScriptingTools() { const buttonStyle = "scriptingBox-button" + (this.rootDoc.layoutKey === "layout_onClick" ? "third" : ""); return <div className="scriptingBox-toolbar"> - <button className={buttonStyle} onPointerDown={e => { this.onCompile(); e.stopPropagation(); }}>Compile</button> - <button className={buttonStyle} onPointerDown={e => { this.onApply(); e.stopPropagation(); }}>Apply</button> + <button className={buttonStyle} style={{ width: "33%" }} onPointerDown={e => { this.onCompile(); e.stopPropagation(); }}>Compile</button> + <button className={buttonStyle} style={{ width: "33%" }} onPointerDown={e => { this.onApply(); e.stopPropagation(); }}>Apply</button> + <button className={buttonStyle} style={{ width: "33%" }} onPointerDown={e => { this.onSave(); e.stopPropagation(); }}>Save</button> + {this.rootDoc.layoutKey !== "layout_onClick" ? (null) : <button className={buttonStyle} onPointerDown={e => { this.onFinish(); e.stopPropagation(); }}>Finish</button>} </div>; |