diff options
| author | Mohammad Amoush <mohammad_amoush@brown.edu> | 2019-07-22 13:57:10 -0400 |
|---|---|---|
| committer | Mohammad Amoush <mohammad_amoush@brown.edu> | 2019-07-22 13:57:10 -0400 |
| commit | 658ded478c273654174cd2706f8b3e021b8ceb95 (patch) | |
| tree | 7526f7850dd3702b9746125d2f4349a0d6aea8ee /src/new_fields | |
| parent | 157060f7e6029c76765aa20d8fdbe325401a3880 (diff) | |
| parent | 8db50c6ba0be83b85c896043da53e40c17523e90 (diff) | |
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into youtube-api-muhammed
Diffstat (limited to 'src/new_fields')
| -rw-r--r-- | src/new_fields/Doc.ts | 42 | ||||
| -rw-r--r-- | src/new_fields/InkField.ts | 4 | ||||
| -rw-r--r-- | src/new_fields/Schema.ts | 2 | ||||
| -rw-r--r-- | src/new_fields/ScriptField.ts | 30 | ||||
| -rw-r--r-- | src/new_fields/util.ts | 28 |
5 files changed, 84 insertions, 22 deletions
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 0d9fa540f..2ad6ae5f0 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -10,14 +10,16 @@ import { RefField, FieldId } from "./RefField"; import { ToScriptString, SelfProxy, Parent, OnUpdate, Self, HandleUpdate, Update, Id } from "./FieldSymbols"; import { scriptingGlobal } from "../client/util/Scripting"; import { List } from "./List"; +import { DocumentType } from "../client/documents/Documents"; +import { ComputedField } from "./ScriptField"; export namespace Field { export function toKeyValueString(doc: Doc, key: string): string { const onDelegate = Object.keys(doc).includes(key); - let field = FieldValue(doc[key]); + let field = ComputedField.WithoutComputed(() => FieldValue(doc[key])); if (Field.IsField(field)) { - return (onDelegate ? "=" : "") + Field.toScriptString(field); + return (onDelegate ? "=" : "") + (field instanceof ComputedField ? `:=${field.script.originalScript}` : Field.toScriptString(field)); } return ""; } @@ -316,7 +318,7 @@ export namespace Doc { if (extensionDoc === undefined) { setTimeout(() => { let docExtensionForField = new Doc(doc[Id] + fieldKey, true); - docExtensionForField.title = "Extension of " + doc.title + "'s field:" + fieldKey; + docExtensionForField.title = doc.title + ":" + fieldKey + ".ext"; docExtensionForField.extendsDoc = doc; let proto: Doc | undefined = doc; while (proto && !Doc.IsPrototype(proto)) { @@ -344,20 +346,23 @@ export namespace Doc { // ... which means we change the layout to be an expanded view of the template layout. // This allows the view override the template's properties and be referenceable as its own document. - let expandedTemplateLayout = templateLayoutDoc["_expanded_" + dataDoc[Id]]; + let expandedTemplateLayout = dataDoc[templateLayoutDoc[Id]]; if (expandedTemplateLayout instanceof Doc) { return expandedTemplateLayout; } if (expandedTemplateLayout === undefined && BoolCast(templateLayoutDoc.isTemplate)) { setTimeout(() => { - templateLayoutDoc["_expanded_" + dataDoc[Id]] = Doc.MakeDelegate(templateLayoutDoc); - (templateLayoutDoc["_expanded_" + dataDoc[Id]] as Doc).title = templateLayoutDoc.title + " applied to " + dataDoc.title; - (templateLayoutDoc["_expanded_" + dataDoc[Id]] as Doc).isExpandedTemplate = templateLayoutDoc; + let expandedDoc = Doc.MakeDelegate(templateLayoutDoc); + expandedDoc.title = templateLayoutDoc.title + "[" + StrCast(dataDoc.title).match(/\.\.\.[0-9]*/) + "]"; + expandedDoc.isExpandedTemplate = templateLayoutDoc; + dataDoc[templateLayoutDoc[Id]] = expandedDoc; }, 0); } - return templateLayoutDoc; + return templateLayoutDoc; // use the templateLayout when it's not a template or the expandedTemplate is pending. } + let _pendingExpansions: Map<string, boolean> = new Map(); + export function MakeCopy(doc: Doc, copyProto: boolean = false): Doc { const copy = new Doc; Object.keys(doc).forEach(key => { @@ -371,6 +376,8 @@ export namespace Doc { copy[key] = field; } else if (field instanceof ObjectField) { copy[key] = ObjectField.MakeCopy(field); + } else if (field instanceof Promise) { + field.then(f => (copy[key] === undefined) && (copy[key] = f)); //TODO what should we do here? } else { copy[key] = field; } @@ -383,12 +390,12 @@ export namespace 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; + if (doc) { + const delegate = new Doc(id, true); + delegate.proto = doc; + return delegate; } - const delegate = new Doc(id, true); - delegate.proto = doc; - return delegate; + return undefined; } export function MakeTemplate(fieldTemplate: Doc, metaKey: string, proto: Doc) { @@ -416,6 +423,13 @@ export namespace Doc { fieldTemplate.nativeHeight = nh; fieldTemplate.isTemplate = true; fieldTemplate.showTitle = "title"; - fieldTemplate.proto = proto; + setTimeout(() => fieldTemplate.proto = proto); + } + + export async function ToggleDetailLayout(d: Doc) { + let miniLayout = await PromiseValue(d.miniLayout); + let detailLayout = await PromiseValue(d.detailedLayout); + d.layout !== miniLayout ? miniLayout && (d.layout = d.miniLayout) : detailLayout && (d.layout = detailLayout); + if (d.layout === detailLayout) Doc.GetProto(d).nativeWidth = Doc.GetProto(d).nativeHeight = undefined; } }
\ No newline at end of file diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index 4e3b7abe0..39c6c8ce3 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -2,7 +2,7 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, custom, createSimpleSchema, list, object, map } from "serializr"; import { ObjectField } from "./ObjectField"; import { Copy, ToScriptString } from "./FieldSymbols"; -import { deepCopy } from "../Utils"; +import { DeepCopy } from "../Utils"; export enum InkTool { None, @@ -39,7 +39,7 @@ export class InkField extends ObjectField { } [Copy]() { - return new InkField(deepCopy(this.inkData)); + return new InkField(DeepCopy(this.inkData)); } [ToScriptString]() { diff --git a/src/new_fields/Schema.ts b/src/new_fields/Schema.ts index 2355304d5..b1a449e08 100644 --- a/src/new_fields/Schema.ts +++ b/src/new_fields/Schema.ts @@ -104,7 +104,7 @@ export function makeStrictInterface<T extends Interface>(schema: T): (doc: Doc) } export function createSchema<T extends Interface>(schema: T): T & { proto: ToConstructor<Doc> } { - schema.proto = Doc; + (schema as any).proto = Doc; return schema as any; } diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts index e2994ed70..e8a1ea28a 100644 --- a/src/new_fields/ScriptField.ts +++ b/src/new_fields/ScriptField.ts @@ -4,6 +4,8 @@ import { Copy, ToScriptString, Parent, SelfProxy } from "./FieldSymbols"; import { serializable, createSimpleSchema, map, primitive, object, deserialize, PropSchema, custom, SKIP } from "serializr"; import { Deserializable } from "../client/util/SerializationHelper"; import { Doc } from "../new_fields/Doc"; +import { Plugins } from "./util"; +import { computedFn } from "mobx-utils"; function optional(propSchema: PropSchema) { return custom(value => { @@ -86,11 +88,37 @@ export class ScriptField extends ObjectField { @Deserializable("computed", deserializeScript) export class ComputedField extends ScriptField { //TODO maybe add an observable cache based on what is passed in for doc, considering there shouldn't really be that many possible values for doc - value(doc: Doc) { + value = computedFn((doc: Doc) => { const val = this.script.run({ this: doc }); if (val.success) { return val.result; } return undefined; + }); +} + +export namespace ComputedField { + let useComputed = true; + export function DisableComputedFields() { + useComputed = false; } + + export function EnableComputedFields() { + useComputed = true; + } + + export function WithoutComputed<T>(fn: () => T) { + DisableComputedFields(); + try { + return fn(); + } finally { + EnableComputedFields(); + } + } + + Plugins.addGetterPlugin((doc, _, value) => { + if (useComputed && value instanceof ComputedField) { + return { value: value.value(doc), shouldReturn: true }; + } + }); }
\ No newline at end of file diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index 47e467041..b59ec9b9a 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -1,5 +1,5 @@ import { UndoManager } from "../client/util/UndoManager"; -import { Doc, Field } from "./Doc"; +import { Doc, Field, FieldResult } from "./Doc"; import { SerializationHelper } from "../client/util/SerializationHelper"; import { ProxyField } from "./Proxy"; import { RefField } from "./RefField"; @@ -11,6 +11,20 @@ import { ComputedField } from "./ScriptField"; function _readOnlySetter(): never { throw new Error("Documents can't be modified in read-only mode"); } + +export interface GetterResult { + value: FieldResult; + shouldReturn: boolean; +} +export type GetterPlugin = (receiver: any, prop: string | number, currentValue: any) => GetterResult | undefined; +const getterPlugins: GetterPlugin[] = []; + +export namespace Plugins { + export function addGetterPlugin(plugin: GetterPlugin) { + getterPlugins.push(plugin); + } +} + const _setterImpl = action(function (target: any, prop: string | symbol | number, value: any, receiver: any): boolean { //console.log("-set " + target[SelfProxy].title + "(" + target[SelfProxy][prop] + ")." + prop.toString() + " = " + value); if (SerializationHelper.IsSerializing()) { @@ -85,12 +99,18 @@ export function getter(target: any, prop: string | symbol | number, receiver: an function getFieldImpl(target: any, prop: string | number, receiver: any, ignoreProto: boolean = false): any { receiver = receiver || target[SelfProxy]; - const field = target.__fields[prop]; + let field = target.__fields[prop]; if (field instanceof ProxyField) { return field.value(); } - if (field instanceof ComputedField) { - return field.value(receiver); + for (const plugin of getterPlugins) { + const res = plugin(receiver, prop, field); + if (res === undefined) continue; + if (res.shouldReturn) { + return res.value; + } else { + field = res.value; + } } if (field === undefined && !ignoreProto && prop !== "proto") { const proto = getFieldImpl(target, "proto", receiver, true);//TODO tfs: instead of receiver we could use target[SelfProxy]... I don't which semantics we want or if it really matters |
