aboutsummaryrefslogtreecommitdiff
path: root/src/fields/Document.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/fields/Document.ts')
-rw-r--r--src/fields/Document.ts201
1 files changed, 131 insertions, 70 deletions
diff --git a/src/fields/Document.ts b/src/fields/Document.ts
index 85ff6ddcb..7cf784f0e 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,19 +9,29 @@ import { Server } from "../client/Server";
import { Types } from "../server/Message";
import { UndoManager } from "../client/util/UndoManager";
import { HtmlField } from "./HtmlField";
+import { BooleanField } from "./BooleanField";
+import { allLimit } from "async";
+import { prototype } from "nodemailer/lib/smtp-pool";
+import { HistogramField } from "../client/northstar/dash-fields/HistogramField";
export class Document extends Field {
//TODO tfs: We should probably store FieldWaiting in fields when we request it from the server so that we don't set up multiple server gets for the same document and field
- 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);
}
}
+ static FromJson(data: any, id: string, save: boolean): Document {
+ let doc = new Document(id, save);
+ let fields = data as [string, string][];
+ fields.forEach(pair => doc._proxies.set(pair[0], pair[1]));
+ return doc;
+ }
UpdateFromServer(data: [string, string][]) {
for (const key in data) {
@@ -30,22 +40,24 @@ 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 = () => this.GetNumber(KeyStore.Width, 0);
+ public Height = () => 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 = () => this.GetNumber(KeyStore.Scale, 1);
@computed
public get Title(): string {
let title = this.Get(KeyStore.Title, true);
- if (title)
- if (title != FieldWaiting && title instanceof TextField)
+ if (title || title === FieldWaiting) {
+ 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";
+ if (parTitle || parTitle === FieldWaiting) {
+ if (parTitle !== FieldWaiting) return parTitle.Data + ".alias";
else return "-waiting-.alias";
+ }
return "-untitled-";
}
@@ -57,7 +69,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
@@ -65,7 +77,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.
@@ -78,10 +90,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 {
@@ -90,17 +102,17 @@ export class Document extends Field {
}
} else {
let doc: FieldValue<Document> = this;
- while (doc && doc != FieldWaiting && field != FieldWaiting) {
+ while (doc && field !== FieldWaiting) {
let curField = doc.fields.get(key.Id);
let curProxy = doc._proxies.get(key.Id);
if (!curField || (curProxy && curField.field.Id !== curProxy)) {
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 {
@@ -108,7 +120,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;
@@ -118,8 +133,7 @@ export class Document extends Field {
break;
}
}
- if (doc == FieldWaiting)
- field = FieldWaiting;
+ if (doc === FieldWaiting) field = FieldWaiting;
}
return field;
@@ -148,24 +162,32 @@ export class Document extends Field {
} else {
callback(undefined);
}
- })
+ });
} else {
callback(undefined);
}
}
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 {
+ 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) => {
+ return this.GetAsync(key, field => {
cb(Cast(field, ctor));
});
- }
+ };
if (callback) {
fn(callback);
} else {
- return new Promise(res => fn(res));
+ return new Promise(fn);
}
}
@@ -175,10 +197,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 {
@@ -201,17 +227,25 @@ 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) {
+ if (getfield !== FieldWaiting) {
return Cast(getfield, ctor);
}
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) {
+ if (field && field !== FieldWaiting) {
return field;
}
const newField = new ctor();
@@ -219,9 +253,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;
}
@@ -229,6 +267,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);
}
@@ -238,7 +280,7 @@ export class Document extends Field {
}
GetList<T extends Field>(key: Key, defaultVal: T[]): T[] {
- return this.GetData<T[], ListField<T>>(key, ListField, defaultVal)
+ return this.GetData<T[], ListField<T>>(key, ListField, defaultVal);
}
@action
@@ -246,16 +288,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);
@@ -264,22 +305,22 @@ export class Document extends Field {
UndoManager.AddEvent({
undo: () => this.Set(key, oldField, setOnPrototype),
redo: () => this.Set(key, field, setOnPrototype)
- })
+ });
}
}
@action
SetOnPrototype(key: Key, field: Field | undefined): void {
this.GetTAsync(KeyStore.Prototype, Document, (f: Opt<Document>) => {
- f && f.Set(key, field)
- })
+ f && f.Set(key, field);
+ });
}
@action
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)
- })
+ f && f.SetData(key, value, ctor, replaceWrongType);
+ });
}
@action
@@ -298,7 +339,10 @@ export class Document extends Field {
SetText(key: Key, value: string, replaceWrongType = true) {
this.SetData(key, value, TextField, replaceWrongType);
}
-
+ @action
+ SetBoolean(key: Key, value: boolean, replaceWrongType = true) {
+ this.SetData(key, value, BooleanField, replaceWrongType);
+ }
@action
SetNumber(key: Key, value: number, replaceWrongType = true) {
this.SetData(key, value, NumberField, replaceWrongType);
@@ -311,7 +355,7 @@ export class Document extends Field {
GetAllPrototypes(): Document[] {
let protos: Document[] = [];
let doc: FieldValue<Document> = this;
- while (doc && doc != FieldWaiting) {
+ while (doc && doc !== FieldWaiting) {
protos.push(doc);
doc = doc.GetPrototype();
}
@@ -319,12 +363,12 @@ export class Document extends Field {
}
CreateAlias(id?: string): Document {
- let alias = new Document(id)
+ let alias = new Document(id);
this.GetTAsync(KeyStore.Prototype, Document, (f: Opt<Document>) => {
- f && alias.Set(KeyStore.Prototype, f)
- })
+ f && alias.Set(KeyStore.Prototype, f);
+ });
- return alias
+ return alias;
}
MakeDelegate(id?: string): Document {
@@ -348,22 +392,39 @@ export class Document extends Field {
return title;
//throw new Error("Method not implemented.");
}
- Copy(): Field {
- throw new Error("Method not implemented.");
- }
-
- 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])
+ Copy(copyProto?: boolean, id?: string): Field {
+ let copy = new Document();
+ this._proxies.forEach((fieldid, keyid) => { // copy each prototype field
+ let key = KeyStore.KeyLookup(keyid);
+ if (key) {
+ this.GetAsync(key, (field: Opt<Field>) => {
+ if (key === KeyStore.Prototype && copyProto) { // handle prototype field specially
+ if (field instanceof Document) {
+ copy.Set(key, field.Copy(false)); // only copying one level of prototypes for now...
+ }
+ }
+ else
+ if (field instanceof Document) { // ... TODO bcz: should we copy documents or reference them
+ copy.Set(key!, field);
+ }
+ else if (field) {
+ copy.Set(key!, field.Copy());
+ }
+ });
}
});
+ return copy;
+ }
+
+ ToJson() {
+ let fields: [string, string][] = [];
+ this._proxies.forEach((field, key) =>
+ field && fields.push([key, field]));
return {
type: Types.Document,
data: fields,
- _id: this.Id
- }
+ id: this.Id
+ };
}
-} \ No newline at end of file
+}