diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/documents/Documents.ts | 2 | ||||
-rw-r--r-- | src/client/northstar/dash-fields/HistogramField.ts | 2 | ||||
-rw-r--r-- | src/client/northstar/operations/HistogramOperation.ts | 4 | ||||
-rw-r--r-- | src/client/util/DragManager.ts | 6 | ||||
-rw-r--r-- | src/client/util/Scripting.ts | 95 | ||||
-rw-r--r-- | src/client/util/Transform.ts | 14 | ||||
-rw-r--r-- | src/client/views/Main.tsx | 63 | ||||
-rw-r--r-- | src/client/views/collections/CollectionSchemaView.tsx | 26 | ||||
-rw-r--r-- | src/client/views/collections/CollectionTreeView.scss | 86 | ||||
-rw-r--r-- | src/client/views/collections/CollectionTreeView.tsx | 14 | ||||
-rw-r--r-- | src/client/views/collections/CollectionViewBase.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/KeyValueBox.tsx | 6 | ||||
-rw-r--r-- | src/client/views/nodes/KeyValuePair.tsx | 6 | ||||
-rw-r--r-- | src/fields/Document.ts | 30 | ||||
-rw-r--r-- | src/fields/KeyStore.ts | 104 | ||||
-rw-r--r-- | src/fields/NumberField.ts | 2 |
16 files changed, 272 insertions, 190 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 1b1485c12..aa109e779 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -44,6 +44,7 @@ export interface DocumentOptions { layoutKeys?: Key[]; viewType?: number; backgroundColor?: string; + copyDraggedItems?: boolean; } export namespace Documents { @@ -87,6 +88,7 @@ export namespace Documents { if (options.ink !== undefined) { doc.Set(KeyStore.Ink, new InkField(options.ink)); } if (options.layout !== undefined) { doc.SetText(KeyStore.Layout, options.layout); } if (options.layoutKeys !== undefined) { doc.Set(KeyStore.LayoutKeys, new ListField(options.layoutKeys)); } + if (options.copyDraggedItems !== undefined) { doc.SetBoolean(KeyStore.CopyDraggedItems, options.copyDraggedItems); } return doc; } diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index f939ccd83..fa2a9c008 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -27,7 +27,7 @@ export class HistogramField extends BasicField<HistogramOperation> { } Copy(): Field { - return new HistogramField(this.Data); + return new HistogramField(this.Data.Copy()); } ToScriptString(): string { diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts index 7f48d1629..a3ddc1c98 100644 --- a/src/client/northstar/operations/HistogramOperation.ts +++ b/src/client/northstar/operations/HistogramOperation.ts @@ -42,6 +42,10 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons this.SchemaName = schemaName; } + Copy(): HistogramOperation { + return new HistogramOperation(this.SchemaName, this.X, this.Y, this.V, this.Normalization); + } + Equals(other: Object): boolean { throw new Error("Method not implemented."); } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 80ddd1878..c3d63f887 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -8,7 +8,7 @@ import { DocumentDecorations } from "../views/DocumentDecorations"; import { DocumentView } from "../views/nodes/DocumentView"; import { returnFalse } from "../../Utils"; -export function setupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc: () => Document, moveFunc?: DragManager.MoveFunction) { +export function setupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc: () => Document, moveFunc?: DragManager.MoveFunction, copyOnDrop: boolean = false) { let onRowMove = action((e: PointerEvent): void => { e.stopPropagation(); e.preventDefault(); @@ -16,6 +16,7 @@ export function setupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc: document.removeEventListener("pointermove", onRowMove); document.removeEventListener('pointerup', onRowUp); var dragData = new DragManager.DocumentDragData([docFunc()]); + dragData.copyOnDrop = copyOnDrop; dragData.moveDocument = moveFunc; DragManager.StartDocumentDrag([_reference.current!], dragData, e.x, e.y); }); @@ -119,13 +120,14 @@ export namespace DragManager { xOffset?: number; yOffset?: number; aliasOnDrop?: boolean; + copyOnDrop?: boolean; moveDocument?: MoveFunction; [id: string]: any; } export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) { StartDrag(eles, dragData, downX, downY, options, - (dropData: { [id: string]: any }) => (dropData.droppedDocuments = dragData.aliasOnDrop ? dragData.draggedDocuments.map(d => d.CreateAlias()) : dragData.draggedDocuments)); + (dropData: { [id: string]: any }) => (dropData.droppedDocuments = dragData.aliasOnDrop ? dragData.draggedDocuments.map(d => d.CreateAlias()) : dragData.copyOnDrop ? dragData.draggedDocuments.map(d => d.Copy(true) as Document) : dragData.draggedDocuments)); } export class LinkDragData { diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 8aef44a3a..bf9b8266f 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -18,39 +18,57 @@ import * as typescriptlib from '!!raw-loader!./type_decls.d' import { Documents } from "../documents/Documents"; import { Key } from "../../fields/Key"; +export interface ScriptSucccess { + success: true; + result: any; +} + +export interface ScriptError { + success: false; + error: any; +} + +export type ScriptResult = ScriptSucccess | ScriptError; -export interface ExecutableScript { - (): any; +export interface CompileSuccess { + compiled: true; + run(args?: { [name: string]: any }): ScriptResult; +} - compiled: boolean; +export interface CompileError { + compiled: false; + errors: any[]; } -function Compile(script: string | undefined, diagnostics: Opt<any[]>, scope: { [name: string]: any }): ExecutableScript { - const compiled = !(diagnostics && diagnostics.some(diag => diag.category === ts.DiagnosticCategory.Error)); +export type CompiledScript = CompileSuccess | CompileError; + +function Run(script: string | undefined, customParams: string[], diagnostics: any[]): CompiledScript { + const errors = diagnostics.some(diag => diag.category === ts.DiagnosticCategory.Error); + if (errors || !script) { + return { compiled: false, errors: diagnostics }; + } - let func: () => Opt<Field>; - if (compiled && script) { - let fieldTypes = [Document, NumberField, TextField, ImageField, RichTextField, ListField, Key]; - let paramNames = ["KeyStore", "Documents", ...fieldTypes.map(fn => fn.name)]; - let params: any[] = [KeyStore, Documents, ...fieldTypes] - for (let prop in scope) { - if (prop === "this") { + let fieldTypes = [Document, NumberField, TextField, ImageField, RichTextField, ListField, Key]; + let paramNames = ["KeyStore", "Documents", ...fieldTypes.map(fn => fn.name)]; + let params: any[] = [KeyStore, Documents, ...fieldTypes] + let compiledFunction = new Function(...paramNames, `return ${script}`); + let run = (args: { [name: string]: any } = {}): ScriptResult => { + let argsArray: any[] = []; + for (let name of customParams) { + if (name === "this") { continue; } - paramNames.push(prop); - params.push(scope[prop]); + argsArray.push(args[name]); + } + let thisParam = args.this; + try { + const result = compiledFunction.apply(thisParam, params).apply(thisParam, argsArray); + return { success: true, result }; + } catch (error) { + return { success: false, error }; } - let thisParam = scope.this; - let compiledFunction = new Function(...paramNames, script); - func = function (): Opt<Field> { - return compiledFunction.apply(thisParam, params) - }; - } else { - func = () => undefined; } - - Object.assign(func, { compiled }); - return func as ExecutableScript; + return { compiled: true, run }; } interface File { @@ -106,20 +124,39 @@ class ScriptingCompilerHost { } } -export function CompileScript(script: string, scope?: { [name: string]: any }, addReturn: boolean = false): ExecutableScript { +export interface ScriptOptions { + requiredType?: string; + addReturn?: boolean; + params?: { [name: string]: string }; +} + +export function CompileScript(script: string, { requiredType = "", addReturn = false, params = {} }: ScriptOptions = {}): CompiledScript { let host = new ScriptingCompilerHost; - let funcScript = `(function() { + let paramArray: string[] = []; + if ("this" in params) { + paramArray.push("this"); + } + for (const key in params) { + if (key === "this") continue; + paramArray.push(key); + } + let paramString = paramArray.map(key => `${key}: ${params[key]}`).join(", "); + let funcScript = `(function(${paramString})${requiredType ? `: ${requiredType}` : ''} { ${addReturn ? `return ${script};` : script} - }).apply(this)` + })`; host.writeFile("file.ts", funcScript); host.writeFile('node_modules/typescript/lib/lib.d.ts', typescriptlib); let program = ts.createProgram(["file.ts"], {}, host); let testResult = program.emit(); - let outputText = "return " + host.readFile("file.js"); + let outputText = host.readFile("file.js"); let diagnostics = ts.getPreEmitDiagnostics(program).concat(testResult.diagnostics); - return Compile(outputText, diagnostics, scope || {}); + return Run(outputText, paramArray, diagnostics); +} + +export function OrLiteralType(returnType: string): string { + return `${returnType} | string | number`; } export function ToField(data: any): Opt<Field> { diff --git a/src/client/util/Transform.ts b/src/client/util/Transform.ts index 54effd512..ed4282874 100644 --- a/src/client/util/Transform.ts +++ b/src/client/util/Transform.ts @@ -17,45 +17,45 @@ export class Transform { this._scale = scale; } - translate = (x: number, y: number): Transform => { + translate = (x: number, y: number): this => { this._translateX += x; this._translateY += y; return this; } - scale = (scale: number): Transform => { + scale = (scale: number): this => { this._scale *= scale; this._translateX *= scale; this._translateY *= scale; return this; } - scaleAbout = (scale: number, x: number, y: number): Transform => { + scaleAbout = (scale: number, x: number, y: number): this => { this._translateX += x * this._scale - x * this._scale * scale; this._translateY += y * this._scale - y * this._scale * scale; this._scale *= scale; return this; } - transform = (transform: Transform): Transform => { + transform = (transform: Transform): this => { this._translateX = transform._translateX + transform._scale * this._translateX; this._translateY = transform._translateY + transform._scale * this._translateY; this._scale *= transform._scale; return this; } - preTranslate = (x: number, y: number): Transform => { + preTranslate = (x: number, y: number): this => { this._translateX += this._scale * x; this._translateY += this._scale * y; return this; } - preScale = (scale: number): Transform => { + preScale = (scale: number): this => { this._scale *= scale; return this; } - preTransform = (transform: Transform): Transform => { + preTransform = (transform: Transform): this => { this._translateX += transform._translateX * this._scale; this._translateY += transform._translateY * this._scale; this._scale *= transform._scale; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index bffe4fb11..b78d5a8f9 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -1,57 +1,42 @@ -import { action, configure, observable, runInAction, trace, computed, reaction } from 'mobx'; +import { IconName, library } from '@fortawesome/fontawesome-svg-core'; +import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faTree, faUndoAlt } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, computed, configure, observable, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; import "normalize.css"; import * as React from 'react'; import * as ReactDOM from 'react-dom'; +import Measure from 'react-measure'; +import * as request from 'request'; import { Document } from '../../fields/Document'; +import { Field, FieldWaiting, Opt } from '../../fields/Field'; import { KeyStore } from '../../fields/KeyStore'; -import "./Main.scss"; +import { ListField } from '../../fields/ListField'; +import { WorkspacesMenu } from '../../server/authentication/controllers/WorkspacesMenu'; +import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { MessageStore } from '../../server/Message'; import { Utils, returnTrue, emptyFunction } from '../../Utils'; -import * as request from 'request' import * as rp from 'request-promise' +import { RouteStore } from '../../server/RouteStore'; +import { ServerUtils } from '../../server/ServerUtil'; import { Documents } from '../documents/Documents'; +import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel'; +import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel'; +import { Gateway, Settings } from '../northstar/manager/Gateway'; +import { AggregateFunction, Catalog } from '../northstar/model/idea/idea'; +import '../northstar/model/ModelExtensions'; +import { HistogramOperation } from '../northstar/operations/HistogramOperation'; +import '../northstar/utils/Extensions'; import { Server } from '../Server'; import { setupDrag } from '../util/DragManager'; import { Transform } from '../util/Transform'; -import { UndoManager, undoBatch } from '../util/UndoManager'; -import { WorkspacesMenu } from '../../server/authentication/controllers/WorkspacesMenu'; +import { UndoManager } from '../util/UndoManager'; import { CollectionDockingView } from './collections/CollectionDockingView'; import { ContextMenu } from './ContextMenu'; import { DocumentDecorations } from './DocumentDecorations'; -import { DocumentView } from './nodes/DocumentView'; -import "./Main.scss"; -import { observer } from 'mobx-react'; import { InkingControl } from './InkingControl'; -import { RouteStore } from '../../server/RouteStore'; -import { library, IconName } from '@fortawesome/fontawesome-svg-core'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faFont } from '@fortawesome/free-solid-svg-icons'; -import { faImage } from '@fortawesome/free-solid-svg-icons'; -import { faFilePdf } from '@fortawesome/free-solid-svg-icons'; -import { faObjectGroup } from '@fortawesome/free-solid-svg-icons'; -import { faTable } from '@fortawesome/free-solid-svg-icons'; -import { faGlobeAsia } from '@fortawesome/free-solid-svg-icons'; -import { faUndoAlt } from '@fortawesome/free-solid-svg-icons'; -import { faRedoAlt } from '@fortawesome/free-solid-svg-icons'; -import { faPenNib } from '@fortawesome/free-solid-svg-icons'; -import { faFilm } from '@fortawesome/free-solid-svg-icons'; -import { faMusic } from '@fortawesome/free-solid-svg-icons'; -import { faTree } from '@fortawesome/free-solid-svg-icons'; -import Measure from 'react-measure'; -import { DashUserModel } from '../../server/authentication/models/user_model'; -import { ServerUtils } from '../../server/ServerUtil'; -import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; -import { Field, Opt, FieldWaiting } from '../../fields/Field'; -import { ListField } from '../../fields/ListField'; -import { Gateway, Settings } from '../northstar/manager/Gateway'; -import { Catalog, Schema, Attribute, AttributeGroup, AggregateFunction } from '../northstar/model/idea/idea'; -import { ArrayUtil } from '../northstar/utils/ArrayUtil'; -import '../northstar/model/ModelExtensions' -import '../northstar/utils/Extensions' -import { HistogramOperation } from '../northstar/operations/HistogramOperation'; -import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel'; -import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel'; -import { CollectionView } from './collections/CollectionView'; +import "./Main.scss"; +import { DocumentView } from './nodes/DocumentView'; @observer export class Main extends React.Component { @@ -246,7 +231,7 @@ export class Main extends React.Component { let addTextNode = action(() => Documents.TextDocument({ width: 200, height: 200, title: "a text note" })) let addColNode = action(() => Documents.FreeformDocument([], { width: 200, height: 200, title: "a freeform collection" })); let addSchemaNode = action(() => Documents.SchemaDocument([], { width: 200, height: 200, title: "a schema collection" })); - let addTreeNode = action(() => Documents.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas" })); + let addTreeNode = action(() => Documents.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", copyDraggedItems: true })); let addVideoNode = action(() => Documents.VideoDocument(videourl, { width: 200, height: 200, title: "video node" })); let addPDFNode = action(() => Documents.PdfDocument(pdfurl, { width: 200, height: 200, title: "a schema collection" })); let addImageNode = action(() => Documents.ImageDocument(imgurl, { width: 200, height: 200, title: "an image of a cat" })); diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 3817d5333..4604945d1 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -91,12 +91,10 @@ export class CollectionSchemaView extends CollectionViewBase { ) let reference = React.createRef<HTMLDivElement>(); let onItemDown = setupDrag(reference, () => props.Document, this.props.moveDocument); - let applyToDoc = (doc: Document, value: string) => { - let script = CompileScript(value, { this: doc }, true); - if (!script.compiled) { - return false; - } - let field = script(); + let applyToDoc = (doc: Document, run: (args?: { [name: string]: any }) => any) => { + const res = run({ this: doc }); + if (!res.success) return false; + const field = res.result; if (field instanceof Field) { doc.Set(props.fieldKey, field); return true; @@ -122,11 +120,23 @@ export class CollectionSchemaView extends CollectionViewBase { } return field || ""; }} - SetValue={(value: string) => applyToDoc(props.Document, value)} + SetValue={(value: string) => { + let script = CompileScript(value, { addReturn: true, params: { this: "Document" } }); + if (!script.compiled) { + return false; + } + return applyToDoc(props.Document, script.run); + }} OnFillDown={(value: string) => { + let script = CompileScript(value, { addReturn: true, params: { this: "Document" } }); + if (!script.compiled) { + return; + } + const run = script.run; + //TODO This should be able to be refactored to compile the script once this.props.Document.GetTAsync<ListField<Document>>(this.props.fieldKey, ListField).then((val) => { if (val) { - val.Data.forEach(doc => applyToDoc(doc, value)); + val.Data.forEach(doc => applyToDoc(doc, run)); } }) }}> diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index 5a14aa54d..f2affbf55 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -1,64 +1,62 @@ @import "../global_variables"; -#body { + +.collectionTreeView-dropTarget { + border: 0px solid transparent; + border-radius: $border-radius; + box-sizing: border-box; + height: 100%; padding: 20px; padding-left: 10px; padding-right: 0px; background: $light-color-secondary; font-size: 13px; overflow: scroll; -} -ul { - list-style: none; - padding-left: 20px; -} + ul { + list-style: none; + padding-left: 20px; + } -li { - margin: 5px 0; -} + li { + margin: 5px 0; + } -.collection-child { - margin-top: 10px; - margin-bottom: 10px; -} + .collection-child { + margin-top: 10px; + margin-bottom: 10px; + } -.no-indent { - padding-left: 0; -} + .no-indent { + padding-left: 0; + } -.bullet { - width: 1.5em; - display: inline-block; - color: $intermediate-color; -} + .bullet { + width: 1.5em; + display: inline-block; + color: $intermediate-color; + } -.coll-title { - font-size: 24px; - margin-bottom: 20px; -} + .coll-title { + font-size: 24px; + margin-bottom: 20px; + } -.collectionTreeView-dropTarget { - border: 0px solid transparent; - border-radius: $border-radius; - box-sizing: border-box; - height: 100%; -} + .docContainer { + display: inline-table; + } -.docContainer { - display: inline-table; -} + .docContainer:hover { + .delete-button { + display: inline; + width: auto; + } + } -.docContainer:hover { .delete-button { + color: $intermediate-color; + float: right; + margin-left: 15px; + margin-top: 3px; display: inline; - width: auto; } -} - -.delete-button { - color: $intermediate-color; - float: right; - margin-left: 15px; - margin-top: 3px; - display: inline; }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 32d74164d..dce35868e 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -14,12 +14,14 @@ import { CollectionView } from "./CollectionView"; import { CollectionViewBase } from "./CollectionViewBase"; import React = require("react") import { COLLECTION_BORDER_WIDTH } from './CollectionBaseView'; +import { props } from 'bluebird'; export interface TreeViewProps { document: Document; deleteDoc: (doc: Document) => void; moveDocument: DragManager.MoveFunction; + copyOnDrag: boolean; } export enum BulletType { @@ -75,7 +77,7 @@ class TreeView extends React.Component<TreeViewProps> { */ renderTitle() { let reference = React.createRef<HTMLDivElement>(); - let onItemDown = setupDrag(reference, () => this.props.document, this.props.moveDocument); + let onItemDown = setupDrag(reference, () => this.props.document, this.props.moveDocument, this.props.copyOnDrag); let editableView = (titleString: string) => (<EditableView display={"inline"} @@ -97,14 +99,13 @@ class TreeView extends React.Component<TreeViewProps> { render() { let bulletType = BulletType.List; let childElements: JSX.Element | undefined = undefined; - var children = this.props.document.GetT<ListField<Document>>(KeyStore.Data, ListField); if (children && children !== FieldWaiting) { // add children for a collection if (!this._collapsed) { bulletType = BulletType.Collapsible; childElements = <ul> - {children.Data.map(value => <TreeView key={value.Id} document={value} deleteDoc={this.remove} moveDocument={this.move} />)} - </ul> + {children.Data.map(value => <TreeView key={value.Id} document={value} deleteDoc={this.remove} moveDocument={this.move} copyOnDrag={this.props.copyOnDrag} />)} + </ul > } else bulletType = BulletType.Collapsed; } @@ -130,10 +131,11 @@ export class CollectionTreeView extends CollectionViewBase { } render() { - var children = this.props.Document.GetT<ListField<Document>>(KeyStore.Data, ListField); + let children = this.props.Document.GetT<ListField<Document>>(KeyStore.Data, ListField); + let copyOnDrag = this.props.Document.GetBoolean(KeyStore.CopyDraggedItems, false); let childrenElement = !children || children === FieldWaiting ? (null) : (children.Data.map(value => - <TreeView document={value} key={value.Id} deleteDoc={this.remove} moveDocument={this.props.moveDocument} />) + <TreeView document={value} key={value.Id} deleteDoc={this.remove} moveDocument={this.props.moveDocument} copyOnDrag={copyOnDrag} />) ) return ( diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 446b1c240..84d378e1c 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -70,7 +70,7 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps> @action protected drop(e: Event, de: DragManager.DropEvent): boolean { if (de.data instanceof DragManager.DocumentDragData) { - if (de.data.aliasOnDrop) { + if (de.data.aliasOnDrop || de.data.copyOnDrop) { [KeyStore.Width, KeyStore.Height, KeyStore.CurPage].map(key => de.data.draggedDocuments.map((draggedDocument: Document, i: number) => draggedDocument.GetTAsync(key, NumberField, (f: Opt<NumberField>) => f ? de.data.droppedDocuments[i].SetNumber(key, f.Data) : null))); diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 9958a7c5a..8a7f32e6d 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -40,11 +40,13 @@ export class KeyValueBox extends React.Component<FieldViewProps> { } let realDoc = doc; - let script = CompileScript(this._valueInput, undefined, true); + let script = CompileScript(this._valueInput, { addReturn: true }); if (!script.compiled) { return; } - let field = script(); + let res = script.run(); + if (!res.success) return; + const field = res.result; if (field instanceof Field) { realDoc.Set(new Key(this._keyInput), field); } else { diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index a676844dc..c6a0a7296 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -81,11 +81,13 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> { return field || ""; }} SetValue={(value: string) => { - let script = CompileScript(value, undefined, true); + let script = CompileScript(value, { addReturn: true }); if (!script.compiled) { return false; } - let field = script(); + let res = script.run(); + if (!res.success) return false; + const field = res.result; if (field instanceof Field) { props.Document.Set(props.fieldKey, field); return true; diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 3f26abbda..4fa478f32 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -10,6 +10,9 @@ import { Types } from "../server/Message"; import { UndoManager } from "../client/util/UndoManager"; import { HtmlField } from "./HtmlField"; import { BooleanField } from "./BooleanField"; +import { allLimit } from "async"; +import { prototype } from "nodemailer/lib/smtp-pool"; +import { HistogramField } from "../client/northstar/dash-fields/HistogramField"; export class Document extends Field { //TODO tfs: We should probably store FieldWaiting in fields when we request it from the server so that we don't set up multiple server gets for the same document and field @@ -330,7 +333,10 @@ export class Document extends Field { SetText(key: Key, value: string, replaceWrongType = true) { this.SetData(key, value, TextField, replaceWrongType); } - + @action + SetBoolean(key: Key, value: boolean, replaceWrongType = true) { + this.SetData(key, value, BooleanField, replaceWrongType); + } @action SetNumber(key: Key, value: number, replaceWrongType = true) { this.SetData(key, value, NumberField, replaceWrongType); @@ -380,8 +386,26 @@ export class Document extends Field { return title; //throw new Error("Method not implemented."); } - Copy(): Field { - throw new Error("Method not implemented."); + Copy(copyProto?: boolean, id?: string): Field { + let copy = new Document(); + this._proxies.forEach((fieldid, keyid) => { // copy each prototype field + let key = KeyStore.KeyLookup(keyid); + if (key) { + this.GetAsync(key, (field: Opt<Field>) => { + if (key === KeyStore.Prototype && copyProto) { // handle prototype field specially + if (field instanceof Document) { + copy.Set(key, field.Copy(false)); // only copying one level of prototypes for now... + } + } + else + if (field instanceof Document) // ... TODO bcz: should we copy documents or reference them + copy.Set(key!, field) + else if (field) + copy.Set(key!, field.Copy()) + }) + } + }); + return copy; } ToJson(): { type: Types; data: [string, string][]; _id: string } { diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index 6ed3b1604..e24e9c8ec 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -2,49 +2,63 @@ import { Key } from "./Key"; import { KeyTransfer } from "../server/Message"; export namespace KeyStore { - export const Prototype = new Key("Prototype"); - export const X = new Key("X"); - export const Y = new Key("Y"); - export const Page = new Key("Page"); - export const Title = new Key("Title"); - export const Author = new Key("Author"); - export const PanX = new Key("PanX"); - export const PanY = new Key("PanY"); - export const Scale = new Key("Scale"); - export const NativeWidth = new Key("NativeWidth"); - export const NativeHeight = new Key("NativeHeight"); - export const Width = new Key("Width"); - export const Height = new Key("Height"); - export const ZIndex = new Key("ZIndex"); - export const Data = new Key("Data"); - export const Annotations = new Key("Annotations"); - export const ViewType = new Key("ViewType"); - export const Layout = new Key("Layout"); - export const BackgroundColor = new Key("BackgroundColor"); - export const BackgroundLayout = new Key("BackgroundLayout"); - export const OverlayLayout = new Key("OverlayLayout"); - export const LayoutKeys = new Key("LayoutKeys"); - export const LayoutFields = new Key("LayoutFields"); - export const ColumnsKey = new Key("SchemaColumns"); - export const SchemaSplitPercentage = new Key("SchemaSplitPercentage"); - export const Caption = new Key("Caption"); - export const ActiveWorkspace = new Key("ActiveWorkspace"); - export const DocumentText = new Key("DocumentText"); - export const BrushingDocs = new Key("BrushingDocs"); - export const LinkedToDocs = new Key("LinkedToDocs"); - export const LinkedFromDocs = new Key("LinkedFromDocs"); - export const LinkDescription = new Key("LinkDescription"); - export const LinkTags = new Key("LinkTag"); - export const Thumbnail = new Key("Thumbnail"); - export const ThumbnailPage = new Key("ThumbnailPage"); - export const CurPage = new Key("CurPage"); - export const AnnotationOn = new Key("AnnotationOn"); - export const NumPages = new Key("NumPages"); - export const Ink = new Key("Ink"); - export const Cursors = new Key("Cursors"); - export const OptionalRightCollection = new Key("OptionalRightCollection"); - export const Archives = new Key("Archives"); - export const Updated = new Key("Updated"); - export const Workspaces = new Key("Workspaces"); - export const Minimized = new Key("Minimized"); + export const Prototype = new Key("Prototype"); + export const X = new Key("X"); + export const Y = new Key("Y"); + export const Page = new Key("Page"); + export const Title = new Key("Title"); + export const Author = new Key("Author"); + export const PanX = new Key("PanX"); + export const PanY = new Key("PanY"); + export const Scale = new Key("Scale"); + export const NativeWidth = new Key("NativeWidth"); + export const NativeHeight = new Key("NativeHeight"); + export const Width = new Key("Width"); + export const Height = new Key("Height"); + export const ZIndex = new Key("ZIndex"); + export const Data = new Key("Data"); + export const Annotations = new Key("Annotations"); + export const ViewType = new Key("ViewType"); + export const Layout = new Key("Layout"); + export const BackgroundColor = new Key("BackgroundColor"); + export const BackgroundLayout = new Key("BackgroundLayout"); + export const OverlayLayout = new Key("OverlayLayout"); + export const LayoutKeys = new Key("LayoutKeys"); + export const LayoutFields = new Key("LayoutFields"); + export const ColumnsKey = new Key("SchemaColumns"); + export const SchemaSplitPercentage = new Key("SchemaSplitPercentage"); + export const Caption = new Key("Caption"); + export const ActiveWorkspace = new Key("ActiveWorkspace"); + export const DocumentText = new Key("DocumentText"); + export const BrushingDocs = new Key("BrushingDocs"); + export const LinkedToDocs = new Key("LinkedToDocs"); + export const LinkedFromDocs = new Key("LinkedFromDocs"); + export const LinkDescription = new Key("LinkDescription"); + export const LinkTags = new Key("LinkTag"); + export const Thumbnail = new Key("Thumbnail"); + export const ThumbnailPage = new Key("ThumbnailPage"); + export const CurPage = new Key("CurPage"); + export const AnnotationOn = new Key("AnnotationOn"); + export const NumPages = new Key("NumPages"); + export const Ink = new Key("Ink"); + export const Cursors = new Key("Cursors"); + export const OptionalRightCollection = new Key("OptionalRightCollection"); + export const Archives = new Key("Archives"); + export const Workspaces = new Key("Workspaces"); + export const Minimized = new Key("Minimized"); + export const CopyDraggedItems = new Key("CopyDraggedItems"); + + export const KeyList: Key[] = [Prototype, X, Y, Page, Title, Author, PanX, PanY, Scale, NativeWidth, NativeHeight, + Width, Height, ZIndex, Data, Annotations, ViewType, Layout, BackgroundColor, BackgroundLayout, OverlayLayout, LayoutKeys, + LayoutFields, ColumnsKey, SchemaSplitPercentage, Caption, ActiveWorkspace, DocumentText, BrushingDocs, LinkedToDocs, LinkedFromDocs, + LinkDescription, LinkTags, Thumbnail, ThumbnailPage, CurPage, AnnotationOn, NumPages, Ink, Cursors, OptionalRightCollection, + Archives, Workspaces, Minimized, CopyDraggedItems + ]; + export function KeyLookup(keyid: string) { + for (const key of KeyList) { + if (key.Id === keyid) + return key; + } + return undefined; + } } diff --git a/src/fields/NumberField.ts b/src/fields/NumberField.ts index 47dfc74cb..e0c8648de 100644 --- a/src/fields/NumberField.ts +++ b/src/fields/NumberField.ts @@ -8,7 +8,7 @@ export class NumberField extends BasicField<number> { } ToScriptString(): string { - return "new NumberField(this.Data)"; + return `new NumberField(${this.Data})`; } Copy() { |