aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Schicke <tyler_schicke@brown.edu>2019-07-28 17:59:00 -0400
committerTyler Schicke <tyler_schicke@brown.edu>2019-07-28 17:59:00 -0400
commitbe1e6e967a60f49eec1cb1d404912b0736812323 (patch)
treed0ea9b9eae9834b44c28fc91794e84bf8a168fc2
parent5fd48d3d10e86cea834f0238ec5d648febb62c81 (diff)
Added ability to capture documents in button scripts
-rw-r--r--src/client/views/ScriptBox.tsx23
-rw-r--r--src/client/views/ScriptingRepl.tsx31
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx1
-rw-r--r--src/client/views/nodes/ButtonBox.tsx6
-rw-r--r--src/client/views/nodes/DocumentIcon.tsx65
5 files changed, 94 insertions, 32 deletions
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<ScriptBoxProps> {
console.log(error);
}
+ overlayDisposer?: () => void;
+ onFocus = () => {
+ if (this.overlayDisposer) {
+ this.overlayDisposer();
+ }
+ this.overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { 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 (
<div className="scriptBox-outerDiv">
<div className="scriptBox-toolbar">
<button onClick={e => { this.props.onSave(this._scriptText, this.onError); e.stopPropagation(); }}>Save</button>
<button onClick={e => { this.props.onCancel && this.props.onCancel(); e.stopPropagation(); }}>Cancel</button>
</div>
- <textarea className="scriptBox-textarea" onChange={this.onChange} value={this._scriptText}></textarea>
+ <textarea className="scriptBox-textarea" onChange={this.onChange} value={this._scriptText} onFocus={onFocus} onBlur={onBlur}></textarea>
</div>
);
}
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,41 +4,16 @@ 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 (
- <div className="documentIcon-outerDiv" style={{
- position: "absolute",
- transform: `translate(${x + width / 2}px, ${y}px)`,
- }}>
- <p>${this.props.index}</p>
- </div>
- );
- }
-}
-
-@observer
-export class DocumentIconContainer extends React.Component {
- render() {
- return DocumentManager.Instance.DocumentViews.map((dv, i) => <DocumentIcon key={i} index={i} view={dv} />);
- }
-}
-
-@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<DockedFrameProps> {
return (null);
}
let resolvedDataDoc = this._document.layout instanceof Doc ? this._document : this._dataDoc;
- console.log("pw = " + this.panelWidth() + "," + this.panelHeight() + " " + this.contentScaling());
return <DocumentView key={this._document[Id]}
Document={this._document}
DataDoc={resolvedDataDoc}
diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx
index 744611661..d2c23fdab 100644
--- a/src/client/views/nodes/ButtonBox.tsx
+++ b/src/client/views/nodes/ButtonBox.tsx
@@ -14,6 +14,7 @@ import { Doc } from '../../../new_fields/Doc';
import './ButtonBox.scss';
import { observer } from 'mobx-react';
+import { DocumentIconContainer } from './DocumentIcon';
library.add(faEdit);
@@ -51,7 +52,8 @@ export class ButtonBox extends DocComponent<FieldViewProps, ButtonDocument>(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<FieldViewProps, ButtonDocument>(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 (
+ <div className="documentIcon-outerDiv" style={{
+ position: "absolute",
+ transform: `translate(${x + width / 2}px, ${y}px)`,
+ }}>
+ <p>d{this.props.index}</p>
+ </div>
+ );
+ }
+}
+
+@observer
+export class DocumentIconContainer extends React.Component {
+ public static getTransformer(): Transformer {
+ const usedDocuments = new Set<number>();
+ 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) => <DocumentIcon key={i} index={i} view={dv} />);
+ }
+} \ No newline at end of file