From e262d9ac73af5b2cef384468c47d69917e205d44 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 7 Apr 2020 23:01:46 -0400
Subject: lots of code cleanup - removed all northstar db stuff.  added
 scriptingBox.  renamed things.  made collectiontypes strings not numbers.

---
 src/client/views/nodes/ScriptingBox.tsx | 71 +++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)
 create mode 100644 src/client/views/nodes/ScriptingBox.tsx

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

diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
new file mode 100644
index 000000000..a2dd134ed
--- /dev/null
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -0,0 +1,71 @@
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { faEdit } from '@fortawesome/free-regular-svg-icons';
+import { computed } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Doc } from '../../../new_fields/Doc';
+import { documentSchema } from '../../../new_fields/documentSchemas';
+import { CompileScript } from "../../util/Scripting";
+import { ScriptBox } from '../ScriptBox';
+import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema';
+import { ScriptField } from '../../../new_fields/ScriptField';
+import { BoolCast, ScriptCast } from '../../../new_fields/Types';
+import { DocComponent } from '../DocComponent';
+import { FieldView, FieldViewProps } from './FieldView';
+import './ScriptingBox.scss';
+import { DocumentIconContainer } from './DocumentIcon';
+
+
+library.add(faEdit as any);
+
+const ScriptingSchema = createSchema({
+    onClick: ScriptField,
+    buttonParams: listSpec("string"),
+    text: "string"
+});
+
+type ScriptingDocument = makeInterface<[typeof ScriptingSchema, typeof documentSchema]>;
+const ScriptingDocument = makeInterface(ScriptingSchema, documentSchema);
+
+@observer
+export class ScriptingBox extends DocComponent<FieldViewProps, ScriptingDocument>(ScriptingDocument) {
+    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScriptingBox, fieldKey); }
+
+    @computed get dataDoc() {
+        return this.props.DataDoc &&
+            (this.Document.isTemplateForField || BoolCast(this.props.DataDoc.isTemplateForField) ||
+                this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document);
+    }
+
+    specificContextMenu = (e: React.MouseEvent): void => { }
+
+    render() {
+        const script = ScriptCast(this.props.Document[this.props.fieldKey]);
+        let originalText: string | undefined = undefined;
+        if (script) {
+            originalText = script.script.originalScript;
+        }
+        return !(this.props.Document instanceof Doc) ? (null) :
+            <ScriptBox initialText={originalText}
+                setParams={() => { }}
+                onCancel={() => { }}
+                onSave={(text, onError) => {
+                    if (!text) {
+                        this.dataDoc[this.props.fieldKey] = undefined;
+                    } else {
+                        const script = CompileScript(text, {
+                            params: { this: Doc.name },
+                            typecheck: false,
+                            editable: true,
+                            transformer: DocumentIconContainer.getTransformer()
+                        });
+                        if (!script.compiled) {
+                            onError(script.errors.map(error => error.messageText).join("\n"));
+                        }
+                        else {
+                            this.dataDoc[this.props.fieldKey] = new ScriptField(script);
+                        }
+                    }
+                }} showDocumentIcons />;
+    }
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From b21db9d40c1619df5455ba8ffe3ef76913cc92de Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 8 Apr 2020 19:14:47 -0400
Subject: added scripting box

---
 src/client/documents/Documents.ts                  |   4 +-
 src/client/util/Scripting.ts                       |   8 +-
 src/client/views/MainView.tsx                      |   3 +-
 src/client/views/nodes/ScriptingBox.scss           |  33 +++++
 src/client/views/nodes/ScriptingBox.tsx            | 137 ++++++++++++---------
 .../authentication/models/current_user_utils.ts    |   1 +
 6 files changed, 123 insertions(+), 63 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 5231dbb8c..5eca71ca9 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -509,8 +509,8 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.PRES), initial, options);
         }
 
-        export function ScriptingDocument(url: string, options: DocumentOptions = {}) {
-            return InstanceFromProto(Prototypes.get(DocumentType.SCRIPTING), new YoutubeField(new URL(url)), options);
+        export function ScriptingDocument(options: DocumentOptions = {}) {
+            return InstanceFromProto(Prototypes.get(DocumentType.SCRIPTING), "", options);
         }
 
         export function VideoDocument(url: string, options: DocumentOptions = {}) {
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index cf04c44ca..f97d91d10 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -89,9 +89,9 @@ const _scriptingGlobals: { [name: string]: any } = {};
 let scriptingGlobals: { [name: string]: any } = _scriptingGlobals;
 
 function Run(script: string | undefined, customParams: string[], diagnostics: any[], originalScript: string, options: ScriptOptions): CompileResult {
-    const errors = diagnostics.some(diag => diag.category === ts.DiagnosticCategory.Error);
-    if ((options.typecheck !== false && errors) || !script) {
-        return { compiled: false, errors: diagnostics };
+    const errors = diagnostics.filter(diag => diag.category === ts.DiagnosticCategory.Error);
+    if ((options.typecheck !== false && errors.length) || !script) {
+        return { compiled: false, errors };
     }
 
     const paramNames = Object.keys(scriptingGlobals);
@@ -201,7 +201,7 @@ export interface ScriptOptions {
     capturedVariables?: { [name: string]: Field }; // list of captured variables
     typecheck?: boolean; // should the compiler perform typechecking
     editable?: boolean; // can the script edit Docs
-    traverser?: TraverserParam; 
+    traverser?: TraverserParam;
     transformer?: Transformer; // does the editor display a text label by each document that can be used as a captured document reference
     globals?: { [name: string]: any };
 }
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 7c9f47fe4..1edfc871f 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,5 +1,5 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons';
+import { faTerminal, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
@@ -101,6 +101,7 @@ export class MainView extends React.Component {
             }
         }
 
+        library.add(faTerminal);
         library.add(faFileAlt);
         library.add(faStickyNote);
         library.add(faFont);
diff --git a/src/client/views/nodes/ScriptingBox.scss b/src/client/views/nodes/ScriptingBox.scss
index e69de29bb..f31c72bb2 100644
--- a/src/client/views/nodes/ScriptingBox.scss
+++ b/src/client/views/nodes/ScriptingBox.scss
@@ -0,0 +1,33 @@
+.scriptingBox-outerDiv {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    pointer-events: all;
+    background-color: rgb(241, 239, 235);
+    padding: 10px;
+    .scriptingBox-inputDiv {
+        display: flex;
+        flex-direction: column;
+        height: calc(100% - 30px);
+        .scriptingBox-errorMessage {
+            overflow: auto;
+        }
+        .scriptingBox-textArea {
+            width: 100%;
+            height: 100%;
+            box-sizing: border-box;
+            resize: none;
+            padding: 7px;
+        }
+    }
+
+    .scriptingBox-toolbar {
+        width: 100%;
+        height: 30px;
+        .scriptingBox-button {
+            width: 50%
+        }
+    }
+}
+
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
index a2dd134ed..74d9c2e94 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -1,71 +1,96 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faEdit } from '@fortawesome/free-regular-svg-icons';
-import { computed } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { Doc } from '../../../new_fields/Doc';
-import { documentSchema } from '../../../new_fields/documentSchemas';
+import { action, observable, computed } from "mobx";
+import { observer } from "mobx-react";
+import * as React from "react";
+import { Opt } from "../../../new_fields/Doc";
+import { documentSchema } from "../../../new_fields/documentSchemas";
+import { createSchema, makeInterface } from "../../../new_fields/Schema";
+import { ScriptField } from "../../../new_fields/ScriptField";
+import { StrCast, ScriptCast } from "../../../new_fields/Types";
+import { returnTrue } from "../../../Utils";
+import { InteractionUtils } from "../../util/InteractionUtils";
 import { CompileScript } from "../../util/Scripting";
-import { ScriptBox } from '../ScriptBox';
-import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema';
-import { ScriptField } from '../../../new_fields/ScriptField';
-import { BoolCast, ScriptCast } from '../../../new_fields/Types';
-import { DocComponent } from '../DocComponent';
-import { FieldView, FieldViewProps } from './FieldView';
-import './ScriptingBox.scss';
-import { DocumentIconContainer } from './DocumentIcon';
-
-
-library.add(faEdit as any);
+import { DocAnnotatableComponent } from "../DocComponent";
+import { EditableView } from "../EditableView";
+import { FieldView, FieldViewProps } from "../nodes/FieldView";
+import "./ScriptingBox.scss";
 
 const ScriptingSchema = createSchema({
-    onClick: ScriptField,
-    buttonParams: listSpec("string"),
-    text: "string"
 });
 
 type ScriptingDocument = makeInterface<[typeof ScriptingSchema, typeof documentSchema]>;
 const ScriptingDocument = makeInterface(ScriptingSchema, documentSchema);
 
 @observer
-export class ScriptingBox extends DocComponent<FieldViewProps, ScriptingDocument>(ScriptingDocument) {
-    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScriptingBox, fieldKey); }
+export class ScriptingBox extends DocAnnotatableComponent<FieldViewProps, ScriptingDocument>(ScriptingDocument) {
+    protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer | undefined;
+    public static LayoutString(fieldStr: string) { return FieldView.LayoutString(ScriptingBox, fieldStr); }
 
-    @computed get dataDoc() {
-        return this.props.DataDoc &&
-            (this.Document.isTemplateForField || BoolCast(this.props.DataDoc.isTemplateForField) ||
-                this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document);
+    @observable private _errorMessage: string = "";
+    @computed get rawScript() { return StrCast(this.dataDoc[this.props.fieldKey + "-raw"]); }
+    set rawScript(value) { this.dataDoc[this.props.fieldKey + "-raw"] = value; }
+
+    @action
+    componentDidMount() {
+        this.rawScript = ScriptCast(this.dataDoc[this.props.fieldKey])?.script?.originalScript || this.rawScript;
     }
 
-    specificContextMenu = (e: React.MouseEvent): void => { }
+    @action
+    onChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
+        this.rawScript = e.target.value;
+    }
 
-    render() {
-        const script = ScriptCast(this.props.Document[this.props.fieldKey]);
-        let originalText: string | undefined = undefined;
-        if (script) {
-            originalText = script.script.originalScript;
+    @action
+    onError = (error: any) => {
+        this._errorMessage = (error as any).map((e: any) => e.messageText).join(" ");
+    }
+
+    @action
+    onCompile = () => {
+        const result = CompileScript(this.rawScript, {});
+        this._errorMessage = "";
+        if (result.compiled) {
+            this._errorMessage = "";
+            this.dataDoc[this.props.fieldKey] = new ScriptField(result);
         }
-        return !(this.props.Document instanceof Doc) ? (null) :
-            <ScriptBox initialText={originalText}
-                setParams={() => { }}
-                onCancel={() => { }}
-                onSave={(text, onError) => {
-                    if (!text) {
-                        this.dataDoc[this.props.fieldKey] = undefined;
-                    } else {
-                        const script = CompileScript(text, {
-                            params: { this: Doc.name },
-                            typecheck: false,
-                            editable: true,
-                            transformer: DocumentIconContainer.getTransformer()
-                        });
-                        if (!script.compiled) {
-                            onError(script.errors.map(error => error.messageText).join("\n"));
-                        }
-                        else {
-                            this.dataDoc[this.props.fieldKey] = new ScriptField(script);
-                        }
-                    }
-                }} showDocumentIcons />;
+        else {
+            this.dataDoc[this.props.fieldKey] = undefined;
+            this.onError(result.errors);
+        }
+    }
+
+    @action
+    onRun = () => {
+        this.onCompile();
+        ScriptCast(this.dataDoc[this.props.fieldKey])?.script.run({},
+            (err: any) => {
+                this._errorMessage = "";
+                this.onError(err);
+            });
+    }
+
+    render() {
+        let onFocus: Opt<() => void> = undefined, onBlur: Opt<() => void> = undefined;
+        const params = <EditableView
+            contents={""}
+            display={"block"}
+            maxHeight={72}
+            height={35}
+            fontSize={28}
+            GetValue={() => ""}
+            SetValue={returnTrue}
+        />;
+        return (
+            <div className="scriptingBox-outerDiv" onPointerDown={(e) => this.props.isSelected() && e.stopPropagation()} onWheel={(e) => this.props.isSelected() && e.stopPropagation()}>
+                <div className="scriptingBox-inputDiv" >
+                    <textarea className="scriptingBox-textarea" placeholder="write your script here" onChange={this.onChange} value={this.rawScript} onFocus={onFocus} onBlur={onBlur} />
+                    <div className="scriptingBox-errorMessage">{this._errorMessage}</div>
+                    <div style={{ background: "beige" }} >{params}</div>
+                </div>
+                <div className="scriptingBox-toolbar">
+                    <button className="scriptingBox-button" onPointerDown={e => { this.onCompile(); e.stopPropagation(); }}>Compile</button>
+                    <button className="scriptingBox-button" onPointerDown={e => { this.onRun(); e.stopPropagation(); }}>Run</button>
+                </div>
+            </div>
+        );
     }
-}
\ No newline at end of file
+}
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index fa1d49e4e..37b680765 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -80,6 +80,7 @@ export class CurrentUserUtils {
             { title: "record", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` },
             { title: "clickable button", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, title: "Button" })' },
             { title: "presentation", icon: "tv", click: 'openOnRight(Doc.UserDoc().curPresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().curPresentation = getCopy(this.dragFactory,true)`, dragFactory: emptyPresentation },
+            { title: "script", icon: "terminal", ignoreClick: true, drag: 'Docs.Create.ScriptingDocument({ _width: 200, _height: 250 title: "untitled script" })' },
             { title: "import folder", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' },
             { title: "mobile view", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' },
             { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.pen,  this)`, activePen: doc },
-- 
cgit v1.2.3-70-g09d2

