diff options
Diffstat (limited to 'src/new_fields')
| -rw-r--r-- | src/new_fields/CursorField.ts | 6 | ||||
| -rw-r--r-- | src/new_fields/Doc.ts | 93 | ||||
| -rw-r--r-- | src/new_fields/List.ts | 10 | ||||
| -rw-r--r-- | src/new_fields/ObjectField.ts | 2 | ||||
| -rw-r--r-- | src/new_fields/util.ts | 24 |
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); |
