diff options
Diffstat (limited to 'src/fields')
-rw-r--r-- | src/fields/BasicField.ts | 19 | ||||
-rw-r--r-- | src/fields/Document.ts | 58 | ||||
-rw-r--r-- | src/fields/DocumentReference.ts | 4 | ||||
-rw-r--r-- | src/fields/Field.ts | 10 | ||||
-rw-r--r-- | src/fields/HtmlField.ts | 25 | ||||
-rw-r--r-- | src/fields/ImageField.ts | 4 | ||||
-rw-r--r-- | src/fields/Key.ts | 2 | ||||
-rw-r--r-- | src/fields/KeyStore.ts | 13 | ||||
-rw-r--r-- | src/fields/ListField.ts | 40 | ||||
-rw-r--r-- | src/fields/NumberField.ts | 4 | ||||
-rw-r--r-- | src/fields/RichTextField.ts | 4 | ||||
-rw-r--r-- | src/fields/TextField.ts | 6 |
12 files changed, 145 insertions, 44 deletions
diff --git a/src/fields/BasicField.ts b/src/fields/BasicField.ts index 15eb067a0..a92c4a236 100644 --- a/src/fields/BasicField.ts +++ b/src/fields/BasicField.ts @@ -1,9 +1,10 @@ -import { Field, FIELD_ID } from "./Field" +import { Field, FieldId } from "./Field" import { observable, computed, action } from "mobx"; import { Server } from "../client/Server"; +import { UndoManager } from "../client/util/UndoManager"; export abstract class BasicField<T> extends Field { - constructor(data: T, save: boolean, id: FIELD_ID = undefined) { + constructor(data: T, save: boolean, id?: FieldId) { super(id); this.data = data; @@ -27,12 +28,22 @@ export abstract class BasicField<T> extends Field { } set Data(value: T) { - if (this.data != value) { - this.data = value; + if (this.data === value) { + return; } + let oldValue = this.data; + this.setData(value); + UndoManager.AddEvent({ + undo: () => this.Data = oldValue, + redo: () => this.Data = value + }) Server.UpdateField(this); } + protected setData(value: T) { + this.data = value; + } + @action TrySetValue(value: any): boolean { if (typeof value == typeof this.data) { diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 3067621be..0d7d357a0 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -1,16 +1,17 @@ -import { Field, Cast, Opt, FieldWaiting, FIELD_ID, FieldValue } from "./Field" import { Key } from "./Key" import { KeyStore } from "./KeyStore"; +import { Field, Cast, FieldWaiting, FieldValue, FieldId } from "./Field" import { NumberField } from "./NumberField"; -import { ObservableMap, computed, action, observable } from "mobx"; +import { ObservableMap, computed, action } from "mobx"; import { TextField } from "./TextField"; import { ListField } from "./ListField"; import { Server } from "../client/Server"; import { Types } from "../server/Message"; +import { UndoManager } from "../client/util/UndoManager"; export class Document extends Field { public fields: ObservableMap<string, { key: Key, field: Field }> = new ObservableMap(); - public _proxies: ObservableMap<string, FIELD_ID> = new ObservableMap(); + public _proxies: ObservableMap<string, FieldId> = new ObservableMap(); constructor(id?: string, save: boolean = true) { super(id) @@ -29,6 +30,10 @@ export class Document extends Field { } } + public Width = () => { return this.GetNumber(KeyStore.Width, 0) } + public Height = () => { return this.GetNumber(KeyStore.Height, 0) } + public Scale = () => { return this.GetNumber(KeyStore.Scale, 1) } + @computed public get Title() { return this.GetText(KeyStore.Title, "<untitled>"); @@ -40,7 +45,17 @@ export class Document extends Field { if (this.fields.has(key.Id)) { field = this.fields.get(key.Id)!.field; } else if (this._proxies.has(key.Id)) { - field = Server.GetDocumentField(this, key); + Server.GetDocumentField(this, key); + /* + The field might have been instantly filled from the cache + Maybe we want to just switch back to returning the value + from Server.GetDocumentField if it's in the cache + */ + if (this.fields.has(key.Id)) { + field = this.fields.get(key.Id)!.field; + } else { + field = FieldWaiting; + } } } else { let doc: FieldValue<Document> = this; @@ -49,7 +64,17 @@ export class Document extends Field { let curProxy = doc._proxies.get(key.Id); if (!curField || (curProxy && curField.field.Id !== curProxy)) { if (curProxy) { - field = Server.GetDocumentField(doc, key); + Server.GetDocumentField(doc, key); + /* + The field might have been instantly filled from the cache + Maybe we want to just switch back to returning the value + from Server.GetDocumentField if it's in the cache + */ + if (this.fields.has(key.Id)) { + field = this.fields.get(key.Id)!.field; + } else { + field = FieldWaiting; + } break; } if ((doc.fields.has(KeyStore.Prototype.Id) || doc._proxies.has(KeyStore.Prototype.Id))) { @@ -69,6 +94,15 @@ export class Document extends Field { return field; } + GetAsync(key: Key, callback: (field: Field) => void): boolean { + //This currently doesn't deal with prototypes + if (this._proxies.has(key.Id)) { + Server.GetDocumentField(this, key, callback); + return true; + } + return false; + } + 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) { @@ -107,7 +141,8 @@ export class Document extends Field { @action Set(key: Key, field: Field | undefined): void { - console.log("Assign: " + key.Name + " = " + (field ? field.GetValue() : "<undefined>") + " (" + (field ? field.Id : "<undefined>") + ")"); + let old = this.fields.get(key.Id); + let oldField = old ? old.field : undefined; if (field) { this.fields.set(key.Id, { key, field }); this._proxies.set(key.Id, field.Id) @@ -117,6 +152,12 @@ export class Document extends Field { this._proxies.delete(key.Id) // Server.DeleteDocumentField(this, key); } + if (oldField || field) { + UndoManager.AddEvent({ + undo: () => this.Set(key, oldField), + redo: () => this.Set(key, field) + }) + } Server.UpdateField(this); } @@ -124,16 +165,13 @@ export class Document extends Field { SetData<T, U extends Field & { Data: T }>(key: Key, value: T, ctor: { new(): U }, replaceWrongType = true) { let field = this.Get(key, true); - //if (field != WAITING) { // do we want to wait for the field to come back from the server to set it, or do we overwrite? if (field instanceof ctor) { field.Data = value; - // Server.SetFieldValue(field, value); } else if (!field || replaceWrongType) { let newField = new ctor(); newField.Data = value; this.Set(key, newField); } - //} } @action @@ -185,14 +223,12 @@ export class Document extends Field { } ToJson(): { type: Types, data: [string, string][], _id: string } { - // console.log(this.fields) let fields: [string, string][] = [] this._proxies.forEach((field, key) => { if (field) { fields.push([key, field as string]) } }); - // console.log(fields) return { type: Types.Document, diff --git a/src/fields/DocumentReference.ts b/src/fields/DocumentReference.ts index 4096cbb92..9d3c209b4 100644 --- a/src/fields/DocumentReference.ts +++ b/src/fields/DocumentReference.ts @@ -1,4 +1,4 @@ -import { Field, Opt, FieldValue, FIELD_ID } from "./Field"; +import { Field, Opt, FieldValue, FieldId } from "./Field"; import { Document } from "./Document"; import { Key } from "./Key"; import { Types } from "../server/Message"; @@ -47,7 +47,7 @@ export class DocumentReference extends Field { return ""; } - ToJson(): { type: Types, data: FIELD_ID, _id: string } { + ToJson(): { type: Types, data: FieldId, _id: string } { return { type: Types.DocumentReference, data: this.document.Id, diff --git a/src/fields/Field.ts b/src/fields/Field.ts index 853fb9327..c7e0232af 100644 --- a/src/fields/Field.ts +++ b/src/fields/Field.ts @@ -11,9 +11,9 @@ export function Cast<T extends Field>(field: FieldValue<Field>, ctor: { new(): T return undefined; } -export let FieldWaiting: FIELD_WAITING = "<Waiting>"; +export const FieldWaiting: FIELD_WAITING = "<Waiting>"; export type FIELD_WAITING = "<Waiting>"; -export type FIELD_ID = string | undefined; +export type FieldId = string; export type Opt<T> = T | undefined; export type FieldValue<T> = Opt<T> | FIELD_WAITING; @@ -24,12 +24,12 @@ export abstract class Field { callback(this); } - private id: string; - get Id(): string { + private id: FieldId; + get Id(): FieldId { return this.id; } - constructor(id: FIELD_ID = undefined) { + constructor(id: Opt<FieldId> = undefined) { this.id = id || Utils.GenerateGuid(); } diff --git a/src/fields/HtmlField.ts b/src/fields/HtmlField.ts new file mode 100644 index 000000000..a07326095 --- /dev/null +++ b/src/fields/HtmlField.ts @@ -0,0 +1,25 @@ +import { BasicField } from "./BasicField"; +import { Types } from "../server/Message"; +import { FieldId } from "./Field"; + +export class HtmlField extends BasicField<string> { + constructor(data: string = "<html></html>", id?: FieldId, save: boolean = true) { + super(data, save, id); + } + + ToScriptString(): string { + return `new HtmlField("${this.Data}")`; + } + + Copy() { + return new HtmlField(this.Data); + } + + ToJson(): { _id: string; type: Types; data: any; } { + return { + type: Types.Html, + data: this.Data, + _id: this.Id, + } + } +}
\ No newline at end of file diff --git a/src/fields/ImageField.ts b/src/fields/ImageField.ts index aba011199..b2226d55a 100644 --- a/src/fields/ImageField.ts +++ b/src/fields/ImageField.ts @@ -1,10 +1,10 @@ import { BasicField } from "./BasicField"; -import { Field, FIELD_ID } from "./Field"; +import { Field, FieldId } from "./Field"; import { Types } from "../server/Message"; import { ObjectID } from "bson"; export class ImageField extends BasicField<URL> { - constructor(data: URL | undefined = undefined, id: FIELD_ID = undefined, save: boolean = true) { + constructor(data: URL | undefined = undefined, id?: FieldId, save: boolean = true) { super(data == undefined ? new URL("http://cs.brown.edu/~bcz/bob_fettucine.jpg") : data, save, id); } diff --git a/src/fields/Key.ts b/src/fields/Key.ts index d3958df2d..c16a00878 100644 --- a/src/fields/Key.ts +++ b/src/fields/Key.ts @@ -1,4 +1,4 @@ -import { Field, FIELD_ID } from "./Field" +import { Field, FieldId } from "./Field" import { Utils } from "../Utils"; import { observable } from "mobx"; import { Types } from "../server/Message"; diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index 1e0b12729..a3b39735d 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -9,16 +9,21 @@ export namespace KeyStore { 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 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 function Get(name: string): Key { - return new Key(name) - } + export const Caption = new Key("Caption"); + export const ActiveFrame = new Key("ActiveFrame"); + export const DocumentText = new Key("DocumentText"); } diff --git a/src/fields/ListField.ts b/src/fields/ListField.ts index 1357dc445..700600804 100644 --- a/src/fields/ListField.ts +++ b/src/fields/ListField.ts @@ -1,22 +1,46 @@ -import { Field, FIELD_ID, FieldValue, Opt } from "./Field"; -import { BasicField } from "./BasicField"; -import { Types } from "../server/Message"; -import { observe, action } from "mobx"; +import { action, IArrayChange, IArraySplice, IObservableArray, observe, observable, Lambda } from "mobx"; import { Server } from "../client/Server"; -import { ServerUtils } from "../server/ServerUtil"; +import { UndoManager } from "../client/util/UndoManager"; +import { Types } from "../server/Message"; +import { BasicField } from "./BasicField"; +import { Field, FieldId } from "./Field"; export class ListField<T extends Field> extends BasicField<T[]> { private _proxies: string[] = [] - constructor(data: T[] = [], id: FIELD_ID = undefined, save: boolean = true) { + constructor(data: T[] = [], id?: FieldId, save: boolean = true) { super(data, save, id); this.updateProxies(); if (save) { Server.UpdateField(this); } - observe(this.Data, () => { + this.observeList(); + } + + private observeDisposer: Lambda | undefined; + private observeList(): void { + this.observeDisposer = observe(this.Data as IObservableArray<T>, (change: IArrayChange<T> | IArraySplice<T>) => { this.updateProxies() + if (change.type == "splice") { + UndoManager.AddEvent({ + undo: () => this.Data.splice(change.index, change.addedCount, ...change.removed), + redo: () => this.Data.splice(change.index, change.removedCount, ...change.added) + }) + } else { + UndoManager.AddEvent({ + undo: () => this.Data[change.index] = change.oldValue, + redo: () => this.Data[change.index] = change.newValue + }) + } Server.UpdateField(this); - }) + }); + } + + protected setData(value: T[]) { + if (this.observeDisposer) { + this.observeDisposer() + } + this.data = observable(value); + this.observeList(); } private updateProxies() { diff --git a/src/fields/NumberField.ts b/src/fields/NumberField.ts index 29e285201..47dfc74cb 100644 --- a/src/fields/NumberField.ts +++ b/src/fields/NumberField.ts @@ -1,9 +1,9 @@ import { BasicField } from "./BasicField" import { Types } from "../server/Message"; -import { FIELD_ID } from "./Field"; +import { FieldId } from "./Field"; export class NumberField extends BasicField<number> { - constructor(data: number = 0, id: FIELD_ID = undefined, save: boolean = true) { + constructor(data: number = 0, id?: FieldId, save: boolean = true) { super(data, save, id); } diff --git a/src/fields/RichTextField.ts b/src/fields/RichTextField.ts index 9783107e3..5efb43314 100644 --- a/src/fields/RichTextField.ts +++ b/src/fields/RichTextField.ts @@ -1,9 +1,9 @@ import { BasicField } from "./BasicField"; import { Types } from "../server/Message"; -import { FIELD_ID } from "./Field"; +import { FieldId } from "./Field"; export class RichTextField extends BasicField<string> { - constructor(data: string = "", id: FIELD_ID = undefined, save: boolean = true) { + constructor(data: string = "", id?: FieldId, save: boolean = true) { super(data, save, id); } diff --git a/src/fields/TextField.ts b/src/fields/TextField.ts index efb3c035f..71d8ea310 100644 --- a/src/fields/TextField.ts +++ b/src/fields/TextField.ts @@ -1,9 +1,9 @@ import { BasicField } from "./BasicField" -import { FIELD_ID } from "./Field"; +import { FieldId } from "./Field"; import { Types } from "../server/Message"; export class TextField extends BasicField<string> { - constructor(data: string = "", id: FIELD_ID = undefined, save: boolean = true) { + constructor(data: string = "", id?: FieldId, save: boolean = true) { super(data, save, id); } @@ -22,4 +22,4 @@ export class TextField extends BasicField<string> { _id: this.Id } } -} +}
\ No newline at end of file |