From 74593e4370b554072ebbdef9a683a04a1bcbbde1 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 24 Jul 2019 22:10:00 -0400 Subject: Added a Button document --- src/client/views/nodes/ButtonBox.tsx | 74 ++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 src/client/views/nodes/ButtonBox.tsx (limited to 'src/client/views/nodes/ButtonBox.tsx') diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx new file mode 100644 index 000000000..622595cdc --- /dev/null +++ b/src/client/views/nodes/ButtonBox.tsx @@ -0,0 +1,74 @@ +import * as React from 'react'; +import { FieldViewProps, FieldView } from './FieldView'; +import { createSchema, makeInterface } from '../../../new_fields/Schema'; +import { ScriptField } from '../../../new_fields/ScriptField'; +import { DocComponent } from '../DocComponent'; +import { ContextMenu } from '../ContextMenu'; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faEdit } from '@fortawesome/free-regular-svg-icons'; +import { emptyFunction } from '../../../Utils'; +import { ScriptBox } from '../ScriptBox'; +import { CompileScript } from '../../util/Scripting'; +import { OverlayView } from '../OverlayView'; +import { Doc } from '../../../new_fields/Doc'; + +import './ButtonBox.scss'; +import { observer } from 'mobx-react'; + +library.add(faEdit); + +const ButtonSchema = createSchema({ + onClick: ScriptField, + text: "string" +}); + +type ButtonDocument = makeInterface<[typeof ButtonSchema]>; +const ButtonDocument = makeInterface(ButtonSchema); + +@observer +export class ButtonBox extends DocComponent(ButtonDocument) { + public static LayoutString() { return FieldView.LayoutString(ButtonBox); } + + onClick = (e: React.MouseEvent) => { + const onClick = this.Document.onClick; + if (!onClick) { + return; + } + e.stopPropagation(); + e.preventDefault(); + onClick.script.run({ this: this.props.Document }); + } + + onContextMenu = () => { + ContextMenu.Instance.addItem({ + description: "Edit OnClick script", icon: "edit", event: () => { + let overlayDisposer: () => void = emptyFunction; + const script = this.Document.onClick; + let originalText: string | undefined = undefined; + if (script) originalText = script.script.originalScript; + // tslint:disable-next-line: no-unnecessary-callback-wrapper + let scriptingBox = overlayDisposer()} onSave={(text, onError) => { + const script = CompileScript(text, { + params: { this: Doc.name }, + typecheck: false + }); + if (!script.compiled) { + onError(script.errors.map(error => error.messageText).join("\n")); + return; + } + this.Document.onClick = new ScriptField(script); + overlayDisposer(); + }} />; + overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, { x: 400, y: 200, width: 500, height: 400, title: `${this.Document.title || ""} OnClick` }); + } + }); + } + + render() { + return ( +
+ +
+ ); + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From d344bb81c43820d606655a4f78dbaedc66ab3638 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 24 Jul 2019 22:23:23 -0400 Subject: Small fix to button documents --- src/client/views/nodes/ButtonBox.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/client/views/nodes/ButtonBox.tsx') diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx index 622595cdc..744611661 100644 --- a/src/client/views/nodes/ButtonBox.tsx +++ b/src/client/views/nodes/ButtonBox.tsx @@ -50,7 +50,8 @@ export class ButtonBox extends DocComponent(Butt let scriptingBox = overlayDisposer()} onSave={(text, onError) => { const script = CompileScript(text, { params: { this: Doc.name }, - typecheck: false + typecheck: false, + editable: true }); if (!script.compiled) { onError(script.errors.map(error => error.messageText).join("\n")); -- cgit v1.2.3-70-g09d2 From be1e6e967a60f49eec1cb1d404912b0736812323 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sun, 28 Jul 2019 17:59:00 -0400 Subject: Added ability to capture documents in button scripts --- src/client/views/ScriptBox.tsx | 23 +++++++- src/client/views/ScriptingRepl.tsx | 31 +---------- .../views/collections/CollectionDockingView.tsx | 1 - src/client/views/nodes/ButtonBox.tsx | 6 +- src/client/views/nodes/DocumentIcon.tsx | 65 ++++++++++++++++++++++ 5 files changed, 94 insertions(+), 32 deletions(-) create mode 100644 src/client/views/nodes/DocumentIcon.tsx (limited to 'src/client/views/nodes/ButtonBox.tsx') diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx index fa236c2da..d073945e5 100644 --- a/src/client/views/ScriptBox.tsx +++ b/src/client/views/ScriptBox.tsx @@ -3,11 +3,15 @@ import { observer } from "mobx-react"; import { observable, action } from "mobx"; import "./ScriptBox.scss"; +import { OverlayView } from "./OverlayView"; +import { DocumentIconContainer } from "./nodes/DocumentIcon"; +import { Opt } from "../../new_fields/Doc"; export interface ScriptBoxProps { onSave: (text: string, onError: (error: string) => void) => void; onCancel?: () => void; initialText?: string; + showDocumentIcons?: boolean; } @observer @@ -30,14 +34,31 @@ export class ScriptBox extends React.Component { console.log(error); } + overlayDisposer?: () => void; + onFocus = () => { + if (this.overlayDisposer) { + this.overlayDisposer(); + } + this.overlayDisposer = OverlayView.Instance.addElement(, { x: 0, y: 0 }); + } + + onBlur = () => { + this.overlayDisposer && this.overlayDisposer(); + } + render() { + let onFocus: Opt<() => void> = undefined, onBlur: Opt<() => void> = undefined; + if (this.props.showDocumentIcons) { + onFocus = this.onFocus; + onBlur = this.onBlur; + } return (
- +
); } diff --git a/src/client/views/ScriptingRepl.tsx b/src/client/views/ScriptingRepl.tsx index 0cff145b6..e05195ca0 100644 --- a/src/client/views/ScriptingRepl.tsx +++ b/src/client/views/ScriptingRepl.tsx @@ -4,40 +4,15 @@ import { observable, action } from 'mobx'; import './ScriptingRepl.scss'; import { Scripting, CompileScript, ts, Transformer } from '../util/Scripting'; import { DocumentManager } from '../util/DocumentManager'; -import { DocumentView } from './nodes/DocumentView'; import { OverlayView } from './OverlayView'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { library } from '@fortawesome/fontawesome-svg-core'; import { faCaretDown, faCaretRight } from '@fortawesome/free-solid-svg-icons'; +import { DocumentIconContainer } from './nodes/DocumentIcon'; library.add(faCaretDown); library.add(faCaretRight); -@observer -export class DocumentIcon extends React.Component<{ view: DocumentView, index: number }> { - render() { - const view = this.props.view; - const transform = view.props.ScreenToLocalTransform().scale(view.props.ContentScaling()).inverse(); - const { x, y, width, height } = transform.transformBounds(0, 0, view.props.PanelWidth(), view.props.PanelHeight()); - - return ( -
-

${this.props.index}

-
- ); - } -} - -@observer -export class DocumentIconContainer extends React.Component { - render() { - return DocumentManager.Instance.DocumentViews.map((dv, i) => ); - } -} - @observer export class ScriptingObjectDisplay extends React.Component<{ scrollToBottom: () => void, value: { [key: string]: any }, name?: string }> { @observable collapsed = true; @@ -129,7 +104,7 @@ export class ScriptingRepl extends React.Component { if (ts.isParameter(node.parent)) { // delete knownVars[node.text]; } else if (isntPropAccess && isntPropAssign && !(node.text in knownVars) && !(node.text in globalThis)) { - const match = node.text.match(/\$([0-9]+)/); + const match = node.text.match(/\d([0-9]+)/); if (match) { const m = parseInt(match[1]); usedDocuments.push(m); @@ -153,7 +128,7 @@ export class ScriptingRepl extends React.Component { switch (e.key) { case "Enter": { const docGlobals: { [name: string]: any } = {}; - DocumentManager.Instance.DocumentViews.forEach((dv, i) => docGlobals[`$${i}`] = dv.props.Document); + DocumentManager.Instance.DocumentViews.forEach((dv, i) => docGlobals[`d${i}`] = dv.props.Document); const globals = Scripting.makeMutableGlobalsCopy(docGlobals); const script = CompileScript(this.commandString, { typecheck: false, addReturn: true, editable: true, params: { args: "any" }, transformer: this.getTransformer(), globals }); if (!script.compiled) { diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 0865058be..1859ebee7 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -577,7 +577,6 @@ export class DockedFrameRenderer extends React.Component { return (null); } let resolvedDataDoc = this._document.layout instanceof Doc ? this._document : this._dataDoc; - console.log("pw = " + this.panelWidth() + "," + this.panelHeight() + " " + this.contentScaling()); return (Butt const script = CompileScript(text, { params: { this: Doc.name }, typecheck: false, - editable: true + editable: true, + transformer: DocumentIconContainer.getTransformer() }); if (!script.compiled) { onError(script.errors.map(error => error.messageText).join("\n")); @@ -59,7 +61,7 @@ export class ButtonBox extends DocComponent(Butt } this.Document.onClick = new ScriptField(script); overlayDisposer(); - }} />; + }} showDocumentIcons />; overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, { x: 400, y: 200, width: 500, height: 400, title: `${this.Document.title || ""} OnClick` }); } }); diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx new file mode 100644 index 000000000..f56f5e829 --- /dev/null +++ b/src/client/views/nodes/DocumentIcon.tsx @@ -0,0 +1,65 @@ +import { observer } from "mobx-react"; +import * as React from "react"; +import { DocumentView } from "./DocumentView"; +import { DocumentManager } from "../../util/DocumentManager"; +import { Transformer, Scripting, ts } from "../../util/Scripting"; +import { Field } from "../../../new_fields/Doc"; + +@observer +export class DocumentIcon extends React.Component<{ view: DocumentView, index: number }> { + render() { + const view = this.props.view; + const transform = view.props.ScreenToLocalTransform().scale(view.props.ContentScaling()).inverse(); + const { x, y, width, height } = transform.transformBounds(0, 0, view.props.PanelWidth(), view.props.PanelHeight()); + + return ( +
+

d{this.props.index}

+
+ ); + } +} + +@observer +export class DocumentIconContainer extends React.Component { + public static getTransformer(): Transformer { + const usedDocuments = new Set(); + return { + transformer: context => { + return root => { + function visit(node: ts.Node) { + node = ts.visitEachChild(node, visit, context); + + if (ts.isIdentifier(node)) { + const isntPropAccess = !ts.isPropertyAccessExpression(node.parent) || node.parent.expression === node; + const isntPropAssign = !ts.isPropertyAssignment(node.parent) || node.parent.name !== node; + const isntParameter = !ts.isParameter(node.parent); + if (isntPropAccess && isntPropAssign && isntParameter && !(node.text in globalThis)) { + const match = node.text.match(/d([0-9]+)/); + if (match) { + const m = parseInt(match[1]); + usedDocuments.add(m); + } + } + } + + return node; + } + return ts.visitNode(root, visit); + }; + }, + getVars() { + const docs = DocumentManager.Instance.DocumentViews; + const capturedVariables: { [name: string]: Field } = {}; + usedDocuments.forEach(index => capturedVariables[`d${index}`] = docs[index].props.Document); + return { capturedVariables }; + } + }; + } + render() { + return DocumentManager.Instance.DocumentViews.map((dv, i) => ); + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2