diff options
Diffstat (limited to 'src/fields')
-rw-r--r-- | src/fields/AudioField.ts | 31 | ||||
-rw-r--r-- | src/fields/Document.ts | 119 | ||||
-rw-r--r-- | src/fields/HtmlField.ts | 2 | ||||
-rw-r--r-- | src/fields/ImageField.ts | 4 | ||||
-rw-r--r-- | src/fields/KVPField | 0 | ||||
-rw-r--r-- | src/fields/KVPField.ts | 30 | ||||
-rw-r--r-- | src/fields/KeyStore.ts | 16 | ||||
-rw-r--r-- | src/fields/ListField.ts | 55 | ||||
-rw-r--r-- | src/fields/PDFField.ts | 4 | ||||
-rw-r--r-- | src/fields/TupleField.ts | 59 | ||||
-rw-r--r-- | src/fields/VideoField.ts | 30 | ||||
-rw-r--r-- | src/fields/WebField.ts | 4 |
12 files changed, 265 insertions, 89 deletions
diff --git a/src/fields/AudioField.ts b/src/fields/AudioField.ts new file mode 100644 index 000000000..8864471ae --- /dev/null +++ b/src/fields/AudioField.ts @@ -0,0 +1,31 @@ +import { BasicField } from "./BasicField"; +import { Field, FieldId } from "./Field"; +import { Types } from "../server/Message"; + +export class AudioField extends BasicField<URL> { + constructor(data: URL | undefined = undefined, id?: FieldId, save: boolean = true) { + super(data == undefined ? new URL("http://techslides.com/demos/samples/sample.mp3") : data, save, id); + } + + toString(): string { + return this.Data.href; + } + + + ToScriptString(): string { + return `new AudioField("${this.Data}")`; + } + + Copy(): Field { + return new AudioField(this.Data); + } + + ToJson(): { type: Types, data: string, _id: string } { + return { + type: Types.Audio, + data: this.Data.href, + _id: this.Id + } + } + +}
\ No newline at end of file diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 2e873439c..85ff6ddcb 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -1,8 +1,8 @@ import { Key } from "./Key" import { KeyStore } from "./KeyStore"; -import { Field, Cast, FieldWaiting, FieldValue, FieldId } from "./Field" +import { Field, Cast, FieldWaiting, FieldValue, FieldId, Opt } from "./Field" import { NumberField } from "./NumberField"; -import { ObservableMap, computed, action } from "mobx"; +import { ObservableMap, computed, action, runInAction } from "mobx"; import { TextField } from "./TextField"; import { ListField } from "./ListField"; import { Server } from "../client/Server"; @@ -11,6 +11,7 @@ import { UndoManager } from "../client/util/UndoManager"; import { HtmlField } from "./HtmlField"; 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 _proxies: ObservableMap<string, FieldId> = new ObservableMap(); @@ -34,8 +35,23 @@ export class Document extends Field { 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 + public get Fields() { + return this.fields; } /** @@ -118,14 +134,39 @@ 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 { - //TODO: This should probably check if this.fields contains the key before calling Server.GetDocumentField - //This currently doesn't deal with prototypes - if (this._proxies.has(key.Id)) { + 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); + } + } + + 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)); } - return false; } /** @@ -201,36 +242,54 @@ export class Document extends Field { } @action - Set(key: Key, field: Field | undefined): void { + Set(key: Key, field: Field | undefined, setOnPrototype = false): void { 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) - // Server.AddDocumentField(this, key, field); - } else { - this.fields.delete(key.Id); - this._proxies.delete(key.Id) - // Server.DeleteDocumentField(this, key); + if (setOnPrototype) { + this.SetOnPrototype(key, field) + } + else { + if (field) { + this.fields.set(key.Id, { key, field }); + this._proxies.set(key.Id, field.Id) + // Server.AddDocumentField(this, key, field); + } else { + this.fields.delete(key.Id); + this._proxies.delete(key.Id) + // Server.DeleteDocumentField(this, key); + } + Server.UpdateField(this); } if (oldField || field) { UndoManager.AddEvent({ - undo: () => this.Set(key, oldField), - redo: () => this.Set(key, field) + undo: () => this.Set(key, oldField, setOnPrototype), + redo: () => this.Set(key, field, setOnPrototype) }) } - Server.UpdateField(this); } @action - SetData<T, U extends Field & { Data: T }>(key: Key, value: T, ctor: { new(): U }, replaceWrongType = true) { + SetOnPrototype(key: Key, field: Field | undefined): void { + this.GetTAsync(KeyStore.Prototype, Document, (f: Opt<Document>) => { + 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) + }) + } + @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); } } @@ -259,6 +318,15 @@ export class Document extends Field { return protos; } + CreateAlias(id?: string): Document { + let alias = new Document(id) + this.GetTAsync(KeyStore.Prototype, Document, (f: Opt<Document>) => { + f && alias.Set(KeyStore.Prototype, f) + }) + + return alias + } + MakeDelegate(id?: string): Document { let delegate = new Document(id); @@ -275,6 +343,7 @@ export class Document extends Field { throw new Error("Method not implemented."); } GetValue() { + return this.Title; var title = (this._proxies.has(KeyStore.Title.Id) ? "???" : this.Title) + "(" + this.Id + ")"; return title; //throw new Error("Method not implemented."); diff --git a/src/fields/HtmlField.ts b/src/fields/HtmlField.ts index a07326095..7cbdf7e58 100644 --- a/src/fields/HtmlField.ts +++ b/src/fields/HtmlField.ts @@ -15,7 +15,7 @@ export class HtmlField extends BasicField<string> { return new HtmlField(this.Data); } - ToJson(): { _id: string; type: Types; data: any; } { + ToJson(): { _id: string; type: Types; data: string; } { return { type: Types.Html, data: this.Data, diff --git a/src/fields/ImageField.ts b/src/fields/ImageField.ts index be8d73e68..a9ece7d7b 100644 --- a/src/fields/ImageField.ts +++ b/src/fields/ImageField.ts @@ -19,10 +19,10 @@ export class ImageField extends BasicField<URL> { return new ImageField(this.Data); } - ToJson(): { type: Types, data: URL, _id: string } { + ToJson(): { type: Types, data: string, _id: string } { return { type: Types.Image, - data: this.Data, + data: this.Data.href, _id: this.Id } } diff --git a/src/fields/KVPField b/src/fields/KVPField deleted file mode 100644 index e69de29bb..000000000 --- a/src/fields/KVPField +++ /dev/null diff --git a/src/fields/KVPField.ts b/src/fields/KVPField.ts deleted file mode 100644 index a7ecc0768..000000000 --- a/src/fields/KVPField.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { BasicField } from "./BasicField" -import { FieldId } from "./Field"; -import { Types } from "../server/Message"; -import { Document } from "./Document" - -export class KVPField extends BasicField<Document> { - constructor(data: Document | undefined = undefined, id?: FieldId, save: boolean = true) { - super(data == undefined ? new Document() : data, save, id); - } - - toString(): string { - return this.Data.Title; - } - - ToScriptString(): string { - return `new KVPField("${this.Data}")`; - } - - Copy() { - return new KVPField(this.Data); - } - - ToJson(): { type: Types, data: Document, _id: string } { - return { - type: Types.Text, - data: this.Data, - _id: this.Id - } - } -}
\ No newline at end of file diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index f67257093..1f039e592 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -19,16 +19,30 @@ export namespace KeyStore { export const Annotations = new Key("Annotations"); export const ViewType = new Key("ViewType"); export const Layout = new Key("Layout"); + export const BackgroundColor = new Key("BackgroundColor"); 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 const SchemaSplitPercentage = new Key("SchemaSplitPercentage"); export const Caption = new Key("Caption"); - export const ActiveFrame = new Key("ActiveFrame"); + export const ActiveWorkspace = new Key("ActiveWorkspace"); export const DocumentText = new Key("DocumentText"); + export const BrushingDocs = new Key("BrushingDocs"); + export const LinkedToDocs = new Key("LinkedToDocs"); + export const LinkedFromDocs = new Key("LinkedFromDocs"); + export const LinkDescription = new Key("LinkDescription"); + export const LinkTags = new Key("LinkTag"); export const Thumbnail = new Key("Thumbnail"); + export const ThumbnailPage = new Key("ThumbnailPage"); export const CurPage = new Key("CurPage"); + export const AnnotationOn = new Key("AnnotationOn"); export const NumPages = new Key("NumPages"); export const Ink = new Key("Ink"); + export const Cursors = new Key("Cursors"); + export const OptionalRightCollection = new Key("OptionalRightCollection"); + export const Archives = new Key("Archives"); + export const Updated = new Key("Updated"); + export const Workspaces = new Key("Workspaces"); } diff --git a/src/fields/ListField.ts b/src/fields/ListField.ts index ce32da0a6..c4008bd12 100644 --- a/src/fields/ListField.ts +++ b/src/fields/ListField.ts @@ -4,6 +4,7 @@ import { UndoManager } from "../client/util/UndoManager"; import { Types } from "../server/Message"; import { BasicField } from "./BasicField"; import { Field, FieldId } from "./Field"; +import { FieldMap } from "../client/SocketStub"; export class ListField<T extends Field> extends BasicField<T[]> { private _proxies: string[] = [] @@ -16,8 +17,13 @@ export class ListField<T extends Field> extends BasicField<T[]> { this.observeList(); } + private _processingServerUpdate: boolean = false; + private observeDisposer: Lambda | undefined; private observeList(): void { + if (this.observeDisposer) { + this.observeDisposer() + } this.observeDisposer = observe(this.Data as IObservableArray<T>, (change: IArrayChange<T> | IArraySplice<T>) => { this.updateProxies() if (change.type == "splice") { @@ -31,14 +37,12 @@ export class ListField<T extends Field> extends BasicField<T[]> { redo: () => this.Data[change.index] = change.newValue }) } - Server.UpdateField(this); + if (!this._processingServerUpdate) + Server.UpdateField(this); }); } protected setData(value: T[]) { - if (this.observeDisposer) { - this.observeDisposer() - } this.data = observable(value); this.updateProxies(); this.observeList(); @@ -68,31 +72,30 @@ export class ListField<T extends Field> extends BasicField<T[]> { } init(callback: (field: Field) => any) { - Server.GetFields(this._proxies, action((fields: { [index: string]: Field }) => { - if (!this.arraysEqual(this._proxies, this.Data.map(field => field.Id))) { + Server.GetFields(this._proxies, action((fields: FieldMap) => { + if (!this.arraysEqual(this._proxies, this.data.map(field => field.Id))) { var dataids = this.data.map(d => d.Id); - var added = this.data.length == this._proxies.length - 1; + var proxies = this._proxies.map(p => p); + var added = this.data.length < this._proxies.length; var deleted = this.data.length > this._proxies.length; for (let i = 0; i < dataids.length && added; i++) - added = this._proxies.indexOf(dataids[i]) != -1; + added = proxies.indexOf(dataids[i]) != -1; for (let i = 0; i < this._proxies.length && deleted; i++) - deleted = dataids.indexOf(this._proxies[i]) != -1; - if (added) { // if only 1 items was added - for (let i = 0; i < this._proxies.length; i++) - if (dataids.indexOf(this._proxies[i]) === -1) - this.Data.splice(i, 0, fields[this._proxies[i]] as T); - } else if (deleted) { // if only items were deleted - for (let i = this.data.length - 1; i >= 0; i--) { - if (this._proxies.indexOf(this.data[i].Id) === -1) { - this.Data.splice(i, 1); - } - } - } else // otherwise, just rebuild the whole list - this.data = this._proxies.map(id => fields[id] as T) - observe(this.Data, () => { - this.updateProxies() - Server.UpdateField(this); - }) + deleted = dataids.indexOf(proxies[i]) != -1; + + this._processingServerUpdate = true; + for (let i = 0; i < proxies.length && added; i++) { + if (dataids.indexOf(proxies[i]) === -1) + this.Data.splice(i, 0, fields[proxies[i]] as T); + } + for (let i = dataids.length - 1; i >= 0 && deleted; i--) { + if (proxies.indexOf(dataids[i]) === -1) + this.Data.splice(i, 1); + } + if (!added && !deleted) {// otherwise, just rebuild the whole list + this.setData(proxies.map(id => fields[id] as T)); + } + this._processingServerUpdate = false; } callback(this); })) @@ -109,7 +112,7 @@ export class ListField<T extends Field> extends BasicField<T[]> { ToJson(): { type: Types, data: string[], _id: string } { return { type: Types.List, - data: this._proxies, + data: this._proxies || [], _id: this.Id } } diff --git a/src/fields/PDFField.ts b/src/fields/PDFField.ts index f3a009001..b6625387e 100644 --- a/src/fields/PDFField.ts +++ b/src/fields/PDFField.ts @@ -22,10 +22,10 @@ export class PDFField extends BasicField<URL> { return `new PDFField("${this.Data}")`; } - ToJson(): { type: Types, data: URL, _id: string } { + ToJson(): { type: Types, data: string, _id: string } { return { type: Types.PDF, - data: this.Data, + data: this.Data.href, _id: this.Id } } diff --git a/src/fields/TupleField.ts b/src/fields/TupleField.ts new file mode 100644 index 000000000..e2162c751 --- /dev/null +++ b/src/fields/TupleField.ts @@ -0,0 +1,59 @@ +import { action, IArrayChange, IArraySplice, IObservableArray, observe, observable, Lambda } from "mobx"; +import { Server } from "../client/Server"; +import { UndoManager } from "../client/util/UndoManager"; +import { Types } from "../server/Message"; +import { BasicField } from "./BasicField"; +import { Field, FieldId } from "./Field"; + +export class TupleField<T, U> extends BasicField<[T, U]> { + constructor(data: [T, U], id?: FieldId, save: boolean = true) { + super(data, save, id); + if (save) { + Server.UpdateField(this); + } + this.observeTuple(); + } + + private observeDisposer: Lambda | undefined; + private observeTuple(): void { + this.observeDisposer = observe(this.Data as (T | U)[] as IObservableArray<T | U>, (change: IArrayChange<T | U> | IArraySplice<T | U>) => { + if (change.type === "update") { + UndoManager.AddEvent({ + undo: () => this.Data[change.index] = change.oldValue, + redo: () => this.Data[change.index] = change.newValue + }) + Server.UpdateField(this); + } else { + throw new Error("Why are you messing with the length of a tuple, huh?"); + } + }); + } + + protected setData(value: [T, U]) { + if (this.observeDisposer) { + this.observeDisposer() + } + this.data = observable(value) as (T | U)[] as [T, U]; + this.observeTuple(); + } + + UpdateFromServer(values: [T, U]) { + this.setData(values); + } + + ToScriptString(): string { + return `new TupleField([${this.Data[0], this.Data[1]}])`; + } + + Copy(): Field { + return new TupleField<T, U>(this.Data); + } + + ToJson(): { type: Types, data: [T, U], _id: string } { + return { + type: Types.Tuple, + data: this.Data, + _id: this.Id + } + } +}
\ No newline at end of file diff --git a/src/fields/VideoField.ts b/src/fields/VideoField.ts new file mode 100644 index 000000000..626e4ec83 --- /dev/null +++ b/src/fields/VideoField.ts @@ -0,0 +1,30 @@ +import { BasicField } from "./BasicField"; +import { Field, FieldId } from "./Field"; +import { Types } from "../server/Message"; + +export class VideoField extends BasicField<URL> { + constructor(data: URL | undefined = undefined, id?: FieldId, save: boolean = true) { + super(data == undefined ? new URL("http://techslides.com/demos/sample-videos/small.mp4") : data, save, id); + } + + toString(): string { + return this.Data.href; + } + + ToScriptString(): string { + return `new VideoField("${this.Data}")`; + } + + Copy(): Field { + return new VideoField(this.Data); + } + + ToJson(): { type: Types, data: string, _id: string } { + return { + type: Types.Video, + data: this.Data.href, + _id: this.Id + } + } + +}
\ No newline at end of file diff --git a/src/fields/WebField.ts b/src/fields/WebField.ts index 8f945d686..6c4de5000 100644 --- a/src/fields/WebField.ts +++ b/src/fields/WebField.ts @@ -19,10 +19,10 @@ export class WebField extends BasicField<URL> { return new WebField(this.Data); } - ToJson(): { type: Types, data: URL, _id: string } { + ToJson(): { type: Types, data: string, _id: string } { return { type: Types.Web, - data: this.Data, + data: this.Data.href, _id: this.Id } } |