diff options
author | bob <bcz@cs.brown.edu> | 2019-06-11 10:53:36 -0400 |
---|---|---|
committer | bob <bcz@cs.brown.edu> | 2019-06-11 10:53:36 -0400 |
commit | 95674ee7f68782d1ce85858120efea956825bcb9 (patch) | |
tree | 0d2ddc9838b45278d6533099f7030a9713d6413f /src/new_fields/Doc.ts | |
parent | 4dacd1220e6a0ef73167f187f52f3b4c222c2586 (diff) | |
parent | 06d5bb5c65da6f4a115ebf8118989115420bccef (diff) |
merged embedded linking with master
Diffstat (limited to 'src/new_fields/Doc.ts')
-rw-r--r-- | src/new_fields/Doc.ts | 135 |
1 files changed, 67 insertions, 68 deletions
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 7b86cd8b1..7e02a5bc5 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -4,31 +4,37 @@ 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") - || (typeof field === "number") - || (typeof field === "boolean") - || (field instanceof ObjectField) - || (field instanceof RefField); +import { ObjectField } from "./ObjectField"; +import { RefField, FieldId } from "./RefField"; +import { ToScriptString, SelfProxy, Parent, OnUpdate, Self, HandleUpdate, Update, Id } from "./FieldSymbols"; + +export namespace Field { + export function toScriptString(field: Field): string { + if (typeof field === "string") { + return `"${field}"`; + } else if (typeof field === "number" || typeof field === "boolean") { + return String(field); + } else { + return field[ToScriptString](); + } + } + export function IsField(field: any): field is Field; + export function IsField(field: any, includeUndefined: true): field is Field | undefined; + export function IsField(field: any, includeUndefined: boolean = false): field is Field | undefined { + return (typeof field === "string") + || (typeof field === "number") + || (typeof field === "boolean") + || (field instanceof ObjectField) + || (field instanceof RefField) + || (includeUndefined && field === undefined); + } } export type Field = number | string | boolean | ObjectField | RefField; export type Opt<T> = T | undefined; export type FieldWaiting<T extends RefField = RefField> = T extends undefined ? never : Promise<T | undefined>; export type FieldResult<T extends Field = Field> = Opt<T> | FieldWaiting<Extract<T, RefField>>; -export const Update = Symbol("Update"); -export const Self = Symbol("Self"); -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. @@ -42,10 +48,13 @@ export function DocListCastAsync(field: FieldResult, defaultValue?: Doc[]) { 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[]; } +export const WidthSym = Symbol("Width"); +export const HeightSym = Symbol("Height"); + @Deserializable("doc").withFields(["id"]) export class Doc extends RefField { constructor(id?: FieldId, forceSave?: boolean) { @@ -53,6 +62,7 @@ export class Doc extends RefField { const doc = new Proxy<this>(this, { set: setter, get: getter, + // getPrototypeOf: (target) => Cast(target[SelfProxy].proto, Doc) || null, // TODO this might be able to replace the proto logic in getter has: (target, key) => key in target.__fields, ownKeys: target => Object.keys(target.__fields), getOwnPropertyDescriptor: (target, prop) => { @@ -60,6 +70,7 @@ export class Doc extends RefField { return { configurable: true,//TODO Should configurable be true? enumerable: true, + value: target.__fields[prop] }; } return Reflect.getOwnPropertyDescriptor(target, prop); @@ -105,6 +116,10 @@ export class Doc extends RefField { public [WidthSym] = () => NumCast(this[SelfProxy].width); // bcz: is this the right way to access width/height? it didn't work with : this.width public [HeightSym] = () => NumCast(this[SelfProxy].height); + [ToScriptString]() { + return "invalid"; + } + public [HandleUpdate](diff: any) { const set = diff.$set; if (set) { @@ -138,8 +153,11 @@ export namespace Doc { 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 function IsPrototype(doc: Doc) { + return GetT(doc, "isPrototype", "boolean", true); + } export async function SetOnPrototype(doc: Doc, key: string, value: Field) { - const proto = Object.getOwnPropertyNames(doc).indexOf("isPrototype") == -1 ? doc.proto : doc; + const proto = Object.getOwnPropertyNames(doc).indexOf("isPrototype") === -1 ? doc.proto : doc; if (proto) { proto[key] = value; @@ -169,27 +187,35 @@ export namespace 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; + let r = (doc === other); + let r2 = (doc.proto === other); + let r3 = (other.proto === doc); + let r4 = (doc.proto === other.proto); + return r || r2 || r3 || r4; } - export function MakeAlias(doc: Doc) { - const alias = new Doc; + // gets the document's prototype or returns the document if it is a prototype + export function GetProto(doc: Doc) { + return Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : doc.proto!; + } - if (!doc.proto) { - alias.proto = doc; - } else { - PromiseValue(Cast(doc.proto, Doc)).then(proto => { - if (proto) { - alias.proto = proto; - } - }); + export function allKeys(doc: Doc): string[] { + const results: Set<string> = new Set; + + let proto: Doc | undefined = doc; + while (proto) { + Object.keys(proto).forEach(key => results.add(key)); + proto = proto.proto; } - return alias; + return Array.from(results); + } + + export function MakeAlias(doc: Doc) { + if (!GetT(doc, "isPrototype", "boolean", true)) { + return Doc.MakeCopy(doc); + } + return new Doc; } export function MakeCopy(doc: Doc, copyProto: boolean = false): Doc { @@ -213,41 +239,14 @@ 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.proto!.linkDescription = ""; - linkDoc.proto!.linkTags = "Default"; - - linkDoc.proto!.linkedTo = target; - linkDoc.proto!.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; } - export const Prototype = Symbol("Prototype"); }
\ No newline at end of file |