diff options
Diffstat (limited to 'src/fields/Document.ts')
-rw-r--r-- | src/fields/Document.ts | 221 |
1 files changed, 153 insertions, 68 deletions
diff --git a/src/fields/Document.ts b/src/fields/Document.ts index b6439364a..92d03d765 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -1,6 +1,6 @@ -import { Key } from "./Key" +import { Key } from "./Key"; import { KeyStore } from "./KeyStore"; -import { Field, Cast, FieldWaiting, FieldValue, FieldId, Opt } from "./Field" +import { Field, Cast, FieldWaiting, FieldValue, FieldId, Opt } from "./Field"; import { NumberField } from "./NumberField"; import { ObservableMap, computed, action, runInAction } from "mobx"; import { TextField } from "./TextField"; @@ -9,17 +9,21 @@ import { Server } from "../client/Server"; import { Types } from "../server/Message"; import { UndoManager } from "../client/util/UndoManager"; import { HtmlField } from "./HtmlField"; +import { BooleanField } from "./BooleanField"; export class Document extends Field { //TODO tfs: We should probably store FieldWaiting in fields when we request it from the server so that we don't set up multiple server gets for the same document and field - public fields: ObservableMap<string, { key: Key, field: Field }> = new ObservableMap(); + public fields: ObservableMap< + string, + { key: Key; field: Field } + > = new ObservableMap(); public _proxies: ObservableMap<string, FieldId> = new ObservableMap(); constructor(id?: string, save: boolean = true) { - super(id) + super(id); if (save) { - Server.UpdateField(this) + Server.UpdateField(this); } } @@ -30,13 +34,35 @@ export class Document extends Field { } } - public Width = () => { return this.GetNumber(KeyStore.Width, 0) } - public Height = () => { return this.GetNumber(KeyStore.Height, this.GetNumber(KeyStore.NativeWidth, 0) ? this.GetNumber(KeyStore.NativeHeight, 0) / this.GetNumber(KeyStore.NativeWidth, 0) * this.GetNumber(KeyStore.Width, 0) : 0) } - public Scale = () => { return this.GetNumber(KeyStore.Scale, 1) } + public Width = () => { + return this.GetNumber(KeyStore.Width, 0); + }; + public Height = () => { + return this.GetNumber( + KeyStore.Height, + this.GetNumber(KeyStore.NativeWidth, 0) + ? (this.GetNumber(KeyStore.NativeHeight, 0) / + this.GetNumber(KeyStore.NativeWidth, 0)) * + this.GetNumber(KeyStore.Width, 0) + : 0 + ); + }; + public Scale = () => { + return this.GetNumber(KeyStore.Scale, 1); + }; @computed - public get Title() { - return this.GetText(KeyStore.Title, "<untitled>"); + public get Title(): string { + let title = this.Get(KeyStore.Title, true); + if (title) + if (title != FieldWaiting && title instanceof TextField) + return title.Data; + else return "-waiting-"; + let parTitle = this.GetT(KeyStore.Title, TextField); + if (parTitle) + if (parTitle != FieldWaiting) return parTitle.Data + ".alias"; + else return "-waiting-.alias"; + return "-untitled-"; } @computed @@ -47,7 +73,7 @@ export class Document extends Field { /** * Get the field in the document associated with the given key. If the * associated field has not yet been filled in from the server, a request - * to the server will automatically be sent, the value will be filled in + * to the server will automatically be sent, the value will be filled in * when the request is completed, and {@link Field.ts#FieldWaiting} will be returned. * @param key - The key of the value to get * @param ignoreProto - If true, ignore any prototype this document @@ -55,7 +81,7 @@ export class Document extends Field { * If false (default), search up the prototype chain, starting at this document, * for a document that has a field associated with the given key, and return the first * one found. - * + * * @returns If the document does not have a field associated with the given key, returns `undefined`. * If the document does have an associated field, but the field has not been fetched from the server, returns {@link Field.ts#FieldWaiting}. * If the document does have an associated field, and the field has not been fetched from the server, returns the associated field. @@ -68,10 +94,10 @@ export class Document extends Field { } else if (this._proxies.has(key.Id)) { 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 - */ + 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 { @@ -87,10 +113,10 @@ export class Document extends Field { if (curProxy) { 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 - */ + 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 { @@ -98,7 +124,10 @@ export class Document extends Field { } break; } - if ((doc.fields.has(KeyStore.Prototype.Id) || doc._proxies.has(KeyStore.Prototype.Id))) { + if ( + doc.fields.has(KeyStore.Prototype.Id) || + doc._proxies.has(KeyStore.Prototype.Id) + ) { doc = doc.GetPrototype(); } else { break; @@ -108,8 +137,7 @@ export class Document extends Field { break; } } - if (doc == FieldWaiting) - field = FieldWaiting; + if (doc == FieldWaiting) field = FieldWaiting; } return field; @@ -124,22 +152,47 @@ export class Document extends Field { * Note: The callback will not be called if there is no associated field. * @returns `true` if the field exists on the document and `callback` will be called, and `false` otherwise */ - GetAsync(key: Key, callback: (field: Field) => void): boolean { + GetAsync(key: Key, callback: (field: Opt<Field>) => void): void { //TODO: This currently doesn't deal with prototypes let field = this.fields.get(key.Id); if (field && field.field) { callback(field.field); } else if (this._proxies.has(key.Id)) { Server.GetDocumentField(this, key, callback); - return true; + } else if (this._proxies.has(KeyStore.Prototype.Id)) { + this.GetTAsync(KeyStore.Prototype, Document, proto => { + if (proto) { + proto.GetAsync(key, callback); + } else { + callback(undefined); + } + }); + } else { + callback(undefined); } - return false; } - GetTAsync<T extends Field>(key: Key, ctor: { new(): T }, callback: (field: Opt<T>) => void): boolean { - return this.GetAsync(key, (field) => { - callback(Cast(field, ctor)); - }) + GetTAsync<T extends Field>(key: Key, ctor: { new(): T }): Promise<Opt<T>>; + GetTAsync<T extends Field>( + key: Key, + ctor: { new(): T }, + callback: (field: Opt<T>) => void + ): void; + GetTAsync<T extends Field>( + key: Key, + ctor: { new(): T }, + callback?: (field: Opt<T>) => void + ): Promise<Opt<T>> | void { + let fn = (cb: (field: Opt<T>) => void) => { + return this.GetAsync(key, field => { + cb(Cast(field, ctor)); + }); + }; + if (callback) { + fn(callback); + } else { + return new Promise(res => fn(res)); + } } /** @@ -148,10 +201,14 @@ export class Document extends Field { * or the field associated with the given key is not of the given type. * @param ctor - Constructor of the field type to get. E.g., TextField, ImageField, etc. */ - GetOrCreateAsync<T extends Field>(key: Key, ctor: { new(): T }, callback: (field: T) => void): void { + GetOrCreateAsync<T extends Field>( + key: Key, + ctor: { new(): T }, + callback: (field: T) => void + ): void { //This currently doesn't deal with prototypes if (this._proxies.has(key.Id)) { - Server.GetDocumentField(this, key, (field) => { + Server.GetDocumentField(this, key, field => { if (field && field instanceof ctor) { callback(field); } else { @@ -174,7 +231,11 @@ export class Document extends Field { * @returns Same as {@link Document#Get}, except will return `undefined` * if there is an associated field but it is of the wrong type. */ - GetT<T extends Field = Field>(key: Key, ctor: { new(...args: any[]): T }, ignoreProto: boolean = false): FieldValue<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); @@ -182,7 +243,11 @@ export class Document extends Field { return FieldWaiting; } - GetOrCreate<T extends Field>(key: Key, ctor: { new(): T }, ignoreProto: boolean = false): T { + GetOrCreate<T extends Field>( + key: Key, + ctor: { new(): T }, + ignoreProto: boolean = false + ): T { const field = this.GetT(key, ctor, ignoreProto); if (field && field != FieldWaiting) { return field; @@ -192,9 +257,13 @@ export class Document extends Field { return newField; } - GetData<T, U extends Field & { Data: T }>(key: Key, ctor: { new(): U }, defaultVal: T): T { + GetData<T, U extends Field & { Data: T }>( + key: Key, + ctor: { new(): U }, + defaultVal: T + ): T { let val = this.Get(key); - let vval = (val && val instanceof ctor) ? val.Data : defaultVal; + let vval = val && val instanceof ctor ? val.Data : defaultVal; return vval; } @@ -202,6 +271,10 @@ export class Document extends Field { return this.GetData(key, HtmlField, defaultVal); } + GetBoolean(key: Key, defaultVal: boolean): boolean { + return this.GetData(key, BooleanField, defaultVal); + } + GetNumber(key: Key, defaultVal: number): number { return this.GetData(key, NumberField, defaultVal); } @@ -211,14 +284,7 @@ export class Document extends Field { } GetList<T extends Field>(key: Key, defaultVal: T[]): T[] { - return this.GetData<T[], ListField<T>>(key, ListField, defaultVal) - } - - @action - SetOnPrototype(key: Key, field: Field | undefined): void { - this.GetAsync(KeyStore.Prototype, (f: Field) => { - (f as Document).Set(key, field) - }) + return this.GetData<T[], ListField<T>>(key, ListField, defaultVal); } @action @@ -226,16 +292,15 @@ export class Document extends Field { let old = this.fields.get(key.Id); let oldField = old ? old.field : undefined; if (setOnPrototype) { - this.SetOnPrototype(key, field) - } - else { + this.SetOnPrototype(key, field); + } else { if (field) { this.fields.set(key.Id, { key, field }); - this._proxies.set(key.Id, field.Id) + this._proxies.set(key.Id, field.Id); // Server.AddDocumentField(this, key, field); } else { this.fields.delete(key.Id); - this._proxies.delete(key.Id) + this._proxies.delete(key.Id); // Server.DeleteDocumentField(this, key); } Server.UpdateField(this); @@ -244,26 +309,42 @@ export class Document extends Field { UndoManager.AddEvent({ undo: () => this.Set(key, oldField, setOnPrototype), redo: () => this.Set(key, field, setOnPrototype) - }) + }); } } @action - SetDataOnPrototype<T, U extends Field & { Data: T }>(key: Key, value: T, ctor: { new(): U }, replaceWrongType = true) { - this.GetAsync(KeyStore.Prototype, (f: Field) => { - (f as Document).SetData(key, value, ctor) - }) + SetOnPrototype(key: Key, field: Field | undefined): void { + this.GetTAsync(KeyStore.Prototype, Document, (f: Opt<Document>) => { + f && f.Set(key, field); + }); } @action - SetData<T, U extends Field & { Data: T }>(key: Key, value: T, ctor: { new(): U }, replaceWrongType = true) { + SetDataOnPrototype<T, U extends Field & { Data: T }>( + key: Key, + value: T, + ctor: { new(): U }, + replaceWrongType = true + ) { + this.GetTAsync(KeyStore.Prototype, Document, (f: Opt<Document>) => { + f && f.SetData(key, value, ctor); + }); + } + @action + SetData<T, U extends Field & { Data: T }>( + key: Key, + value: T, + ctor: { new(data: T): U }, + replaceWrongType = true + ) { let field = this.Get(key, true); if (field instanceof ctor) { field.Data = value; } else if (!field || replaceWrongType) { - let newField = new ctor(); - newField.Data = value; + let newField = new ctor(value); + // newField.Data = value; this.Set(key, newField); } } @@ -293,12 +374,12 @@ export class Document extends Field { } CreateAlias(id?: string): Document { - let alias = new Document(id) - this.GetAsync(KeyStore.Prototype, (f: Field) => { - alias.Set(KeyStore.Prototype, f) - }) + let alias = new Document(id); + this.GetTAsync(KeyStore.Prototype, Document, (f: Opt<Document>) => { + f && alias.Set(KeyStore.Prototype, f); + }); - return alias + return alias; } MakeDelegate(id?: string): Document { @@ -318,7 +399,11 @@ export class Document extends Field { } GetValue() { return this.Title; - var title = (this._proxies.has(KeyStore.Title.Id) ? "???" : this.Title) + "(" + this.Id + ")"; + var title = + (this._proxies.has(KeyStore.Title.Id) ? "???" : this.Title) + + "(" + + this.Id + + ")"; return title; //throw new Error("Method not implemented."); } @@ -326,11 +411,11 @@ export class Document extends Field { throw new Error("Method not implemented."); } - ToJson(): { type: Types, data: [string, string][], _id: string } { - let fields: [string, string][] = [] + ToJson(): { type: Types; data: [string, string][]; _id: string } { + let fields: [string, string][] = []; this._proxies.forEach((field, key) => { if (field) { - fields.push([key, field as string]) + fields.push([key, field as string]); } }); @@ -338,6 +423,6 @@ export class Document extends Field { type: Types.Document, data: fields, _id: this.Id - } + }; } -}
\ No newline at end of file +} |