diff options
Diffstat (limited to 'src/client')
| -rw-r--r-- | src/client/Server.ts | 80 | ||||
| -rw-r--r-- | src/client/SocketStub.ts | 28 | ||||
| -rw-r--r-- | src/client/documents/Documents.ts | 39 | ||||
| -rw-r--r-- | src/client/views/Main.tsx | 132 | ||||
| -rw-r--r-- | src/client/views/collections/CollectionFreeFormView.tsx | 21 | ||||
| -rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 4 |
6 files changed, 212 insertions, 92 deletions
diff --git a/src/client/Server.ts b/src/client/Server.ts index a08fc2e87..e9edb7b9c 100644 --- a/src/client/Server.ts +++ b/src/client/Server.ts @@ -1,42 +1,79 @@ -import { Field, FieldWaiting, FIELD_ID, FIELD_WAITING, FieldValue } from "../fields/Field" +import { Field, FieldWaiting, FIELD_ID, FIELD_WAITING, FieldValue, Opt } 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"; +import { MessageStore, Types } from "./../server/Message"; export class Server { private static ClientFieldsCached: ObservableMap<FIELD_ID, Field | FIELD_WAITING> = new ObservableMap(); - static Socket: SocketIOClient.Socket = OpenSocket("http://localhost:1234") + static Socket: SocketIOClient.Socket = OpenSocket("http://localhost:1234"); static GUID: string = Utils.GenerateGuid() + private static Cache: { [id: string]: Field } = {}; + + @action + static updateField(field: { _id: string, data: any, type: Types }) { + if (field._id in Server.Cache) { + const f = Server.Cache[field._id]; + f.UpdateFromServer(field.data); + f.init(() => { }); + } + } + // 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) { + public static GetField(fieldid: FIELD_ID, callback: (field: Opt<Field>) => void = (f) => { }, hackTimeout: number = -1) { if (!this.ClientFieldsCached.get(fieldid)) { - this.ClientFieldsCached.set(fieldid, FieldWaiting); + // 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)))); + SocketStub.SEND_FIELD_REQUEST(fieldid, (field) => { + if (field) { + this.Cache[field.Id] = field; + } + callback(field) + }); } else if (this.ClientFieldsCached.get(fieldid) != FieldWaiting) { callback(this.ClientFieldsCached.get(fieldid) as Field); } return this.ClientFieldsCached.get(fieldid); } + public static GetFields(fieldIds: FIELD_ID[], callback: (fields: { [id: string]: Field }) => any) { + SocketStub.SEND_FIELDS_REQUEST(fieldIds, (fields) => { + for (let key in fields) { + let field = fields[key]; + this.Cache[field.Id] = field; + } + callback(fields) + }); + } + 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; + // let keyId: string = element[0] + // let valueId: string = element[1] + // Server.GetField(keyId, (key: Field) => { + // if (key instanceof Key) { + // Server.GetField(valueId, (field: Field) => { + // console.log(field) + // doc.Set(key as Key, field) + // }) + // } + // else { + // console.log("how did you get a key that isnt a key wtf") + // } + // }) return this.GetField(doc._proxies.get(key.Id), - action((fieldfromserver: Field) => { - doc._proxies.delete(key.Id); - doc.fields.set(key, fieldfromserver); - }) - , hackTimeout); + action((fieldfromserver: Opt<Field>) => { + if (fieldfromserver) { + doc.fields.set(key.Id, { key, field: fieldfromserver }); + } + })); } public static AddDocument(document: Document) { @@ -48,8 +85,20 @@ export class Server { public static DeleteDocumentField(doc: Document, key: Key) { SocketStub.SEND_DELETE_DOCUMENT_FIELD(doc, key); } + + private static lock: boolean = false; + public static UpdateField(field: Field) { - SocketStub.SEND_SET_FIELD(field); + if (this.lock) { + // setTimeout(this.UpdateField, 1000, field) + } + this.lock = true + // console.log("updating field " + field.Id) + SocketStub.SEND_SET_FIELD(field, (args: any) => { + if (this.lock) { + this.lock = false + } + }); } static connected(message: string) { @@ -68,4 +117,5 @@ export class Server { } } -Server.Socket.on(MessageStore.Foo.Message, Server.connected);
\ No newline at end of file +Server.Socket.on(MessageStore.Foo.Message, Server.connected); +Server.Socket.on(MessageStore.SetField.Message, Server.updateField);
\ No newline at end of file diff --git a/src/client/SocketStub.ts b/src/client/SocketStub.ts index 03c0131ba..7545a166c 100644 --- a/src/client/SocketStub.ts +++ b/src/client/SocketStub.ts @@ -1,10 +1,11 @@ -import { Field, FIELD_ID } from "../fields/Field" +import { Field, FIELD_ID, Opt } from "../fields/Field" import { Key, KeyStore } from "../fields/Key" import { ObservableMap, action } from "mobx"; import { Document } from "../fields/Document" import { MessageStore, SetFieldArgs, GetFieldArgs, DocumentTransfer, Types } from "../server/Message"; import { Utils } from "../Utils"; import { Server } from "./Server"; +import { ServerUtils } from "../server/ServerUtil"; export class SocketStub { @@ -32,13 +33,28 @@ export class SocketStub { Utils.Emit(Server.Socket, MessageStore.AddDocument, new DocumentTransfer(document.ToJson())) } - public static SEND_FIELD_REQUEST(fieldid: FIELD_ID, callback: (field: Field) => void) { + public static SEND_FIELD_REQUEST(fieldid: FIELD_ID, callback: (field: Opt<Field>) => void) { if (fieldid) { - let args: GetFieldArgs = new GetFieldArgs(fieldid) - Utils.EmitCallback(Server.Socket, MessageStore.GetField, args, (field: Field) => callback(field)) + Utils.EmitCallback(Server.Socket, MessageStore.GetField, fieldid, (field: any) => { + if (field) { + ServerUtils.FromJson(field).init(callback); + } else { + callback(undefined); + } + }) } } + public static SEND_FIELDS_REQUEST(fieldIds: FIELD_ID[], callback: (fields: { [key: string]: Field }) => any) { + Utils.EmitCallback(Server.Socket, MessageStore.GetFields, fieldIds, (fields: any[]) => { + let fieldMap: any = {}; + for (let field of fields) { + fieldMap[field._id] = ServerUtils.FromJson(field); + } + callback(fieldMap) + }); + } + 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 @@ -67,12 +83,12 @@ export class SocketStub { document._proxies.delete(key.Id); } - public static SEND_SET_FIELD(field: Field) { + public static SEND_SET_FIELD(field: Field, fn: (args: any) => void) { // 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 - Utils.Emit(Server.Socket, MessageStore.SetField, field.ToJson()) + Utils.EmitCallback(Server.Socket, MessageStore.SetField, field.ToJson(), fn) } } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 460bf9b23..210e63cd3 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -21,6 +21,17 @@ interface DocumentOptions { } export namespace Documents { + export function initProtos(callback: () => void) { + Server.GetFields([collectionProtoId, textProtoId, imageProtoId, schemaProtoId, dockProtoId], (fields) => { + collectionProto = fields[collectionProtoId] as Document; + imageProto = fields[imageProtoId] as Document; + textProto = fields[textProtoId] as Document; + dockProto = fields[dockProtoId] as Document; + schemaProto = fields[schemaProtoId] as Document; + callback() + }); + } + function setupOptions(doc: Document, options: DocumentOptions): void { if (options.x) { doc.SetData(KeyStore.X, options.x, NumberField); @@ -43,9 +54,10 @@ export namespace Documents { } let textProto: Document; + const textProtoId = "textProto"; function GetTextPrototype(): Document { if (!textProto) { - textProto = new Document(); + textProto = new Document(textProtoId); textProto.Set(KeyStore.X, new NumberField(0)); textProto.Set(KeyStore.Y, new NumberField(0)); textProto.Set(KeyStore.Width, new NumberField(300)); @@ -64,9 +76,10 @@ export namespace Documents { } let schemaProto: Document; + const schemaProtoId = "schemaProto"; function GetSchemaPrototype(): Document { if (!schemaProto) { - schemaProto = new Document(); + schemaProto = new Document(schemaProtoId); schemaProto.Set(KeyStore.X, new NumberField(0)); schemaProto.Set(KeyStore.Y, new NumberField(0)); schemaProto.Set(KeyStore.Width, new NumberField(300)); @@ -86,6 +99,7 @@ export namespace Documents { let dockProto: Document; + const dockProtoId = "dockProto"; function GetDockPrototype(): Document { if (!dockProto) { dockProto = new Document(); @@ -107,11 +121,11 @@ export namespace Documents { } - let imageProtoId: FIELD_ID; + let imageProto: Document; + const imageProtoId = "imageProto"; function GetImagePrototype(): Document { - if (imageProtoId === undefined) { - let imageProto = new Document(); - imageProtoId = imageProto.Id; + if (!imageProto) { + imageProto = new Document(imageProtoId); imageProto.Set(KeyStore.Title, new TextField("IMAGE PROTO")); imageProto.Set(KeyStore.X, new NumberField(0)); imageProto.Set(KeyStore.Y, new NumberField(0)); @@ -120,26 +134,23 @@ export namespace Documents { imageProto.Set(KeyStore.Layout, new TextField(ImageBox.LayoutString())); // imageProto.SetField(KeyStore.Layout, new TextField('<div style={"background-image: " + {Data}} />')); imageProto.Set(KeyStore.LayoutKeys, new ListField([KeyStore.Data])); - // Server.AddDocument(imageProto); return imageProto; } - return new Document(); - // return Server.GetField(imageProtoId) as Document; + return imageProto; } export function ImageDocument(url: string, options: DocumentOptions = {}): Document { let doc = GetImagePrototype().MakeDelegate(); setupOptions(doc, options); doc.Set(KeyStore.Data, new ImageField(new URL(url))); - // Server.AddDocument(doc); - // var sdoc = Server.GetField(doc.Id) as Document; return doc; } let collectionProto: Document; + const collectionProtoId = "collectionProto"; function GetCollectionPrototype(): Document { if (!collectionProto) { - collectionProto = new Document(); + collectionProto = new Document(collectionProtoId); collectionProto.Set(KeyStore.X, new NumberField(0)); collectionProto.Set(KeyStore.Y, new NumberField(0)); collectionProto.Set(KeyStore.Scale, new NumberField(1)); @@ -153,8 +164,8 @@ export namespace Documents { return collectionProto; } - export function CollectionDocument(documents: Array<Document>, options: DocumentOptions = {}): Document { - let doc = GetCollectionPrototype().MakeDelegate(); + export function CollectionDocument(documents: Array<Document>, options: DocumentOptions = {}, id?: string): Document { + let doc = GetCollectionPrototype().MakeDelegate(id); setupOptions(doc, options); doc.Set(KeyStore.Data, new ListField(documents)); return doc; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 197529c91..14e60409e 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -14,16 +14,21 @@ import { ContextMenu } from './ContextMenu'; import { DocumentView } from './nodes/DocumentView'; import { ImageField } from '../../fields/ImageField'; import { CompileScript } from './../util/Scripting'; +import { Server } from '../Server'; +import { Utils } from '../../Utils'; +import { ServerUtils } from '../../server/ServerUtil'; +import { MessageStore, DocumentTransfer } from '../../server/Message'; +import { Database } from '../../server/database'; configure({ enforceActions: "observed" }); -const mainNodeCollection = new Array<Document>(); -let mainContainer = Documents.DockDocument(mainNodeCollection, { - x: 0, y: 0, title: "main container" -}) +// const mainNodeCollection = new Array<Document>(); +// let mainContainer = Documents.DockDocument(mainNodeCollection, { +// x: 0, y: 0, title: "main container" +// }) window.addEventListener("drop", function (e) { e.preventDefault(); @@ -54,11 +59,80 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { // schemaDocs[4].SetData(KS.Author, "Bob", TextField); // schemaDocs.push(doc2); // const doc7 = Documents.SchemaDocument(schemaDocs) -const docset: Document[] = []; -let doc4 = Documents.CollectionDocument(docset, { - x: 0, y: 400, title: "mini collection" + +const mainDocId = "mainDoc"; +Documents.initProtos(() => { + Utils.EmitCallback(Server.Socket, MessageStore.GetField, mainDocId, (res: any) => { + console.log("HELLO WORLD") + console.log("RESPONSE: " + res) + let mainContainer: Document; + if (res) { + let obj = ServerUtils.FromJson(res) as Document + mainContainer = obj + } + else { + const docset: Document[] = []; + let doc4 = Documents.CollectionDocument(docset, { + x: 0, y: 400, title: "mini collection" + }, mainDocId); + mainContainer = doc4; + let args = new DocumentTransfer(mainContainer.ToJson()) + Utils.Emit(Server.Socket, MessageStore.AddDocument, args) + } + + let addImageNode = action(() => { + mainContainer.GetList<Document>(KeyStore.Data, []).push(Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { + x: 0, y: 300, width: 200, height: 200, title: "added note" + })); + }) + let addTextNode = action(() => { + mainContainer.GetList<Document>(KeyStore.Data, []).push(Documents.TextDocument({ + x: 0, y: 300, width: 200, height: 200, title: "added note" + })); + }) + let addColNode = action(() => { + mainContainer.GetList<Document>(KeyStore.Data, []).push(Documents.CollectionDocument([], { + x: 0, y: 300, width: 200, height: 200, title: "added note" + })); + }) + + let clearDatabase = action(() => { + Utils.Emit(Server.Socket, MessageStore.DeleteAll, {}); + }) + + ReactDOM.render(( + <div style={{ position: "absolute", width: "100%", height: "100%" }}> + <DocumentView Document={mainContainer} ContainingCollectionView={undefined} DocumentView={undefined} /> + <DocumentDecorations /> + <ContextMenu /> + <button style={{ + position: 'absolute', + bottom: '0px', + left: '0px', + width: '150px' + }} onClick={addImageNode}>Add Image</button> + <button style={{ + position: 'absolute', + bottom: '25px', + left: '0px', + width: '150px' + }} onClick={addTextNode}>Add Text</button> + <button style={{ + position: 'absolute', + bottom: '50px', + left: '0px', + width: '150px' + }} onClick={addColNode}>Add Collection</button> + <button style={{ + position: 'absolute', + bottom: '75px', + left: '0px', + width: '150px' + }} onClick={clearDatabase}>Clear Database</button> + </div>), + document.getElementById('root')); + }) }); -mainContainer = doc4; // let doc5 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { // x: 650, y: 500, width: 600, height: 600, title: "cat 2" // }); @@ -78,45 +152,3 @@ mainContainer = doc4; // mainContainer.Set(KeyStore.Data, mainNodes); //} //); - -let addImageNode = action(() => { - doc4.GetList<Document>(KeyStore.Data, []).push(Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { - x: 0, y: 300, width: 200, height: 200, title: "added note" - })); -}) -let addTextNode = action(() => { - doc4.GetList<Document>(KeyStore.Data, []).push(Documents.TextDocument({ - x: 0, y: 300, width: 200, height: 200, title: "added note" - })); -}) -let addColNode = action(() => { - doc4.GetList<Document>(KeyStore.Data, []).push(Documents.CollectionDocument([], { - x: 0, y: 300, width: 200, height: 200, title: "added note" - })); -}) - -ReactDOM.render(( - <div style={{ position: "absolute", width: "100%", height: "100%" }}> - <DocumentView Document={mainContainer} ContainingCollectionView={undefined} DocumentView={undefined} /> - <DocumentDecorations /> - <ContextMenu /> - <button style={{ - position: 'absolute', - bottom: '0px', - left: '0px', - width: '150px' - }} onClick={addImageNode}>Add Image</button> - <button style={{ - position: 'absolute', - bottom: '25px', - left: '0px', - width: '150px' - }} onClick={addTextNode}>Add Text</button> - <button style={{ - position: 'absolute', - bottom: '50px', - left: '0px', - width: '150px' - }} onClick={addColNode}>Add Collection</button> - </div>), - document.getElementById('root'));
\ No newline at end of file diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx index 9cf29d000..c7ead2f2f 100644 --- a/src/client/views/collections/CollectionFreeFormView.tsx +++ b/src/client/views/collections/CollectionFreeFormView.tsx @@ -17,7 +17,6 @@ import { FieldWaiting } from "../../../fields/Field"; @observer export class CollectionFreeFormView extends CollectionViewBase { public static LayoutString() { return CollectionViewBase.LayoutString("CollectionFreeFormView"); } - private _containerRef = React.createRef<HTMLDivElement>(); private _canvasRef = React.createRef<HTMLDivElement>(); private _nodeContainerRef = React.createRef<HTMLDivElement>(); private _lastX: number = 0; @@ -51,9 +50,13 @@ export class CollectionFreeFormView extends CollectionViewBase { e.stopPropagation(); } - componentDidMount() { - if (this._containerRef.current) { - DragManager.MakeDropTarget(this._containerRef.current, { + private dropDisposer?: DragManager.DragDropDisposer; + createDropTarget = (ele: HTMLDivElement) => { + if (this.dropDisposer) { + this.dropDisposer(); + } + if (ele) { + this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop } @@ -174,7 +177,11 @@ export class CollectionFreeFormView extends CollectionViewBase { render() { const { CollectionFieldKey: fieldKey, DocumentForCollection: Document } = this.props; - const value: Document[] = Document.GetList<Document>(fieldKey, []); + // const value: Document[] = Document.GetList<Document>(fieldKey, []); + const lvalue = Document.GetT<ListField<Document>>(fieldKey, ListField); + if (!lvalue || lvalue === "<Waiting>") { + return <p>Error loading collection data</p> + } const panx: number = Document.GetNumber(KeyStore.PanX, 0); const pany: number = Document.GetNumber(KeyStore.PanY, 0); const currScale: number = Document.GetNumber(KeyStore.Scale, 1); @@ -189,11 +196,11 @@ export class CollectionFreeFormView extends CollectionViewBase { onContextMenu={(e) => e.preventDefault()} onDrop={this.onDrop} onDragOver={this.onDragOver} - ref={this._containerRef}> + ref={this.createDropTarget}> <div className="collectionfreeformview" style={{ transform: `translate(${panx}px, ${pany}px) scale(${currScale}, ${currScale})`, transformOrigin: `left, top` }} ref={this._canvasRef}> <div className="node-container" ref={this._nodeContainerRef}> - {value.map(doc => { + {lvalue.Data.map(doc => { return (<CollectionFreeFormDocumentView key={doc.Id} ContainingCollectionView={this} Document={doc} DocumentView={undefined} />); })} </div> diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 730ce62f2..3df351c6c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -128,6 +128,10 @@ export class DocumentView extends React.Component<DocumentViewProps> { render() { let bindings = { ...this.props } as any; + let lkeys = this.props.Document.GetT(KeyStore.LayoutKeys, ListField); + if (!lkeys || lkeys === "<Waiting>") { + return <p>Error loading layout keys</p>; + } for (const key of this.layoutKeys) { bindings[key.Name + "Key"] = key; // this maps string values of the form <keyname>Key to an actual key Kestore.keyname e.g, "DataKey" => KeyStore.Data } |
