aboutsummaryrefslogtreecommitdiff
path: root/src/fields
diff options
context:
space:
mode:
Diffstat (limited to 'src/fields')
-rw-r--r--src/fields/Document.ts7
-rw-r--r--src/fields/ListField.ts96
-rw-r--r--src/fields/ScriptField.ts64
3 files changed, 147 insertions, 20 deletions
diff --git a/src/fields/Document.ts b/src/fields/Document.ts
index 4584660fb..60eaf5b51 100644
--- a/src/fields/Document.ts
+++ b/src/fields/Document.ts
@@ -16,10 +16,7 @@ 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) {
@@ -406,7 +403,7 @@ export class Document extends Field {
}
else if (field) {
copy.Set(key!, field.Copy());
- }
+ }
});
}
});
diff --git a/src/fields/ListField.ts b/src/fields/ListField.ts
index b6eab5f86..8311e737b 100644
--- a/src/fields/ListField.ts
+++ b/src/fields/ListField.ts
@@ -5,12 +5,18 @@ import { Types } from "../server/Message";
import { BasicField } from "./BasicField";
import { Field, FieldId } from "./Field";
import { FieldMap } from "../client/SocketStub";
+import { ScriptField } from "./ScriptField";
export class ListField<T extends Field> extends BasicField<T[]> {
private _proxies: string[] = [];
- constructor(data: T[] = [], id?: FieldId, save: boolean = true) {
+ private _scriptIds: string[] = [];
+ private scripts: ScriptField[] = [];
+
+ constructor(data: T[] = [], scripts: ScriptField[] = [], id?: FieldId, save: boolean = true) {
super(data, save, id);
+ this.scripts = scripts;
this.updateProxies();
+ this._scriptIds = this.scripts.map(script => script.Id);
if (save) {
Server.UpdateField(this);
}
@@ -25,17 +31,22 @@ export class ListField<T extends Field> extends BasicField<T[]> {
this.observeDisposer();
}
this.observeDisposer = observe(this.Data as IObservableArray<T>, (change: IArrayChange<T> | IArraySplice<T>) => {
+ const target = change.object;
this.updateProxies();
if (change.type === "splice") {
+ this.runScripts(change.removed, false);
UndoManager.AddEvent({
- undo: () => this.Data.splice(change.index, change.addedCount, ...change.removed),
- redo: () => this.Data.splice(change.index, change.removedCount, ...change.added)
+ undo: () => target.splice(change.index, change.addedCount, ...change.removed),
+ redo: () => target.splice(change.index, change.removedCount, ...change.added)
});
+ this.runScripts(change.added, true);
} else {
+ this.runScripts([change.oldValue], false);
UndoManager.AddEvent({
- undo: () => this.Data[change.index] = change.oldValue,
- redo: () => this.Data[change.index] = change.newValue
+ undo: () => target[change.index] = change.oldValue,
+ redo: () => target[change.index] = change.newValue
});
+ this.runScripts([change.newValue], true);
}
if (!this._processingServerUpdate) {
Server.UpdateField(this);
@@ -43,19 +54,60 @@ export class ListField<T extends Field> extends BasicField<T[]> {
});
}
+ private runScripts(fields: T[], added: boolean) {
+ for (const script of this.scripts) {
+ this.runScript(fields, script, added);
+ }
+ }
+
+ private runScript(fields: T[], script: ScriptField, added: boolean) {
+ if (!this._processingServerUpdate) {
+ for (const field of fields) {
+ script.script.run({ field, added });
+ }
+ }
+ }
+
+ addScript(script: ScriptField) {
+ this.scripts.push(script);
+ this._scriptIds.push(script.Id);
+
+ this.runScript(this.Data, script, true);
+ UndoManager.AddEvent({
+ undo: () => this.removeScript(script),
+ redo: () => this.addScript(script),
+ });
+ Server.UpdateField(this);
+ }
+
+ removeScript(script: ScriptField) {
+ const index = this.scripts.indexOf(script);
+ if (index === -1) {
+ return;
+ }
+ this.scripts.splice(index, 1);
+ this._scriptIds.splice(index, 1);
+ UndoManager.AddEvent({
+ undo: () => this.addScript(script),
+ redo: () => this.removeScript(script),
+ });
+ this.runScript(this.Data, script, false);
+ Server.UpdateField(this);
+ }
+
protected setData(value: T[]) {
+ this.runScripts(this.data, false);
+
this.data = observable(value);
this.updateProxies();
this.observeList();
+ this.runScripts(this.data, true);
}
private updateProxies() {
this._proxies = this.Data.map(field => field.Id);
}
- UpdateFromServer(fields: string[]) {
- this._proxies = fields;
- }
private arraysEqual(a: any[], b: any[]) {
if (a === b) return true;
if (a === null || b === null) return false;
@@ -73,7 +125,7 @@ export class ListField<T extends Field> extends BasicField<T[]> {
}
init(callback: (field: Field) => any) {
- Server.GetFields(this._proxies, action((fields: FieldMap) => {
+ const fieldsPromise = Server.GetFields(this._proxies).then(action((fields: FieldMap) => {
if (!this.arraysEqual(this._proxies, this.data.map(field => field.Id))) {
var dataids = this.data.map(d => d.Id);
var proxies = this._proxies.map(p => p);
@@ -102,8 +154,13 @@ export class ListField<T extends Field> extends BasicField<T[]> {
}
this._processingServerUpdate = false;
}
- callback(this);
}));
+
+ const scriptsPromise = Server.GetFields(this._scriptIds).then((fields: FieldMap) => {
+ this.scripts = this._scriptIds.map(id => fields[id] as ScriptField);
+ });
+
+ Promise.all([fieldsPromise, scriptsPromise]).then(() => callback(this));
}
ToScriptString(): string {
@@ -114,17 +171,26 @@ export class ListField<T extends Field> extends BasicField<T[]> {
return new ListField<T>(this.Data);
}
- ToJson(): { type: Types, data: string[], _id: string } {
+
+ UpdateFromServer(data: { fields: string[], scripts: string[] }) {
+ this._proxies = data.fields;
+ this._scriptIds = data.scripts;
+ }
+ ToJson(): { type: Types, data: { fields: string[], scripts: string[] }, _id: string } {
return {
type: Types.List,
- data: this._proxies || [],
+ data: {
+ fields: this._proxies,
+ scripts: this._scriptIds,
+ },
_id: this.Id
};
}
- static FromJson(id: string, ids: string[]): ListField<Field> {
- let list = new ListField([], id, false);
- list._proxies = ids;
+ static FromJson(id: string, data: { fields: string[], scripts: string[] }): ListField<Field> {
+ let list = new ListField([], [], id, false);
+ list._proxies = data.fields;
+ list._scriptIds = data.scripts;
return list;
}
} \ No newline at end of file
diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts
new file mode 100644
index 000000000..24c1d9b3a
--- /dev/null
+++ b/src/fields/ScriptField.ts
@@ -0,0 +1,64 @@
+import { Field, FieldId } from "./Field";
+import { Types } from "../server/Message";
+import { CompileScript, ScriptOptions, CompiledScript } from "../client/util/Scripting";
+import { Server } from "../client/Server";
+
+export interface ScriptData {
+ script: string;
+ options: ScriptOptions;
+}
+
+export class ScriptField extends Field {
+ readonly script: CompiledScript;
+
+ constructor(script: CompiledScript, id?: FieldId, save: boolean = true) {
+ super(id);
+
+ this.script = script;
+
+ if (save) {
+ Server.UpdateField(this);
+ }
+ }
+
+ static FromJson(id: string, data: ScriptData): ScriptField {
+ const script = CompileScript(data.script, data.options);
+ if (!script.compiled) {
+ throw new Error("Can't compile script");
+ }
+ return new ScriptField(script, id, false);
+ }
+
+ ToScriptString() {
+ return "new ScriptField(...)";
+ }
+
+ GetValue() {
+ return this.script;
+ }
+
+ TrySetValue(): boolean {
+ throw new Error("Script fields currently can't be modified");
+ }
+
+ UpdateFromServer() {
+ throw new Error("Script fields currently can't be updated");
+ }
+
+ ToJson(): { _id: string, type: Types, data: ScriptData } {
+ const { options, originalScript } = this.script;
+ return {
+ _id: this.Id,
+ type: Types.Script,
+ data: {
+ script: originalScript,
+ options
+ },
+ };
+ }
+
+ Copy(): Field {
+ //Script fields are currently immutable, so we can fake copy them
+ return this;
+ }
+} \ No newline at end of file