aboutsummaryrefslogtreecommitdiff
path: root/src/new_fields
diff options
context:
space:
mode:
Diffstat (limited to 'src/new_fields')
-rw-r--r--src/new_fields/CursorField.ts6
-rw-r--r--src/new_fields/Doc.ts93
-rw-r--r--src/new_fields/List.ts10
-rw-r--r--src/new_fields/ObjectField.ts2
-rw-r--r--src/new_fields/util.ts24
5 files changed, 75 insertions, 60 deletions
diff --git a/src/new_fields/CursorField.ts b/src/new_fields/CursorField.ts
index 7fd326a5f..fc144222c 100644
--- a/src/new_fields/CursorField.ts
+++ b/src/new_fields/CursorField.ts
@@ -6,17 +6,17 @@ import { serializable, createSimpleSchema, object } from "serializr";
export type CursorPosition = {
x: number,
y: number
-}
+};
export type CursorMetadata = {
id: string,
identifier: string
-}
+};
export type CursorData = {
metadata: CursorMetadata,
position: CursorPosition
-}
+};
const PositionSchema = createSimpleSchema({
x: true,
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 46ccb3e90..02dd34cb4 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -4,12 +4,9 @@ import { autoObject, SerializationHelper, Deserializable } from "../client/util/
import { DocServer } from "../client/DocServer";
import { setter, getter, getField, updateFunction, deleteProperty } from "./util";
import { Cast, ToConstructor, PromiseValue, FieldValue, NumCast } from "./Types";
-import { UndoManager, undoBatch } from "../client/util/UndoManager";
import { listSpec } from "./Schema";
-import { List } from "./List";
import { ObjectField, Parent, OnUpdate } from "./ObjectField";
import { RefField, FieldId, Id, HandleUpdate } from "./RefField";
-import { Docs } from "../client/documents/Documents";
export function IsField(field: any): field is Field {
return (typeof field === "string")
@@ -29,15 +26,21 @@ export const SelfProxy = Symbol("SelfProxy");
export const WidthSym = Symbol("Width");
export const HeightSym = Symbol("Height");
+/**
+ * Cast any field to either a List of Docs or undefined if the given field isn't a List of Docs.
+ * If a default value is given, that will be returned instead of undefined.
+ * If a default value is given, the returned value should not be modified as it might be a temporary value.
+ * If no default value is given, and the returned value is not undefined, it can be safely modified.
+ */
export function DocListCastAsync(field: FieldResult): Promise<Doc[] | undefined>;
export function DocListCastAsync(field: FieldResult, defaultValue: Doc[]): Promise<Doc[]>;
export function DocListCastAsync(field: FieldResult, defaultValue?: Doc[]) {
const list = Cast(field, listSpec(Doc));
- return list ? Promise.all(list) : Promise.resolve(defaultValue);
+ return list ? Promise.all(list).then(() => list) : Promise.resolve(defaultValue);
}
-export function DocListCast(field: FieldResult) {
- return Cast(field, listSpec(Doc), []).filter(d => d && d instanceof Doc).map(d => d as Doc)
+export function DocListCast(field: FieldResult): Doc[] {
+ return Cast(field, listSpec(Doc), []).filter(d => d instanceof Doc) as Doc[];
}
@Deserializable("doc").withFields(["id"])
@@ -130,11 +133,12 @@ export namespace Doc {
const self = doc[Self];
return getField(self, key, ignoreProto);
}
- export function GetT<T extends Field>(doc: Doc, key: string, ctor: ToConstructor<T>, ignoreProto: boolean = false): T | null | undefined {
- return Cast(Get(doc, key, ignoreProto), ctor) as T | null | undefined;
+ export function GetT<T extends Field>(doc: Doc, key: string, ctor: ToConstructor<T>, ignoreProto: boolean = false): FieldResult<T> {
+ return Cast(Get(doc, key, ignoreProto), ctor) as FieldResult<T>;
}
export async function SetOnPrototype(doc: Doc, key: string, value: Field) {
- const proto = doc.proto;
+ const proto = Object.getOwnPropertyNames(doc).indexOf("isPrototype") === -1 ? doc.proto : doc;
+
if (proto) {
proto[key] = value;
}
@@ -152,22 +156,43 @@ export namespace Doc {
for (const key in fields) {
if (fields.hasOwnProperty(key)) {
const value = fields[key];
- if (value !== undefined) {
- doc[key] = value;
- }
+ // Do we want to filter out undefineds?
+ // if (value !== undefined) {
+ doc[key] = value;
+ // }
}
}
return doc;
}
+ // compare whether documents or their protos match
+ export function AreProtosEqual(doc: Doc, other: Doc) {
+ let r = (doc[Id] === other[Id]);
+ let r2 = (doc.proto && doc.proto.Id === other[Id]);
+ let r3 = (other.proto && other.proto.Id === doc[Id]);
+ let r4 = (doc.proto && other.proto && doc.proto[Id] === other.proto[Id]);
+ return r || r2 || r3 || r4 ? true : false;
+ }
+
+ // gets the document's prototype or returns the document if it is a prototype
+ export function GetProto(doc: Doc) {
+ return Object.getOwnPropertyNames(doc).indexOf("isPrototype") === -1 ? doc.proto! : doc;
+ }
+
+
export function MakeAlias(doc: Doc) {
+ const proto = Object.getOwnPropertyNames(doc).indexOf("isPrototype") === -1 ? doc.proto : undefined;
const alias = new Doc;
- PromiseValue(Cast(doc.proto, Doc)).then(proto => {
- if (proto) {
- alias.proto = proto;
- }
- });
+ if (!proto) {
+ alias.proto = doc;
+ } else {
+ PromiseValue(Cast(doc.proto, Doc)).then(proto => {
+ if (proto) {
+ alias.proto = proto;
+ }
+ });
+ }
return alias;
}
@@ -193,39 +218,13 @@ export namespace Doc {
return copy;
}
- export function MakeLink(source: Doc, target: Doc) {
- UndoManager.RunInBatch(() => {
- let linkDoc = Docs.TextDocument({ width: 100, height: 30, borderRounding: -1 });
- //let linkDoc = new Doc;
- linkDoc.proto!.title = "-link name-";
- linkDoc.linkDescription = "";
- linkDoc.linkTags = "Default";
-
- linkDoc.linkedTo = target;
- linkDoc.linkedFrom = source;
-
- let linkedFrom = Cast(target.linkedFromDocs, listSpec(Doc));
- if (!linkedFrom) {
- target.linkedFromDocs = linkedFrom = new List<Doc>();
- }
- linkedFrom.push(linkDoc);
-
- let linkedTo = Cast(source.linkedToDocs, listSpec(Doc));
- if (!linkedTo) {
- source.linkedToDocs = linkedTo = new List<Doc>();
- }
- linkedTo.push(linkDoc);
- return linkDoc;
- }, "make link");
- }
-
- export function MakeDelegate(doc: Doc): Doc;
- export function MakeDelegate(doc: Opt<Doc>): Opt<Doc>;
- export function MakeDelegate(doc: Opt<Doc>): Opt<Doc> {
+ export function MakeDelegate(doc: Doc, id?: string): Doc;
+ export function MakeDelegate(doc: Opt<Doc>, id?: string): Opt<Doc>;
+ export function MakeDelegate(doc: Opt<Doc>, id?: string): Opt<Doc> {
if (!doc) {
return undefined;
}
- const delegate = new Doc();
+ const delegate = new Doc(id, true);
delegate.proto = doc;
return delegate;
}
diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts
index 88a65eba4..70e36f911 100644
--- a/src/new_fields/List.ts
+++ b/src/new_fields/List.ts
@@ -230,6 +230,16 @@ class ListImpl<T extends Field> extends ObjectField {
const list = new Proxy<this>(this, {
set: setter,
get: listGetter,
+ ownKeys: target => Object.keys(target.__fields),
+ getOwnPropertyDescriptor: (target, prop) => {
+ if (prop in target.__fields) {
+ return {
+ configurable: true,//TODO Should configurable be true?
+ enumerable: true,
+ };
+ }
+ return Reflect.getOwnPropertyDescriptor(target, prop);
+ },
deleteProperty: deleteProperty,
defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); },
});
diff --git a/src/new_fields/ObjectField.ts b/src/new_fields/ObjectField.ts
index f276bfa67..51768c6db 100644
--- a/src/new_fields/ObjectField.ts
+++ b/src/new_fields/ObjectField.ts
@@ -6,7 +6,7 @@ export const Parent = Symbol("Parent");
export const Copy = Symbol("Copy");
export abstract class ObjectField {
- protected [OnUpdate](diff?: any) { };
+ protected [OnUpdate](diff?: any) { }
private [Parent]?: RefField | ObjectField;
abstract [Copy](): ObjectField;
}
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index a5f5e368b..d94994a07 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -55,6 +55,17 @@ export function getter(target: any, prop: string | symbol | number, receiver: an
}
return getField(target, prop);
}
+function getProtoField(protoField: Doc | undefined, prop: string | number, cb?: (field: Field | undefined) => void) {
+ if (!protoField) return undefined;
+ let field = protoField[prop];
+ if (field instanceof Promise) {
+ cb && field.then(cb);
+ return field;
+ } else {
+ cb && cb(field);
+ return field;
+ }
+}
//TODO The callback parameter is never being passed in currently, so we should be able to get rid of it.
export function getField(target: any, prop: string | number, ignoreProto: boolean = false, callback?: (field: Field | undefined) => void): any {
@@ -62,17 +73,12 @@ export function getField(target: any, prop: string | number, ignoreProto: boolea
if (field instanceof ProxyField) {
return field.value(callback);
}
- if (field === undefined && !ignoreProto) {
+ if (field === undefined && !ignoreProto && prop !== "proto") {
const proto = getField(target, "proto", true);
if (proto instanceof Doc) {
- let field = proto[prop];
- if (field instanceof Promise) {
- callback && field.then(callback);
- return undefined;
- } else {
- callback && callback(field);
- return field;
- }
+ return getProtoField(proto, prop, callback);
+ } else if (proto instanceof Promise) {
+ return proto.then(async proto => getProtoField(proto, prop, callback));
}
}
callback && callback(field);