diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/Server.ts | 66 | ||||
-rw-r--r-- | src/client/SocketStub.ts | 78 | ||||
-rw-r--r-- | src/client/documents/Documents.ts (renamed from src/documents/Documents.ts) | 19 | ||||
-rw-r--r-- | src/client/util/DragManager.ts (renamed from src/util/DragManager.ts) | 6 | ||||
-rw-r--r-- | src/client/util/Scripting.ts (renamed from src/util/Scripting.ts) | 25 | ||||
-rw-r--r-- | src/client/util/ScrollBox.tsx (renamed from src/util/ScrollBox.tsx) | 0 | ||||
-rw-r--r-- | src/client/util/SelectionManager.ts (renamed from src/util/SelectionManager.ts) | 0 | ||||
-rw-r--r-- | src/client/util/TypedEvent.ts (renamed from src/util/TypedEvent.ts) | 0 | ||||
-rw-r--r-- | src/client/views/ContextMenu.scss (renamed from src/views/ContextMenu.scss) | 0 | ||||
-rw-r--r-- | src/client/views/ContextMenu.tsx (renamed from src/views/ContextMenu.tsx) | 0 | ||||
-rw-r--r-- | src/client/views/ContextMenuItem.tsx (renamed from src/views/ContextMenuItem.tsx) | 0 | ||||
-rw-r--r-- | src/client/views/DocumentDecorations.scss (renamed from src/DocumentDecorations.scss) | 0 | ||||
-rw-r--r-- | src/client/views/DocumentDecorations.tsx (renamed from src/DocumentDecorations.tsx) | 4 | ||||
-rw-r--r-- | src/client/views/EditableView.tsx | 39 | ||||
-rw-r--r-- | src/client/views/Main.scss (renamed from src/Main.scss) | 0 | ||||
-rw-r--r-- | src/client/views/Main.tsx (renamed from src/Main.tsx) | 37 | ||||
-rw-r--r-- | src/client/views/collections/CollectionDockingView.scss (renamed from src/views/collections/CollectionDockingView.scss) | 10 | ||||
-rw-r--r-- | src/client/views/collections/CollectionDockingView.tsx (renamed from src/views/collections/CollectionDockingView.tsx) | 14 | ||||
-rw-r--r-- | src/client/views/collections/CollectionFreeFormView.scss (renamed from src/views/collections/CollectionFreeFormView.scss) | 0 | ||||
-rw-r--r-- | src/client/views/collections/CollectionFreeFormView.tsx (renamed from src/views/collections/CollectionFreeFormView.tsx) | 39 | ||||
-rw-r--r-- | src/client/views/collections/CollectionSchemaView.scss (renamed from src/views/collections/CollectionSchemaView.scss) | 0 | ||||
-rw-r--r-- | src/client/views/collections/CollectionSchemaView.tsx (renamed from src/views/collections/CollectionSchemaView.tsx) | 39 | ||||
-rw-r--r-- | src/client/views/collections/CollectionViewBase.tsx (renamed from src/views/collections/CollectionViewBase.tsx) | 15 | ||||
-rw-r--r-- | src/client/views/nodes/CollectionFreeFormDocumentView.tsx (renamed from src/views/nodes/CollectionFreeFormDocumentView.tsx) | 7 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx (renamed from src/views/nodes/DocumentView.tsx) | 26 | ||||
-rw-r--r-- | src/client/views/nodes/FieldTextBox.scss (renamed from src/views/nodes/FieldTextBox.scss) | 0 | ||||
-rw-r--r-- | src/client/views/nodes/FieldView.tsx (renamed from src/views/nodes/FieldView.tsx) | 16 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.scss (renamed from src/views/nodes/FormattedTextBox.scss) | 0 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx (renamed from src/views/nodes/FormattedTextBox.tsx) | 12 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.scss (renamed from src/views/nodes/ImageBox.scss) | 0 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx (renamed from src/views/nodes/ImageBox.tsx) | 4 | ||||
-rw-r--r-- | src/client/views/nodes/NodeView.scss (renamed from src/views/nodes/NodeView.scss) | 0 | ||||
-rw-r--r-- | src/fields/Document.ts | 20 | ||||
-rw-r--r-- | src/fields/DocumentReference.ts | 11 | ||||
-rw-r--r-- | src/fields/Field.ts | 16 | ||||
-rw-r--r-- | src/fields/ImageField.ts | 6 | ||||
-rw-r--r-- | src/fields/Key.ts | 3 | ||||
-rw-r--r-- | src/fields/ListField.ts | 4 | ||||
-rw-r--r-- | src/fields/NumberField.ts | 4 | ||||
-rw-r--r-- | src/fields/RichTextField.ts | 4 | ||||
-rw-r--r-- | src/fields/TextField.ts | 4 | ||||
-rw-r--r-- | src/server/index.js | 13 | ||||
-rw-r--r-- | src/server/index.ts | 29 | ||||
-rw-r--r-- | src/stores/NodeCollectionStore.ts | 26 | ||||
-rw-r--r-- | src/stores/NodeStore.ts | 24 | ||||
-rw-r--r-- | src/stores/RootStore.ts | 15 | ||||
-rw-r--r-- | src/stores/StaticTextNodeStore.ts | 16 | ||||
-rw-r--r-- | src/stores/VideoNodeStore.ts | 17 | ||||
-rw-r--r-- | src/views/nodes/TextNodeView.tsx | 28 | ||||
-rw-r--r-- | src/views/nodes/TopBar.tsx | 46 | ||||
-rw-r--r-- | src/views/nodes/VideoNodeView.scss | 5 | ||||
-rw-r--r-- | src/views/nodes/VideoNodeView.tsx | 29 |
52 files changed, 426 insertions, 350 deletions
diff --git a/src/client/Server.ts b/src/client/Server.ts new file mode 100644 index 000000000..66ba92497 --- /dev/null +++ b/src/client/Server.ts @@ -0,0 +1,66 @@ +import { Field, FieldWaiting, FIELD_ID, FIELD_WAITING, FieldValue } from "../fields/Field" +import { Key, KeyStore } from "../fields/Key" +import { ObservableMap, action } from "mobx"; +import { Document } from "../fields/Document" +import { SocketStub } from "./SocketStub"; +import * as OpenSocket from 'socket.io-client'; +import { Utils } from "./../Utils"; +import { MessageStore } from "./../server/Message"; + +export class Server { + private static ClientFieldsCached: ObservableMap<FIELD_ID, Field | FIELD_WAITING> = new ObservableMap(); + static Socket: SocketIOClient.Socket = OpenSocket("http://localhost:8080") + static GUID: string = Utils.GenerateGuid() + + // Retrieves the cached value of the field and sends a request to the server for the real value (if it's not cached). + // Call this is from within a reaction and test whether the return value is FieldWaiting. + // 'hackTimeout' is here temporarily for simplicity when debugging things. + public static GetField(fieldid: FIELD_ID, callback: (field: Field) => void = (f) => { }, hackTimeout: number = -1) { + if (!this.ClientFieldsCached.get(fieldid)) { + this.ClientFieldsCached.set(fieldid, FieldWaiting); + //simulating a server call with a registered callback action + SocketStub.SEND_FIELD_REQUEST(fieldid, + action((field: Field) => callback(Server.cacheField(field))), + hackTimeout); + } else if (this.ClientFieldsCached.get(fieldid) != FieldWaiting) { + callback(this.ClientFieldsCached.get(fieldid) as Field); + } + return this.ClientFieldsCached.get(fieldid); + } + + static times = 0; // hack for testing + public static GetDocumentField(doc: Document, key: Key) { + var hackTimeout: number = key == KeyStore.Data ? (this.times++ == 0 ? 5000 : 1000) : key == KeyStore.X ? 2500 : 500; + + return this.GetField(doc._proxies.get(key), + action((fieldfromserver: Field) => { + doc._proxies.delete(key); + doc.fields.set(key, fieldfromserver); + }) + , hackTimeout); + } + + public static AddDocument(document: Document) { + SocketStub.SEND_ADD_DOCUMENT(document); + } + public static AddDocumentField(doc: Document, key: Key, value: Field) { + SocketStub.SEND_ADD_DOCUMENT_FIELD(doc, key, value); + } + public static DeleteDocumentField(doc: Document, key: Key) { + SocketStub.SEND_DELETE_DOCUMENT_FIELD(doc, key); + } + public static SetFieldValue(field: Field, value: any) { + SocketStub.SEND_SET_FIELD(field, value); + } + + @action + private static cacheField(clientField: Field) { + var cached = this.ClientFieldsCached.get(clientField.Id); + if (!cached || cached == FieldWaiting) { + this.ClientFieldsCached.set(clientField.Id, clientField); + } else { + // probably should overwrite the values within any field that was already here... + } + return this.ClientFieldsCached.get(clientField.Id) as Field; + } +} diff --git a/src/client/SocketStub.ts b/src/client/SocketStub.ts new file mode 100644 index 000000000..58dedbf82 --- /dev/null +++ b/src/client/SocketStub.ts @@ -0,0 +1,78 @@ +import { Field, FIELD_ID } from "../fields/Field" +import { Key, KeyStore } from "../fields/Key" +import { ObservableMap, action } from "mobx"; +import { Document } from "../fields/Document" + +export class SocketStub { + + static FieldStore: ObservableMap<FIELD_ID, Field> = new ObservableMap(); + public static SEND_ADD_DOCUMENT(document: Document) { + + // Send a serialized version of the document to the server + // ...SOCKET(ADD_DOCUMENT, serialied document) + + // server stores each document field in its repository of stored fields + document.fields.forEach((f, key) => this.FieldStore.set((f as Field).Id, f as Field)); + + // server stores stripped down document (w/ only field id proxies) in the field store + this.FieldStore.set(document.Id, new Document(document.Id)); + document.fields.forEach((f, key) => (this.FieldStore.get(document.Id) as Document)._proxies.set(key, (f as Field).Id)); + } + + public static SEND_FIELD_REQUEST(fieldid: FIELD_ID, callback: (field: Field) => void, timeout: number) { + + if (timeout < 0)// this is a hack to make things easier to setup until we have a server... won't be neededa fter that. + callback(this.FieldStore.get(fieldid) as Field); + else { // actual logic here... + + // Send a request for fieldid to the server + // ...SOCKET(RETRIEVE_FIELD, fieldid) + + // server responds (simulated with a timeout) and the callback is invoked + setTimeout(() => + + // when the field data comes back, call the callback() function + callback(this.FieldStore.get(fieldid) as Field), + + + timeout); + } + } + + public static SEND_ADD_DOCUMENT_FIELD(doc: Document, key: Key, value: Field) { + + // Send a serialized version of the field to the server along with the + // associated info of the document id and key where it is used. + + // ...SOCKET(ADD_DOCUMENT_FIELD, document id, key id, serialized field) + + // server updates its document to hold a proxy mapping from key => fieldId + var document = this.FieldStore.get(doc.Id) as Document; + if (document) + document._proxies.set(key, value.Id); + + // server adds the field to its repository of fields + this.FieldStore.set(value.Id, value); + } + + public static SEND_DELETE_DOCUMENT_FIELD(doc: Document, key: Key) { + // Send a request to delete the field stored under the specified key from the document + + // ...SOCKET(DELETE_DOCUMENT_FIELD, document id, key id) + + // Server removes the field id from the document's list of field proxies + var document = this.FieldStore.get(doc.Id) as Document; + if (document) + document._proxies.delete(key); + } + + public static SEND_SET_FIELD(field: Field, value: any) { + // Send a request to set the value of a field + + // ...SOCKET(SET_FIELD, field id, serialized field value) + + // Server updates the value of the field in its fieldstore + if (this.FieldStore.get(field.Id)) + this.FieldStore.get(field.Id)!.TrySetValue(value); + } +} diff --git a/src/documents/Documents.ts b/src/client/documents/Documents.ts index 90124d36c..6925234fe 100644 --- a/src/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1,16 +1,16 @@ -import { Document } from "../fields/Document"; +import { Document } from "../../fields/Document"; import { Server } from "../Server"; -import { KeyStore } from "../fields/Key"; -import { TextField } from "../fields/TextField"; -import { NumberField } from "../fields/NumberField"; -import { ListField } from "../fields/ListField"; +import { KeyStore } from "../../fields/Key"; +import { TextField } from "../../fields/TextField"; +import { NumberField } from "../../fields/NumberField"; +import { ListField } from "../../fields/ListField"; import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import { CollectionSchemaView } from "../views/collections/CollectionSchemaView"; -import { ImageField } from "../fields/ImageField"; +import { ImageField } from "../../fields/ImageField"; import { ImageBox } from "../views/nodes/ImageBox"; import { CollectionFreeFormView } from "../views/collections/CollectionFreeFormView"; -import { FIELD_ID } from "../fields/Field"; +import { FIELD_ID } from "../../fields/Field"; interface DocumentOptions { x?: number; @@ -123,7 +123,7 @@ export namespace Documents { Server.AddDocument(imageProto); return imageProto; } - return Server.GetDocument(imageProtoId, true)!; + return Server.GetField(imageProtoId) as Document; } export function ImageDocument(url: string, options: DocumentOptions = {}): Document { @@ -131,7 +131,8 @@ export namespace Documents { setupOptions(doc, options); doc.Set(KeyStore.Data, new ImageField(new URL(url))); Server.AddDocument(doc); - return Server.GetDocument(doc.Id, true)!; + var sdoc = Server.GetField(doc.Id) as Document; + return sdoc; } let collectionProto: Document; diff --git a/src/util/DragManager.ts b/src/client/util/DragManager.ts index 63d6a88f8..f4dcce7c8 100644 --- a/src/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,9 +1,3 @@ -import { Opt } from "../fields/Field"; -import { CollectionFreeFormDocumentView } from "../views/nodes/CollectionFreeFormDocumentView"; -import { DocumentDecorations } from "../DocumentDecorations"; -import { SelectionManager } from "./SelectionManager"; -import { CollectionDockingView } from "../views/collections/CollectionDockingView"; -import { Document } from "../fields/Document"; export namespace DragManager { export function Root() { diff --git a/src/util/Scripting.ts b/src/client/util/Scripting.ts index 804c67bc5..6bc5fa412 100644 --- a/src/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -1,11 +1,12 @@ // import * as ts from "typescript" let ts = (window as any).ts; -import { Opt, Field, FieldWaiting } from "../fields/Field"; -import { Document as DocumentImport } from "../fields/Document"; -import { NumberField as NumberFieldImport } from "../fields/NumberField"; -import { TextField as TextFieldImport } from "../fields/TextField"; -import { RichTextField as RichTextFieldImport } from "../fields/RichTextField"; -import { KeyStore as KeyStoreImport } from "../fields/Key"; +import { Opt, Field } from "../../fields/Field"; +import { Document as DocumentImport } from "../../fields/Document"; +import { NumberField as NumberFieldImport, NumberField } from "../../fields/NumberField"; +import { ImageField as ImageFieldImport } from "../../fields/ImageField"; +import { TextField as TextFieldImport, TextField } from "../../fields/TextField"; +import { RichTextField as RichTextFieldImport } from "../../fields/RichTextField"; +import { KeyStore as KeyStoreImport } from "../../fields/Key"; export interface ExecutableScript { (): any; @@ -14,7 +15,7 @@ export interface ExecutableScript { } function ExecScript(script: string, diagnostics: Opt<any[]>): ExecutableScript { - const compiled = !(diagnostics && diagnostics != FieldWaiting && diagnostics.some(diag => diag.category == ts.DiagnosticCategory.Error)); + const compiled = !(diagnostics && diagnostics.some(diag => diag.category == ts.DiagnosticCategory.Error)); let func: () => Opt<Field>; if (compiled) { @@ -23,6 +24,7 @@ function ExecScript(script: string, diagnostics: Opt<any[]>): ExecutableScript { let Document = DocumentImport; let NumberField = NumberFieldImport; let TextField = TextFieldImport; + let ImageField = ImageFieldImport; let RichTextField = RichTextFieldImport; let window = undefined; let document = undefined; @@ -44,4 +46,13 @@ export function CompileScript(script: string): ExecutableScript { let result = (window as any).ts.transpileModule(script, {}) return ExecScript(result.outputText, result.diagnostics); +} + +export function ToField(data: any): Opt<Field> { + if (typeof data == "string") { + return new TextField(data); + } else if (typeof data == "number") { + return new NumberField(data); + } + return undefined; }
\ No newline at end of file diff --git a/src/util/ScrollBox.tsx b/src/client/util/ScrollBox.tsx index b6b088170..b6b088170 100644 --- a/src/util/ScrollBox.tsx +++ b/src/client/util/ScrollBox.tsx diff --git a/src/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 0759ae110..0759ae110 100644 --- a/src/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts diff --git a/src/util/TypedEvent.ts b/src/client/util/TypedEvent.ts index 0714a7f5c..0714a7f5c 100644 --- a/src/util/TypedEvent.ts +++ b/src/client/util/TypedEvent.ts diff --git a/src/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index 234f82eb9..234f82eb9 100644 --- a/src/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss diff --git a/src/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 4f26a75d2..4f26a75d2 100644 --- a/src/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx diff --git a/src/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 8f00f8b3d..8f00f8b3d 100644 --- a/src/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx diff --git a/src/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index e8b93a18b..e8b93a18b 100644 --- a/src/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss diff --git a/src/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 1cf875ea5..8a94bff36 100644 --- a/src/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -1,9 +1,9 @@ import { observable, computed } from "mobx"; import React = require("react"); -import { SelectionManager } from "./util/SelectionManager"; +import { SelectionManager } from "../util/SelectionManager"; import { observer } from "mobx-react"; import './DocumentDecorations.scss' -import { CollectionFreeFormView } from "./views/collections/CollectionFreeFormView"; +import { CollectionFreeFormView } from "./collections/CollectionFreeFormView"; @observer export class DocumentDecorations extends React.Component { diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx new file mode 100644 index 000000000..2e784d3f9 --- /dev/null +++ b/src/client/views/EditableView.tsx @@ -0,0 +1,39 @@ +import React = require('react') +import { observer } from 'mobx-react'; +import { observable, action } from 'mobx'; + +export interface EditableProps { + GetValue(): string; + SetValue(value: string): boolean; + contents: any; +} + +@observer +export class EditableView extends React.Component<EditableProps> { + @observable + editing: boolean = false; + + @action + onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { + if (e.key == "Enter" && !e.ctrlKey) { + this.props.SetValue(e.currentTarget.value); + this.editing = false; + } else if (e.key == "Escape") { + this.editing = false; + } + } + + render() { + if (this.editing) { + return <input defaultValue={this.props.GetValue()} onKeyDown={this.onKeyDown} autoFocus onBlur={action(() => this.editing = false)} + style={{ width: "100%" }}></input> + } else { + return ( + <div> + {this.props.contents} + <button onClick={action(() => this.editing = true)}>Edit</button> + </div> + ) + } + } +}
\ No newline at end of file diff --git a/src/Main.scss b/src/client/views/Main.scss index e73f62904..e73f62904 100644 --- a/src/Main.scss +++ b/src/client/views/Main.scss diff --git a/src/Main.tsx b/src/client/views/Main.tsx index 6730cf799..9a359e868 100644 --- a/src/Main.tsx +++ b/src/client/views/Main.tsx @@ -3,16 +3,16 @@ import "normalize.css"; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { DocumentDecorations } from './DocumentDecorations'; -import { Documents } from './documents/Documents'; -import { Document } from './fields/Document'; -import { KeyStore, KeyStore as KS } from './fields/Key'; -import { ListField } from './fields/ListField'; -import { NumberField } from './fields/NumberField'; -import { TextField } from './fields/TextField'; +import { Documents } from '../documents/Documents'; +import { Document } from '../../fields/Document'; +import { KeyStore, KeyStore as KS } from '../../fields/Key'; +import { ListField } from '../../fields/ListField'; +import { NumberField } from '../../fields/NumberField'; +import { TextField } from '../../fields/TextField'; import "./Main.scss"; -import { ContextMenu } from './views/ContextMenu'; -import { DocumentView } from './views/nodes/DocumentView'; -import { CompileScript } from './util/Scripting'; +import { ContextMenu } from './ContextMenu'; +import { DocumentView } from './nodes/DocumentView'; +import { ImageField } from '../../fields/ImageField'; configure({ @@ -44,16 +44,17 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { doc2.Set(KS.X, new NumberField(150)); doc2.Set(KS.Y, new NumberField(20)); let doc3 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { - x: 450, y: 500, title: "cat 1" + x: 450, y: 100, title: "cat 1" }); - // const schemaDocs = Array.from(Array(5).keys()).map(v => Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { - // x: 50 + 100 * v, y: 50, width: 100, height: 100, title: "cat" + v - // })); - // schemaDocs[0].SetData(KS.Author, "Tyler", TextField); - // schemaDocs[4].SetData(KS.Author, "Bob", TextField); - // schemaDocs.push(doc2); - // const doc7 = Documents.SchemaDocument(schemaDocs) - const docset = [doc3]; // [doc1, doc2, doc3, doc7]; + doc3.Set(KeyStore.Data, new ImageField); + const schemaDocs = Array.from(Array(5).keys()).map(v => Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { + x: 50 + 100 * v, y: 50, width: 100, height: 100, title: "cat" + v + })); + schemaDocs[0].SetData(KS.Author, "Tyler", TextField); + schemaDocs[4].SetData(KS.Author, "Bob", TextField); + schemaDocs.push(doc2); + const doc7 = Documents.SchemaDocument(schemaDocs) + const docset = [doc1, doc2, doc3, doc7]; let doc4 = Documents.CollectionDocument(docset, { x: 0, y: 400, title: "mini collection" }); diff --git a/src/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss index db924b57f..7c0b512a7 100644 --- a/src/views/collections/CollectionDockingView.scss +++ b/src/client/views/collections/CollectionDockingView.scss @@ -126,7 +126,7 @@ } .flexlayout__tab_button:hover .flexlayout__tab_button_trailing, .flexlayout__tab_button--selected .flexlayout__tab_button_trailing { - background: transparent url("../../../node_modules/flexlayout-react/images/close_white.png") no-repeat center; + background: transparent url("../../../../node_modules/flexlayout-react/images/close_white.png") no-repeat center; } .flexlayout__tab_button_overflow { float: left; @@ -138,7 +138,7 @@ font-size: 10px; color: lightgray; font-family: Arial, sans-serif; - background: transparent url("../../../node_modules/flexlayout-react/images/more.png") no-repeat left; + background: transparent url("../../../../node_modules/flexlayout-react/images/more.png") no-repeat left; } .flexlayout__tabset_header { position: absolute; @@ -186,14 +186,14 @@ height: 20px; border: none; outline-width: 0; - background: transparent url("../../../node_modules/flexlayout-react/images/maximize.png") no-repeat center; + background: transparent url("../../../../node_modules/flexlayout-react/images/maximize.png") no-repeat center; } .flexlayout__tab_toolbar_button-max { width: 20px; height: 20px; border: none; outline-width: 0; - background: transparent url("../../../node_modules/flexlayout-react/images/restore.png") no-repeat center; + background: transparent url("../../../../node_modules/flexlayout-react/images/restore.png") no-repeat center; } .flexlayout__popup_menu {} .flexlayout__popup_menu_item { @@ -295,7 +295,7 @@ } .flexlayout__border_button:hover .flexlayout__border_button_trailing, .flexlayout__border_button--selected .flexlayout__border_button_trailing { - background: transparent url("../../../node_modules/flexlayout-react/images/close_white.png") no-repeat center; + background: transparent url("../../../../node_modules/flexlayout-react/images/close_white.png") no-repeat center; } .flexlayout__border_toolbar_left { position: absolute; diff --git a/src/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index e489e319a..9aee9c10f 100644 --- a/src/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -1,13 +1,12 @@ import { observer } from "mobx-react"; -import { KeyStore } from "../../fields/Key"; +import { KeyStore } from "../../../fields/Key"; import React = require("react"); import FlexLayout from "flexlayout-react"; import { action, observable, computed } from "mobx"; -import { Document } from "../../fields/Document"; +import { Document } from "../../../fields/Document"; import { DocumentView } from "../nodes/DocumentView"; -import { ListField } from "../../fields/ListField"; -import { NumberField } from "../../fields/NumberField"; -import { SSL_OP_SINGLE_DH_USE } from "constants"; +import { ListField } from "../../../fields/ListField"; +import { NumberField } from "../../../fields/NumberField"; import "./CollectionDockingView.scss" import 'golden-layout/src/css/goldenlayout-base.css'; import 'golden-layout/src/css/goldenlayout-dark-theme.css'; @@ -15,7 +14,6 @@ import * as GoldenLayout from "golden-layout"; import * as ReactDOM from 'react-dom'; import { DragManager } from "../../util/DragManager"; import { CollectionViewBase, CollectionViewProps, COLLECTION_BORDER_WIDTH } from "./CollectionViewBase"; -import { FieldWaiting } from "../../fields/Field"; @observer export class CollectionDockingView extends CollectionViewBase { @@ -70,8 +68,6 @@ export class CollectionDockingView extends CollectionViewBase { @action onResize = (event: any) => { - if (this.props.ContainingDocumentView == FieldWaiting) - return; var cur = this.props.ContainingDocumentView!.MainContent.current; // bcz: since GoldenLayout isn't a React component itself, we need to notify it to resize when its document container's size has changed @@ -255,8 +251,6 @@ export class CollectionDockingView extends CollectionViewBase { render() { - if (this.props.ContainingDocumentView == FieldWaiting) - return; const { CollectionFieldKey: fieldKey, DocumentForCollection: Document } = this.props; const value: Document[] = Document.GetData(fieldKey, ListField, []); // bcz: not sure why, but I need these to force the flexlayout to update when the collection size changes. diff --git a/src/views/collections/CollectionFreeFormView.scss b/src/client/views/collections/CollectionFreeFormView.scss index e9d134e7b..e9d134e7b 100644 --- a/src/views/collections/CollectionFreeFormView.scss +++ b/src/client/views/collections/CollectionFreeFormView.scss diff --git a/src/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx index 45d37ca4f..9cf29d000 100644 --- a/src/views/collections/CollectionFreeFormView.tsx +++ b/src/client/views/collections/CollectionFreeFormView.tsx @@ -1,19 +1,18 @@ import { observer } from "mobx-react"; -import { Key, KeyStore } from "../../fields/Key"; import React = require("react"); import { action, observable, computed } from "mobx"; -import { Document } from "../../fields/Document"; import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; -import { ListField } from "../../fields/ListField"; -import { NumberField } from "../../fields/NumberField"; -import { SSL_OP_SINGLE_DH_USE } from "constants"; -import { Documents } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; import "./CollectionFreeFormView.scss"; -import { Utils } from "../../Utils"; +import { Utils } from "../../../Utils"; import { CollectionViewBase, CollectionViewProps, COLLECTION_BORDER_WIDTH } from "./CollectionViewBase"; import { SelectionManager } from "../../util/SelectionManager"; -import { FieldWaiting } from "../../fields/Field"; +import { Key, KeyStore } from "../../../fields/Key"; +import { Document } from "../../../fields/Document"; +import { ListField } from "../../../fields/ListField"; +import { NumberField } from "../../../fields/NumberField"; +import { Documents } from "../../documents/Documents"; +import { FieldWaiting } from "../../../fields/Field"; @observer export class CollectionFreeFormView extends CollectionViewBase { @@ -33,23 +32,21 @@ export class CollectionFreeFormView extends CollectionViewBase { const doc = de.data["document"]; var me = this; if (doc instanceof CollectionFreeFormDocumentView) { - if (doc.props.ContainingCollectionView && doc.props.ContainingCollectionView !== this && doc.props.ContainingCollectionView != FieldWaiting) { + if (doc.props.ContainingCollectionView && doc.props.ContainingCollectionView !== this) { doc.props.ContainingCollectionView.removeDocument(doc.props.Document); this.addDocument(doc.props.Document); } const xOffset = de.data["xOffset"] as number || 0; const yOffset = de.data["yOffset"] as number || 0; const { scale, translateX, translateY } = Utils.GetScreenTransform(this._canvasRef.current!); - if (this.props.ContainingDocumentView != FieldWaiting) { - let sscale = this.props.ContainingDocumentView!.props.Document.GetData(KeyStore.Scale, NumberField, Number(1)) - const screenX = de.x - xOffset; - const screenY = de.y - yOffset; - const docX = (screenX - translateX) / sscale / scale; - const docY = (screenY - translateY) / sscale / scale; - doc.x = docX; - doc.y = docY; - this.bringToFront(doc); - } + let sscale = this.props.ContainingDocumentView!.props.Document.GetData(KeyStore.Scale, NumberField, Number(1)) + const screenX = de.x - xOffset; + const screenY = de.y - yOffset; + const docX = (screenX - translateX) / sscale / scale; + const docY = (screenY - translateY) / sscale / scale; + doc.x = docX; + doc.y = docY; + this.bringToFront(doc); } e.stopPropagation(); } @@ -88,7 +85,7 @@ export class CollectionFreeFormView extends CollectionViewBase { @action onPointerMove = (e: PointerEvent): void => { var me = this; - if (!e.cancelBubble && this.active && this.props.ContainingDocumentView != FieldWaiting) { + if (!e.cancelBubble && this.active) { e.preventDefault(); e.stopPropagation(); let currScale: number = this.props.ContainingDocumentView!.ScalingToScreenSpace; @@ -105,8 +102,6 @@ export class CollectionFreeFormView extends CollectionViewBase { onPointerWheel = (e: React.WheelEvent): void => { e.stopPropagation(); - if (this.props.ContainingDocumentView == FieldWaiting) - return; let { LocalX, Ss, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY } = this.props.ContainingDocumentView!.TransformToLocalPoint(e.pageX, e.pageY); var deltaScale = (1 - (e.deltaY / 1000)) * Ss; diff --git a/src/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss index 707b44db6..707b44db6 100644 --- a/src/views/collections/CollectionSchemaView.scss +++ b/src/client/views/collections/CollectionSchemaView.scss diff --git a/src/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 8817cb496..2d5bd6c99 100644 --- a/src/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -1,8 +1,6 @@ import React = require("react") import ReactTable, { ReactTableDefaults, CellInfo, ComponentPropsGetterRC, ComponentPropsGetterR } from "react-table"; import { observer } from "mobx-react"; -import { KeyStore as KS, Key } from "../../fields/Key"; -import { Document } from "../../fields/Document"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "react-table/react-table.css" import { observable, action, computed } from "mobx"; @@ -11,6 +9,11 @@ import "./CollectionSchemaView.scss" import { ScrollBox } from "../../util/ScrollBox"; import { CollectionViewBase } from "./CollectionViewBase"; import { DocumentView } from "../nodes/DocumentView"; +import { EditableView } from "../EditableView"; +import { CompileScript, ToField } from "../../util/Scripting"; +import { KeyStore as KS, Key } from "../../../fields/Key"; +import { Document } from "../../../fields/Document"; +import { Field } from "../../../fields/Field"; @observer export class CollectionSchemaView extends CollectionViewBase { @@ -25,9 +28,35 @@ export class CollectionSchemaView extends CollectionViewBase { fieldKey: rowProps.value[1], DocumentViewForField: undefined } - return ( + let contents = ( <FieldView {...props} /> ) + return ( + <EditableView contents={contents} GetValue={() => { + let field = props.doc.Get(props.fieldKey); + if (field && field instanceof Field) { + return field.ToScriptString(); + } + return field || ""; + }} SetValue={(value: string) => { + let script = CompileScript(value); + if (!script.compiled) { + return false; + } + let field = script(); + if (field instanceof Field) { + props.doc.Set(props.fieldKey, field); + return true; + } else { + let dataField = ToField(field); + if (dataField) { + props.doc.Set(props.fieldKey, dataField); + return true; + } + } + return false; + }}></EditableView> + ) } private getTrProps: ComponentPropsGetterR = (state, rowInfo) => { @@ -74,7 +103,9 @@ export class CollectionSchemaView extends CollectionViewBase { [KS.Title, KS.Data, KS.Author]) let content; if (this.selectedIndex != -1) { - content = (<DocumentView Document={children[this.selectedIndex]} DocumentView={undefined} ContainingCollectionView={this} />) + content = ( + <DocumentView Document={children[this.selectedIndex]} DocumentView={undefined} ContainingCollectionView={this} /> + ) } else { content = <div /> } diff --git a/src/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 4fce02ef6..09e8ec729 100644 --- a/src/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -1,9 +1,9 @@ import { action, computed } from "mobx"; import { observer } from "mobx-react"; -import { Document } from "../../fields/Document"; -import { Opt, FieldWaiting } from "../../fields/Field"; -import { Key, KeyStore } from "../../fields/Key"; -import { ListField } from "../../fields/ListField"; +import { Document } from "../../../fields/Document"; +import { Opt } from "../../../fields/Field"; +import { Key, KeyStore } from "../../../fields/Key"; +import { ListField } from "../../../fields/ListField"; import { SelectionManager } from "../../util/SelectionManager"; import { ContextMenu } from "../ContextMenu"; import React = require("react"); @@ -30,10 +30,9 @@ export class CollectionViewBase extends React.Component<CollectionViewProps> { public get active(): boolean { var isSelected = (this.props.ContainingDocumentView instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(this.props.ContainingDocumentView)); var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == this); - var topMost = this.props.ContainingDocumentView != undefined && - this.props.ContainingDocumentView != FieldWaiting && this.props.ContainingDocumentView.props.ContainingCollectionView != FieldWaiting && ( - this.props.ContainingDocumentView.props.ContainingCollectionView == undefined || - this.props.ContainingDocumentView.props.ContainingCollectionView instanceof CollectionDockingView); + var topMost = this.props.ContainingDocumentView != undefined && ( + this.props.ContainingDocumentView.props.ContainingCollectionView == undefined || + this.props.ContainingDocumentView.props.ContainingCollectionView instanceof CollectionDockingView); return isSelected || childSelected || topMost; } @action diff --git a/src/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 25d67d96a..1d53cedc4 100644 --- a/src/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,7 +1,7 @@ import { action, computed } from "mobx"; import { observer } from "mobx-react"; -import { Key, KeyStore } from "../../fields/Key"; -import { NumberField } from "../../fields/NumberField"; +import { Key, KeyStore } from "../../../fields/Key"; +import { NumberField } from "../../../fields/NumberField"; import { DragManager } from "../../util/DragManager"; import { SelectionManager } from "../../util/SelectionManager"; import { CollectionDockingView } from "../collections/CollectionDockingView"; @@ -10,7 +10,6 @@ import { ContextMenu } from "../ContextMenu"; import "./NodeView.scss"; import React = require("react"); import { DocumentView, DocumentViewProps } from "./DocumentView"; -import { FieldWaiting } from "../../fields/Field"; @observer @@ -86,7 +85,7 @@ export class CollectionFreeFormDocumentView extends DocumentView { @computed get active(): boolean { return SelectionManager.IsSelected(this) || this.props.ContainingCollectionView === undefined || - (this.props.ContainingCollectionView != FieldWaiting && this.props.ContainingCollectionView!.active); + this.props.ContainingCollectionView.active; } @computed diff --git a/src/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 81353cd60..730ce62f2 100644 --- a/src/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,12 +1,12 @@ import { action, computed } from "mobx"; import { observer } from "mobx-react"; -import { Document } from "../../fields/Document"; -import { Opt, FieldWaiting } from "../../fields/Field"; -import { Key, KeyStore } from "../../fields/Key"; -import { ListField } from "../../fields/ListField"; -import { NumberField } from "../../fields/NumberField"; -import { TextField } from "../../fields/TextField"; -import { Utils } from "../../Utils"; +import { Document } from "../../../fields/Document"; +import { Opt, FieldWaiting } from "../../../fields/Field"; +import { Key, KeyStore } from "../../../fields/Key"; +import { ListField } from "../../../fields/ListField"; +import { NumberField } from "../../../fields/NumberField"; +import { TextField } from "../../../fields/TextField"; +import { Utils } from "../../../Utils"; import { CollectionDockingView } from "../collections/CollectionDockingView"; import { CollectionFreeFormView } from "../collections/CollectionFreeFormView"; import { CollectionSchemaView } from "../collections/CollectionSchemaView"; @@ -49,8 +49,8 @@ export class DocumentView extends React.Component<DocumentViewProps> { // @computed public get ScalingToScreenSpace(): number { - if (this.props.ContainingCollectionView != undefined && this.props.ContainingCollectionView != FieldWaiting && - this.props.ContainingCollectionView.props.ContainingDocumentView != undefined && this.props.ContainingCollectionView.props.ContainingDocumentView != FieldWaiting) { + if (this.props.ContainingCollectionView != undefined && + this.props.ContainingCollectionView.props.ContainingDocumentView != undefined) { let ss = this.props.ContainingCollectionView.props.DocumentForCollection.GetData(KeyStore.Scale, NumberField, Number(1)); return this.props.ContainingCollectionView.props.ContainingDocumentView.ScalingToScreenSpace * ss; } @@ -63,8 +63,8 @@ export class DocumentView extends React.Component<DocumentViewProps> { public TransformToLocalPoint(screenX: number, screenY: number) { // if this collection view is nested within another collection view, then // first transform the screen point into the parent collection's coordinate space. - let { LocalX: parentX, LocalY: parentY } = this.props.ContainingCollectionView != undefined && this.props.ContainingCollectionView != FieldWaiting && - this.props.ContainingCollectionView.props.ContainingDocumentView != undefined && this.props.ContainingCollectionView.props.ContainingDocumentView != FieldWaiting ? + let { LocalX: parentX, LocalY: parentY } = this.props.ContainingCollectionView != undefined && + this.props.ContainingCollectionView.props.ContainingDocumentView != undefined ? this.props.ContainingCollectionView.props.ContainingDocumentView.TransformToLocalPoint(screenX, screenY) : { LocalX: screenX, LocalY: screenY }; let ContainerX: number = parentX - COLLECTION_BORDER_WIDTH; @@ -113,8 +113,8 @@ export class DocumentView extends React.Component<DocumentViewProps> { // if this collection view is nested within another collection view, then // first transform the local point into the parent collection's coordinate space. - let containingDocView = this.props.ContainingCollectionView != undefined && this.props.ContainingCollectionView != FieldWaiting ? this.props.ContainingCollectionView.props.ContainingDocumentView : undefined; - if (containingDocView != undefined && containingDocView != FieldWaiting) { + let containingDocView = this.props.ContainingCollectionView != undefined ? this.props.ContainingCollectionView.props.ContainingDocumentView : undefined; + if (containingDocView != undefined) { let ss = containingDocView.props.Document.GetData(KeyStore.Scale, NumberField, Number(1)); let panxx = containingDocView.props.Document.GetData(KeyStore.PanX, NumberField, Number(0)) + COLLECTION_BORDER_WIDTH * ss; let panyy = containingDocView.props.Document.GetData(KeyStore.PanY, NumberField, Number(0)) + COLLECTION_BORDER_WIDTH * ss; diff --git a/src/views/nodes/FieldTextBox.scss b/src/client/views/nodes/FieldTextBox.scss index b6ce2fabc..b6ce2fabc 100644 --- a/src/views/nodes/FieldTextBox.scss +++ b/src/client/views/nodes/FieldTextBox.scss diff --git a/src/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 05a7b91b9..12371eb2e 100644 --- a/src/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,15 +1,15 @@ import React = require("react") -import { Document } from "../../fields/Document"; import { observer } from "mobx-react"; import { computed } from "mobx"; -import { Field, Opt, FieldWaiting } from "../../fields/Field"; -import { TextField } from "../../fields/TextField"; -import { NumberField } from "../../fields/NumberField"; -import { RichTextField } from "../../fields/RichTextField"; +import { Field, Opt, FieldWaiting, FieldValue } from "../../../fields/Field"; +import { Document } from "../../../fields/Document"; +import { TextField } from "../../../fields/TextField"; +import { NumberField } from "../../../fields/NumberField"; +import { RichTextField } from "../../../fields/RichTextField"; +import { ImageField } from "../../../fields/ImageField"; +import { Key } from "../../../fields/Key"; import { FormattedTextBox } from "./FormattedTextBox"; -import { ImageField } from "../../fields/ImageField"; import { ImageBox } from "./ImageBox"; -import { Key } from "../../fields/Key"; import { DocumentView } from "./DocumentView"; // @@ -27,7 +27,7 @@ export interface FieldViewProps { export class FieldView extends React.Component<FieldViewProps> { public static LayoutString(fieldType: string) { return `<${fieldType} doc={Document} DocumentViewForField={DocumentView} fieldKey={DataKey} />`; } @computed - get field(): Opt<Field> { + get field(): FieldValue<Field> { const { doc, fieldKey } = this.props; return doc.Get(fieldKey); } diff --git a/src/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index 492367fce..492367fce 100644 --- a/src/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss diff --git a/src/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 3e3e22e46..8bc4c902c 100644 --- a/src/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -6,11 +6,11 @@ import { keymap } from "prosemirror-keymap"; import { schema } from "prosemirror-schema-basic"; import { EditorState, Transaction } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; -import { Opt, FieldWaiting } from "../../fields/Field"; +import { Opt, FieldWaiting, FieldValue } from "../../../fields/Field"; import { SelectionManager } from "../../util/SelectionManager"; import "./FormattedTextBox.scss"; import React = require("react") -import { RichTextField } from "../../fields/RichTextField"; +import { RichTextField } from "../../../fields/RichTextField"; import { FieldViewProps, FieldView } from "./FieldView"; import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView"; @@ -48,7 +48,7 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { } dispatchTransaction = (tx: Transaction) => { - if (this._editorView && this._editorView != FieldWaiting) { + if (this._editorView) { const state = this._editorView.state.apply(tx); this._editorView.updateState(state); const { doc, fieldKey } = this.props; @@ -85,17 +85,17 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { const field = this.props.doc.GetT(this.props.fieldKey, RichTextField); return field && field != FieldWaiting ? field.Data : undefined; }, (field) => { - if (field && this._editorView && this._editorView != FieldWaiting) { + if (field && this._editorView) { this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field))); } }) } componentWillUnmount() { - if (this._editorView && this._editorView != FieldWaiting) { + if (this._editorView) { this._editorView.destroy(); } - if (this._reactionDisposer && this._reactionDisposer != FieldWaiting) { + if (this._reactionDisposer) { this._reactionDisposer(); } } diff --git a/src/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss index 136fda1d0..136fda1d0 100644 --- a/src/views/nodes/ImageBox.scss +++ b/src/client/views/nodes/ImageBox.scss diff --git a/src/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 123c76d19..ab20f140c 100644 --- a/src/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -4,10 +4,10 @@ import 'react-image-lightbox/style.css'; // This only needs to be imported once import { SelectionManager } from "../../util/SelectionManager"; import "./ImageBox.scss"; import React = require("react") -import { ImageField } from '../../fields/ImageField'; +import { ImageField } from '../../../fields/ImageField'; import { FieldViewProps, FieldView } from './FieldView'; import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView'; -import { FieldWaiting } from '../../fields/Field'; +import { FieldWaiting } from '../../../fields/Field'; import { observer } from "mobx-react" import { observable, action } from 'mobx'; diff --git a/src/views/nodes/NodeView.scss b/src/client/views/nodes/NodeView.scss index dac1c0a8e..dac1c0a8e 100644 --- a/src/views/nodes/NodeView.scss +++ b/src/client/views/nodes/NodeView.scss diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 3d74c047c..6f9752a8e 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -1,11 +1,11 @@ -import { Field, Cast, Opt, FieldWaiting, FIELD_ID, DOC_ID } from "./Field" +import { Field, Cast, Opt, FieldWaiting, FIELD_ID, FieldValue } from "./Field" import { Key, KeyStore } from "./Key" import { NumberField } from "./NumberField"; import { ObservableMap, computed, action, observable } from "mobx"; import { TextField } from "./TextField"; import { ListField } from "./ListField"; import { findDOMNode } from "react-dom"; -import { Server } from "../Server"; +import { Server } from "../client/Server"; export class Document extends Field { public fields: ObservableMap<Key, Opt<Field>> = new ObservableMap(); @@ -16,8 +16,8 @@ export class Document extends Field { return this.GetText(KeyStore.Title, "<untitled>"); } - Get(key: Key, ignoreProto: boolean = false): Opt<Field> { - let field: Opt<Field>; + Get(key: Key, ignoreProto: boolean = false): FieldValue<Field> { + let field: FieldValue<Field>; if (ignoreProto) { if (this.fields.has(key)) { field = this.fields.get(key); @@ -25,7 +25,7 @@ export class Document extends Field { field = Server.GetDocumentField(this, key); } } else { - let doc: Opt<Document> = this; + let doc: FieldValue<Document> = this; while (doc && doc != FieldWaiting && field != FieldWaiting) { if (!doc.fields.has(key)) { if (doc._proxies.has(key)) { @@ -46,7 +46,7 @@ export class Document extends Field { return field; } - GetT<T extends Field = Field>(key: Key, ctor: { new(...args: any[]): T }, ignoreProto: boolean = false): Opt<T> { + GetT<T extends Field = Field>(key: Key, ctor: { new(...args: any[]): T }, ignoreProto: boolean = false): FieldValue<T> { var getfield = this.Get(key, ignoreProto); if (getfield != FieldWaiting) { return Cast(getfield, ctor); @@ -119,13 +119,13 @@ export class Document extends Field { this.SetData(key, value, NumberField, replaceWrongType); } - GetPrototype(): Opt<Document> { + GetPrototype(): FieldValue<Document> { return this.GetT(KeyStore.Prototype, Document, true); } GetAllPrototypes(): Document[] { let protos: Document[] = []; - let doc: Opt<Document> = this; + let doc: FieldValue<Document> = this; while (doc && doc != FieldWaiting) { protos.push(doc); doc = doc.GetPrototype(); @@ -141,6 +141,10 @@ export class Document extends Field { return delegate; } + ToScriptString(): string { + return ""; + } + TrySetValue(value: any): boolean { throw new Error("Method not implemented."); } diff --git a/src/fields/DocumentReference.ts b/src/fields/DocumentReference.ts index 10dac9f92..983b162a3 100644 --- a/src/fields/DocumentReference.ts +++ b/src/fields/DocumentReference.ts @@ -1,4 +1,4 @@ -import { Field, Opt } from "./Field"; +import { Field, Opt, FieldValue } from "./Field"; import { Document } from "./Document"; import { Key } from "./Key"; @@ -15,12 +15,12 @@ export class DocumentReference extends Field { super(); } - Dereference(): Opt<Field> { + Dereference(): FieldValue<Field> { return this.document.Get(this.key); } - DereferenceToRoot(): Opt<Field> { - let field: Opt<Field> = this; + DereferenceToRoot(): FieldValue<Field> { + let field: FieldValue<Field> = this; while (field instanceof DocumentReference) { field = field.Dereference(); } @@ -37,5 +37,8 @@ export class DocumentReference extends Field { throw new Error("Method not implemented."); } + ToScriptString(): string { + return ""; + } }
\ No newline at end of file diff --git a/src/fields/Field.ts b/src/fields/Field.ts index 9880116c0..6adee9b61 100644 --- a/src/fields/Field.ts +++ b/src/fields/Field.ts @@ -1,7 +1,7 @@ import { Utils } from "../Utils"; -export function Cast<T extends Field>(field: Opt<Field>, ctor: { new(): T }): Opt<T> { +export function Cast<T extends Field>(field: FieldValue<Field>, ctor: { new(): T }): Opt<T> { if (field) { if (ctor && field instanceof ctor) { return field; @@ -13,8 +13,8 @@ export function Cast<T extends Field>(field: Opt<Field>, ctor: { new(): T }): Op export let FieldWaiting: FIELD_WAITING = "<Waiting>"; export type FIELD_WAITING = "<Waiting>"; export type FIELD_ID = string | undefined; -export type DOC_ID = FIELD_ID; -export type Opt<T> = T | undefined | FIELD_WAITING; +export type Opt<T> = T | undefined; +export type FieldValue<T> = Opt<T> | FIELD_WAITING; export abstract class Field { //FieldUpdated: TypedEvent<Opt<FieldUpdatedArgs>> = new TypedEvent<Opt<FieldUpdatedArgs>>(); @@ -28,18 +28,18 @@ export abstract class Field { this.id = id || Utils.GenerateGuid(); } - Dereference(): Opt<Field> { + Dereference(): FieldValue<Field> { return this; } - DereferenceToRoot(): Opt<Field> { + DereferenceToRoot(): FieldValue<Field> { return this; } - DereferenceT<T extends Field = Field>(ctor: { new(): T }): Opt<T> { + DereferenceT<T extends Field = Field>(ctor: { new(): T }): FieldValue<T> { return Cast(this.Dereference(), ctor); } - DereferenceToRootT<T extends Field = Field>(ctor: { new(): T }): Opt<T> { + DereferenceToRootT<T extends Field = Field>(ctor: { new(): T }): FieldValue<T> { return Cast(this.DereferenceToRoot(), ctor); } @@ -47,6 +47,8 @@ export abstract class Field { return this.id === other.id; } + abstract ToScriptString(): string; + abstract TrySetValue(value: any): boolean; abstract GetValue(): any; diff --git a/src/fields/ImageField.ts b/src/fields/ImageField.ts index bc2e7cdf4..d82260f54 100644 --- a/src/fields/ImageField.ts +++ b/src/fields/ImageField.ts @@ -3,13 +3,17 @@ import { Field } from "./Field"; export class ImageField extends BasicField<URL> { constructor(data: URL | undefined = undefined) { - super(data == undefined ? new URL("http://cs.brown.edu/~bcz/face.gif") : data); + super(data == undefined ? new URL("http://cs.brown.edu/~bcz/bob_fettucine.jpg") : data); } toString(): string { return this.Data.href; } + ToScriptString(): string { + return `new ImageField("${this.Data}")`; + } + Copy(): Field { return new ImageField(this.Data); } diff --git a/src/fields/Key.ts b/src/fields/Key.ts index 5cd43f55e..993102613 100644 --- a/src/fields/Key.ts +++ b/src/fields/Key.ts @@ -27,6 +27,9 @@ export class Key extends Field { return this; } + ToScriptString(): string { + return name; + } } diff --git a/src/fields/ListField.ts b/src/fields/ListField.ts index 8607ebe43..8843338c1 100644 --- a/src/fields/ListField.ts +++ b/src/fields/ListField.ts @@ -6,6 +6,10 @@ export class ListField<T extends Field> extends BasicField<T[]> { super(data.slice()); } + ToScriptString(): string { + return "new ListField([" + this.Data.map(field => field.ToScriptString()).join(", ") + "])"; + } + Copy(): Field { return new ListField<T>(this.Data); } diff --git a/src/fields/NumberField.ts b/src/fields/NumberField.ts index c3444f644..03926d696 100644 --- a/src/fields/NumberField.ts +++ b/src/fields/NumberField.ts @@ -5,6 +5,10 @@ export class NumberField extends BasicField<number> { super(data); } + ToScriptString(): string { + return "new NumberField(this.Data)"; + } + Copy() { return new NumberField(this.Data); } diff --git a/src/fields/RichTextField.ts b/src/fields/RichTextField.ts index 24c7472d8..4a77c669c 100644 --- a/src/fields/RichTextField.ts +++ b/src/fields/RichTextField.ts @@ -5,6 +5,10 @@ export class RichTextField extends BasicField<string> { super(data); } + ToScriptString(): string { + return `new RichTextField(${this.Data})`; + } + Copy() { return new RichTextField(this.Data); } diff --git a/src/fields/TextField.ts b/src/fields/TextField.ts index 95825d2ae..11d2ed7cd 100644 --- a/src/fields/TextField.ts +++ b/src/fields/TextField.ts @@ -5,6 +5,10 @@ export class TextField extends BasicField<string> { super(data); } + ToScriptString(): string { + return `new TextField("${this.Data}")`; + } + Copy() { return new TextField(this.Data); } diff --git a/src/server/index.js b/src/server/index.js new file mode 100644 index 000000000..15e763f9d --- /dev/null +++ b/src/server/index.js @@ -0,0 +1,13 @@ +"use strict"; +exports.__esModule = true; +var express = require("express"); +var app = express(); +var port = 8080; // default port to listen +// define a route handler for the default home page +app.get("/", function (req, res) { + res.send("Hello world!"); +}); +// start the Express server +app.listen(port, function () { + console.log("server started at http://localhost:" + port); +}); diff --git a/src/server/index.ts b/src/server/index.ts new file mode 100644 index 000000000..640ad8180 --- /dev/null +++ b/src/server/index.ts @@ -0,0 +1,29 @@ +import * as express from 'express' +const app = express() +import * as webpack from 'webpack' +import * as wdm from 'webpack-dev-middleware'; +import * as whm from 'webpack-hot-middleware'; +import * as path from 'path' +const config = require('../../webpack.config') +const compiler = webpack(config) +const port = 1050; // default port to listen + +// define a route handler for the default home page +app.get("/", (req, res) => { + res.sendFile(path.join(__dirname, '../../deploy/index.html')); +}); + +app.get("/hello", (req, res) => { + res.send("<p>Hello</p>"); +}) + +app.use(wdm(compiler, { + publicPath: config.output.publicPath +})) + +app.use(whm(compiler)) + +// start the Express server +app.listen(port, () => { + console.log(`server started at http://localhost:${port}`); +});
\ No newline at end of file diff --git a/src/stores/NodeCollectionStore.ts b/src/stores/NodeCollectionStore.ts deleted file mode 100644 index 7fac83d51..000000000 --- a/src/stores/NodeCollectionStore.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { computed, observable, action } from "mobx"; -import { NodeStore } from "./NodeStore"; -import { Document } from "../fields/Document"; - -export class NodeCollectionStore extends NodeStore { - - @observable - public Scale: number = 1; - - @observable - public Nodes: NodeStore[] = new Array<NodeStore>(); - - @observable - public Docs: Document[] = []; - - @computed - public get Transform(): string { - const halfWidth = window.innerWidth / 2, halfHeight = window.innerHeight / 2; - return `translate(${this.X + halfWidth}px, ${this.Y + halfHeight}px) scale(${this.Scale}) translate(${-halfWidth}px, ${-halfHeight}px)`; - } - - @action - public AddNodes(stores: NodeStore[]): void { - stores.forEach(store => this.Nodes.push(store)); - } -}
\ No newline at end of file diff --git a/src/stores/NodeStore.ts b/src/stores/NodeStore.ts deleted file mode 100644 index 6a734cf44..000000000 --- a/src/stores/NodeStore.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { computed, observable } from "mobx"; -import { Utils } from "../Utils"; - -export class NodeStore { - - public Id: string = Utils.GenerateGuid(); - - @observable - public X: number = 0; - - @observable - public Y: number = 0; - - @observable - public Width: number = 0; - - @observable - public Height: number = 0; - - @computed - public get Transform(): string { - return "translate(" + this.X + "px, " + this.Y + "px)"; - } -}
\ No newline at end of file diff --git a/src/stores/RootStore.ts b/src/stores/RootStore.ts deleted file mode 100644 index 847fb6807..000000000 --- a/src/stores/RootStore.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { action, observable } from "mobx"; - -// This globally accessible store might come in handy, although you may decide that you don't need it. -export class RootStore { - - private constructor() { - // initialization code - } - - private static _instance: RootStore; - - public static get Instance(): RootStore { - return this._instance || (this._instance = new this()); - } -}
\ No newline at end of file diff --git a/src/stores/StaticTextNodeStore.ts b/src/stores/StaticTextNodeStore.ts deleted file mode 100644 index 7c342a7a2..000000000 --- a/src/stores/StaticTextNodeStore.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { observable } from "mobx"; -import { NodeStore } from "./NodeStore"; - -export class StaticTextNodeStore extends NodeStore { - - constructor(initializer: Partial<StaticTextNodeStore>) { - super(); - Object.assign(this, initializer); - } - - @observable - public Title: string = ""; - - @observable - public Text: string = ""; -}
\ No newline at end of file diff --git a/src/stores/VideoNodeStore.ts b/src/stores/VideoNodeStore.ts deleted file mode 100644 index e5187ab07..000000000 --- a/src/stores/VideoNodeStore.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { observable } from "mobx"; -import { NodeStore } from "./NodeStore"; - -export class VideoNodeStore extends NodeStore { - - constructor(initializer: Partial<VideoNodeStore>) { - super(); - Object.assign(this, initializer); - } - - @observable - public Title: string = ""; - - @observable - public Url: string = ""; - -}
\ No newline at end of file diff --git a/src/views/nodes/TextNodeView.tsx b/src/views/nodes/TextNodeView.tsx deleted file mode 100644 index ab762df12..000000000 --- a/src/views/nodes/TextNodeView.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import {observer} from "mobx-react"; -import {StaticTextNodeStore} from "../../stores/StaticTextNodeStore"; -import "./NodeView.scss"; -import {TopBar} from "./TopBar"; -import React = require("react"); - -interface IProps { - store: StaticTextNodeStore; -} - -@observer -export class TextNodeView extends React.Component<IProps> { - - render() { - let store = this.props.store; - return ( - <div className="node text-node" style={{transform: store.Transform}}> - <TopBar store={store} /> - <div className="scroll-box"> - <div className="content"> - <h3 className="title">{store.Title}</h3> - <p className="paragraph">{store.Text}</p> - </div> - </div> - </div> - ); - } -}
\ No newline at end of file diff --git a/src/views/nodes/TopBar.tsx b/src/views/nodes/TopBar.tsx deleted file mode 100644 index bb126e8b5..000000000 --- a/src/views/nodes/TopBar.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { observer } from "mobx-react"; -import { NodeStore } from "../../stores/NodeStore"; -import "./NodeView.scss"; -import React = require("react"); - -interface IProps { - store: NodeStore; -} - -@observer -export class TopBar extends React.Component<IProps> { - - private _isPointerDown = false; - - onPointerDown = (e: React.PointerEvent): void => { - e.stopPropagation(); - e.preventDefault(); - this._isPointerDown = true; - document.removeEventListener("pointermove", this.onPointerMove); - document.addEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); - document.addEventListener("pointerup", this.onPointerUp); - } - - onPointerUp = (e: PointerEvent): void => { - e.stopPropagation(); - e.preventDefault(); - this._isPointerDown = false; - document.removeEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); - } - - onPointerMove = (e: PointerEvent): void => { - e.stopPropagation(); - e.preventDefault(); - if (!this._isPointerDown) { - return; - } - this.props.store.X += e.movementX; - this.props.store.Y += e.movementY; - } - - render() { - return <div className="top" onPointerDown={this.onPointerDown}></div> - } -} diff --git a/src/views/nodes/VideoNodeView.scss b/src/views/nodes/VideoNodeView.scss deleted file mode 100644 index f412c3519..000000000 --- a/src/views/nodes/VideoNodeView.scss +++ /dev/null @@ -1,5 +0,0 @@ -.node { - video { - width: 100%; - } -}
\ No newline at end of file diff --git a/src/views/nodes/VideoNodeView.tsx b/src/views/nodes/VideoNodeView.tsx deleted file mode 100644 index 0a7b3d174..000000000 --- a/src/views/nodes/VideoNodeView.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { observer } from "mobx-react"; -import { VideoNodeStore } from "../../stores/VideoNodeStore"; -import "./NodeView.scss"; -import { TopBar } from "./TopBar"; -import "./VideoNodeView.scss"; -import React = require("react"); - -interface IProps { - store: VideoNodeStore; -} - -@observer -export class VideoNodeView extends React.Component<IProps> { - - render() { - let store = this.props.store; - return ( - <div className="node text-node" style={{ transform: store.Transform }}> - <TopBar store={store} /> - <div className="scroll-box"> - <div className="content"> - <h3 className="title">{store.Title}</h3> - <video src={store.Url} controls /> - </div> - </div> - </div> - ); - } -}
\ No newline at end of file |