import { action, observable, computed, _allowStateChangesInsideComputed, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as React from "react"; import { documentSchema } from "../../../fields/documentSchemas"; import { createSchema, makeInterface, listSpec } from "../../../fields/Schema"; import { ScriptField } from "../../../fields/ScriptField"; import { StrCast, ScriptCast, Cast } from "../../../fields/Types"; import { InteractionUtils } from "../../util/InteractionUtils"; import { CompileScript, isCompileError, ScriptParam } from "../../util/Scripting"; import { ViewBoxAnnotatableComponent } from "../DocComponent"; import { EditableView } from "../EditableView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "./ScriptingBox.scss"; import { OverlayView } from "../OverlayView"; import { DocumentIconContainer, DocumentIcon } from "./DocumentIcon"; import { List } from "../../../fields/List"; import { DragManager } from "../../util/DragManager"; import { faSearch, faKaaba } from "@fortawesome/free-solid-svg-icons"; import { undoBatch } from "../../util/UndoManager"; import { Utils } from "../../../Utils"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; const ScriptingSchema = createSchema({}); type ScriptingDocument = makeInterface<[typeof ScriptingSchema, typeof documentSchema]>; const ScriptingDocument = makeInterface(ScriptingSchema, documentSchema); @observer export class ScriptingBox extends ViewBoxAnnotatableComponent(ScriptingDocument) { protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer | undefined; rowProps: any; _paramNum: number = 0; public static LayoutString(fieldStr: string) { return FieldView.LayoutString(ScriptingBox, fieldStr); } _overlayDisposer?: () => void; @observable private _errorMessage: string = ""; @observable private _applied: boolean = false; @observable private _paramsNames: string[] = []; @observable private _paramsTypes: string[] = []; @observable private _paramsValues: string[] = []; @observable private _paramsCollapsed: boolean[] = []; @computed get rawScript() { return StrCast(this.dataDoc[this.props.fieldKey + "-rawScript"], StrCast(this.layoutDoc[this.props.fieldKey + "-rawScript"])); } @computed get compileParams() { return Cast(this.dataDoc[this.props.fieldKey + "-params"], listSpec("string"), Cast(this.layoutDoc[this.props.fieldKey + "-params"], listSpec("string"), [])); } set rawScript(value) { this.dataDoc[this.props.fieldKey + "-rawScript"] = value; } stopPropagation = (e: React.SyntheticEvent) => e.stopPropagation(); set compileParams(value) { this.dataDoc[this.props.fieldKey + "-params"] = value; } @action componentDidMount() { this.rawScript = ScriptCast(this.dataDoc[this.props.fieldKey])?.script?.originalScript || this.rawScript; } componentWillUnmount() { this._overlayDisposer?.(); } @action onFinish = () => { const result = CompileScript(this.rawScript, {}); this.rootDoc.layoutKey = "layout"; this.rootDoc.height = 50; this.rootDoc.width = 100; this.props.Document.documentText = this.rawScript; } @action onError = (error: any) => { for (const entry of error) { this._errorMessage = this._errorMessage + " " + entry.messageText; } } @action onCompile = () => { // const params = this.compileParams.reduce((o: ScriptParam, p: string) => { o[p] = "any"; return o; }, {} as ScriptParam); // const result = CompileScript(this.rawScript, { // editable: true // transformer: DocumentIconContainer.getTransformer(), // params, // typecheck: false // }); // this._errorMessage = isCompileError(result) ? result.errors.map(e => e.messageText).join("\n") : ""; // return this.dataDoc[this.props.fieldKey] = result.compiled ? new ScriptField(result) : undefined; const params = this.compileParams.reduce((o: ScriptParam, p: string) => { const param = p.split(":"); o[param[0].trim()] = param[1].trim(); return o; }, {} as ScriptParam); console.log(this.compileParams); const result = CompileScript(this.rawScript, { editable: true, transformer: DocumentIconContainer.getTransformer(), params, typecheck: true }); this._errorMessage = ""; if (result.compiled) { this._errorMessage = ""; this.props.Document.data = new ScriptField(result); } else { this.onError(result.errors); } this.props.Document.documentText = this.rawScript; } @action onRun = () => { const params = this.compileParams.reduce((o: ScriptParam, p: string) => { const param = p.split(":"); o[param[0].trim()] = param[1].trim(); return o; }, {} as ScriptParam); const result = CompileScript(this.rawScript, { editable: true, transformer: DocumentIconContainer.getTransformer(), params, typecheck: true }); this._errorMessage = ""; if (result.compiled) { // this automatically saves result.run({ self: this.rootDoc, this: this.layoutDoc }, (err: any) => { this._errorMessage = ""; this.onError(err); }); this.props.Document.data = new ScriptField(result); } else { this.onError(result.errors); } this.props.Document.documentText = this.rawScript; //this.onCompile()?.script.run({}, err => this._errorMessage = err.map((e: any) => e.messageText).join("\n")); } @action onApply = () => { const params = this.compileParams.reduce((o: ScriptParam, p: string) => { const param = p.split(":"); o[param[0].trim()] = param[1].trim(); return o; }, {} as ScriptParam); console.log(this.compileParams); const result = CompileScript(this.rawScript, { editable: true, transformer: DocumentIconContainer.getTransformer(), params, typecheck: true }); this._errorMessage = ""; if (result.compiled) { this._errorMessage = ""; this.props.Document.data = new ScriptField(result); this._applied = true; } else { this.onError(result.errors); } this.props.Document.documentText = this.rawScript; } @action onEdit = () => { this._applied = false; } onFocus = () => { this._overlayDisposer?.(); this._overlayDisposer = OverlayView.Instance.addElement(, { x: 0, y: 0 }); } @action onDrop = (e: Event, de: DragManager.DropEvent, index: any) => { console.log("drop"); const droppedDocs = de.complete.docDragData?.droppedDocuments; if (droppedDocs?.length) { const dropped = droppedDocs[0]; this.props.Document[index] = dropped; const num = this._paramsNames.indexOf(index); this._paramsValues[num] = StrCast(dropped.title); } } @action onDelete = (num: number) => { this.compileParams.splice(num, 1); const name = this._paramsNames[this._paramsNames.length - num - 1]; this.props.Document[name] = undefined; this._paramsNames.splice(this._paramsNames.length - num - 1, 1); this._paramsTypes.splice(this._paramsTypes.length - num - 1, 1); this._paramsValues.splice(this._paramsValues.length - num - 1, 1); } @action viewChanged = (e: React.ChangeEvent, i: number, name: string) => { //@ts-ignore this.props.Document[name] = e.target.selectedOptions[0].value; //@ts-ignore this._paramsValues[i] = e.target.selectedOptions[0].value; } @action selected = (val: string, index: number, name: string) => { console.log("selected"); this.stopPropagation; this.props.Document[name] = val; this._paramsValues[index] = val; } @action toggleCollapse = (num: number) => { console.log("hello"); if (this._paramsCollapsed[num]) { this._paramsCollapsed[num] = false; } else { this._paramsCollapsed[num] = true; } } render() { const params = ""} SetValue={value => { if (value !== "" && value !== " ") { const parameter = value.split(":"); if (parameter[1] !== undefined) { if (parameter[1].trim() === "Doc" || parameter[1].trim() === "string" || parameter[1].split("|")[1] || parameter[1].trim() === "number" || parameter[1].trim() === "boolean") { if (!!!this._paramsNames.includes(parameter[0].trim()) && this.props.Document[parameter[0].trim()] === undefined) { this._errorMessage = ""; this._paramNum++; const par = this.compileParams; this.compileParams = new List(value.split(";").filter(s => s !== " ")); this.compileParams.push.apply(this.compileParams, par); this._paramsNames.push(parameter[0].trim()); this._paramsTypes.push(parameter[1].trim()); this._paramsValues.push("undefined"); this._paramsCollapsed.push(true); return true; } else { this._errorMessage = "this name has already been used"; return false; } } else { this._errorMessage = "this type is not supported"; return false; } } else { this._errorMessage = "must set type of parameter"; return false; } } return false; }} />; // might want to change this display later on const listParams = this.compileParams.map((parameter, i) =>
{ if (e.key === "Enter") { this._overlayDisposer?.(); } } } > parameter} onDrop={(e: Event, de: DragManager.DropEvent) => this.onDrop(e, de, i)} SetValue={value => { if (value !== "" && value !== " ") { const parameter = value.split(":"); if (parameter[1] !== undefined) { if (parameter[1].trim() === "Doc" || parameter[1].trim() === "string" || parameter[1].split("|")[1] || parameter[1].trim() === "number" || parameter[1].trim() === "boolean") { if ((!!!this._paramsNames.includes(parameter[0].trim()) && this.props.Document[parameter[0].trim()] === undefined) || parameter[0].trim() === this._paramsNames[this._paramsNames.length - i - 1]) { this._errorMessage = ""; this._paramsNames[this._paramsNames.length - i - 1] = parameter[0].trim(); this._paramsTypes[this._paramsTypes.length - i - 1] = parameter[1].trim(); this._paramsValues[this._paramsValues.length - i - 1] = "undefined"; this.compileParams[i] = value; return true; } else { this._errorMessage = "this name has already been used"; return false; } } else { this._errorMessage = "this type is not supported"; return false; } } else { this._errorMessage = "must set type of parameter"; return false; } } else { this.onDelete(i); return true; } }} />
); const settingParams = this._paramsNames.map((parameter: string, i: number) =>
{ if (e.key === "Enter") { this._overlayDisposer?.(); } } } > {this._paramsTypes[i] === "Doc" ?
{parameter + ":" + this._paramsTypes[i] + " = "}
this._paramsValues[i]} onDrop={(e: Event, de: DragManager.DropEvent) => this.onDrop(e, de, parameter)} SetValue={value => { runInAction(() => { const script = CompileScript( value, { addReturn: true, typecheck: false, transformer: DocumentIconContainer.getTransformer(), params: { makeInterface: "any" } }); if (!script.compiled) { this._errorMessage = "invalid document"; return false; } else { const results = script.run(); if (results.success) { this._errorMessage = ""; this.props.Document[parameter] = results.result; this._paramsValues[i] = value; return true; } else { this._errorMessage = "invalid document"; return false; } } }); return true; }} />
: null} {this._paramsTypes[i] === "string" ?
{parameter + ":" + this._paramsTypes[i] + " = "}
StrCast(this.props.Document[parameter]) ?? "undefined"} SetValue={value => { runInAction(() => { if (value !== "" && value !== " ") { this._errorMessage = ""; this.props.Document[parameter] = value; this._paramsValues[i] = value; return true; } else { return false; } }); return true; }} />
: null} {this._paramsTypes[i] === "number" ?
{parameter + ":" + this._paramsTypes[i] + " = "}
StrCast(this.props.Document[parameter]) ?? "undefined"} SetValue={value => { runInAction(() => { if (value !== "" && value !== " ") { if (parseInt(value)) { this._errorMessage = ""; this.props.Document[parameter] = parseInt(value); this._paramsValues[i] = StrCast(parseInt(value)); return true; } else { this._errorMessage = "not a number"; return false; } } else { return false; } }); return true; }} />
: null} {this._paramsTypes[i].split("|")[1] ?
{parameter + ":" + this._paramsTypes[i] + " = "}
: null} {this._paramsTypes[i] === "boolean" ?
{parameter + ":" + this._paramsTypes[i] + " = "}
StrCast(this._paramsValues[i])} SetValue={value => { runInAction(() => { if (value !== "" && value !== " ") { if (value.trim() === "true") { console.log("hello"); this._errorMessage = ""; // does not set this this.props.Document[parameter] = true; // sets this this._paramsValues[i] = "true"; return true; } else { if (value.trim() === "false") { this._errorMessage = ""; this.props.Document[parameter] = false; this._paramsValues[i] = "false"; return true; } else { this._errorMessage = "not a boolean"; return false; } } } else { return false; } }); return true; }} />
: null}
); const scriptingInputs =
this.props.isSelected(true) && e.stopPropagation()} >