aboutsummaryrefslogtreecommitdiff
path: root/src/new_fields
diff options
context:
space:
mode:
authorStanley Yip <stanley_yip@brown.edu>2020-02-09 14:58:57 -0500
committerStanley Yip <stanley_yip@brown.edu>2020-02-09 14:58:57 -0500
commitf6179334d6f2942631caa17b7c8ae2531d87c7c4 (patch)
tree091da0ef7bedb900c958c28cebe4058fade644cf /src/new_fields
parent07141291bee793955d7061f4e479942d7aceda67 (diff)
parent87167fd126e161b29d8d798a5f04e3cf159aae16 (diff)
recommender system works
Diffstat (limited to 'src/new_fields')
-rw-r--r--src/new_fields/CursorField.ts5
-rw-r--r--src/new_fields/DateField.ts9
-rw-r--r--src/new_fields/Doc.ts368
-rw-r--r--src/new_fields/FieldSymbols.ts3
-rw-r--r--src/new_fields/HtmlField.ts5
-rw-r--r--src/new_fields/IconField.ts5
-rw-r--r--src/new_fields/InkField.ts31
-rw-r--r--src/new_fields/List.ts12
-rw-r--r--src/new_fields/ObjectField.ts5
-rw-r--r--src/new_fields/Proxy.ts5
-rw-r--r--src/new_fields/RefField.ts3
-rw-r--r--src/new_fields/RichTextField.ts5
-rw-r--r--src/new_fields/RichTextUtils.ts87
-rw-r--r--src/new_fields/Schema.ts2
-rw-r--r--src/new_fields/SchemaHeaderField.ts5
-rw-r--r--src/new_fields/ScriptField.ts31
-rw-r--r--src/new_fields/URLField.ts5
-rw-r--r--src/new_fields/documentSchemas.ts43
-rw-r--r--src/new_fields/util.ts43
19 files changed, 415 insertions, 257 deletions
diff --git a/src/new_fields/CursorField.ts b/src/new_fields/CursorField.ts
index fd86031a8..28467377b 100644
--- a/src/new_fields/CursorField.ts
+++ b/src/new_fields/CursorField.ts
@@ -2,7 +2,7 @@ import { ObjectField } from "./ObjectField";
import { observable } from "mobx";
import { Deserializable } from "../client/util/SerializationHelper";
import { serializable, createSimpleSchema, object, date } from "serializr";
-import { OnUpdate, ToScriptString, Copy } from "./FieldSymbols";
+import { OnUpdate, ToScriptString, ToString, Copy } from "./FieldSymbols";
export type CursorPosition = {
x: number,
@@ -60,4 +60,7 @@ export default class CursorField extends ObjectField {
[ToScriptString]() {
return "invalid";
}
+ [ToString]() {
+ return "invalid";
+ }
} \ No newline at end of file
diff --git a/src/new_fields/DateField.ts b/src/new_fields/DateField.ts
index abec91e06..a925148c2 100644
--- a/src/new_fields/DateField.ts
+++ b/src/new_fields/DateField.ts
@@ -1,7 +1,7 @@
import { Deserializable } from "../client/util/SerializationHelper";
import { serializable, date } from "serializr";
import { ObjectField } from "./ObjectField";
-import { Copy, ToScriptString } from "./FieldSymbols";
+import { Copy, ToScriptString, ToString } from "./FieldSymbols";
import { scriptingGlobal, Scripting } from "../client/util/Scripting";
@scriptingGlobal
@@ -19,9 +19,16 @@ export class DateField extends ObjectField {
return new DateField(this.date);
}
+ toString() {
+ return `${this.date.toISOString()}`;
+ }
+
[ToScriptString]() {
return `new DateField(new Date(${this.date.toISOString()}))`;
}
+ [ToString]() {
+ return this.date.toISOString();
+ }
}
Scripting.addGlobal(function d(...dateArgs: any[]) {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 4531fd5e0..5f78636a9 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -1,26 +1,28 @@
-import { observable, ObservableMap, runInAction, action } from "mobx";
+import { observable, ObservableMap, runInAction } from "mobx";
import { alias, map, serializable } from "serializr";
import { DocServer } from "../client/DocServer";
import { DocumentType } from "../client/documents/DocumentTypes";
import { Scripting, scriptingGlobal } from "../client/util/Scripting";
import { afterDocDeserialize, autoObject, Deserializable, SerializationHelper } from "../client/util/SerializationHelper";
-import { Copy, HandleUpdate, Id, OnUpdate, Parent, Self, SelfProxy, ToScriptString, Update } from "./FieldSymbols";
+import { Copy, HandleUpdate, Id, OnUpdate, Parent, Self, SelfProxy, ToScriptString, ToString, Update } from "./FieldSymbols";
import { List } from "./List";
import { ObjectField } from "./ObjectField";
import { PrefetchProxy, ProxyField } from "./Proxy";
import { FieldId, RefField } from "./RefField";
import { listSpec } from "./Schema";
-import { ComputedField } from "./ScriptField";
-import { BoolCast, Cast, FieldValue, NumCast, PromiseValue, StrCast, ToConstructor } from "./Types";
+import { ComputedField, ScriptField } from "./ScriptField";
+import { BoolCast, Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types";
import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util";
import { intersectRect } from "../Utils";
import { UndoManager } from "../client/util/UndoManager";
+import { computedFn } from "mobx-utils";
+import { RichTextField } from "./RichTextField";
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
const onDelegate = Object.keys(doc).includes(key);
- let field = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
+ const field = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
if (Field.IsField(field)) {
return (onDelegate ? "=" : "") + (field instanceof ComputedField ? `:=${field.script.originalScript}` : Field.toScriptString(field));
}
@@ -35,6 +37,18 @@ export namespace Field {
return field[ToScriptString]();
}
}
+ export function toString(field: Field): string {
+ if (typeof field === "string") {
+ return field;
+ } else if (typeof field === "number" || typeof field === "boolean") {
+ return String(field);
+ } else if (field instanceof ObjectField) {
+ return field[ToString]();
+ } else if (field instanceof RefField) {
+ return field[ToString]();
+ }
+ return "(null)";
+ }
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 {
@@ -74,6 +88,7 @@ export function DocListCast(field: FieldResult): Doc[] {
export const WidthSym = Symbol("Width");
export const HeightSym = Symbol("Height");
+export const DataSym = Symbol("Data");
export const UpdatingFromServer = Symbol("UpdatingFromServer");
const CachedUpdates = Symbol("Cached updates");
@@ -149,12 +164,16 @@ export class Doc extends RefField {
private [Self] = this;
private [SelfProxy]: any;
- public [WidthSym] = () => NumCast(this[SelfProxy].width);
- public [HeightSym] = () => NumCast(this[SelfProxy].height);
+ public [WidthSym] = () => NumCast(this[SelfProxy]._width);
+ public [HeightSym] = () => NumCast(this[SelfProxy]._height);
+ public get [DataSym]() { return Cast(this[SelfProxy].resolvedDataDoc, Doc, null) || this[SelfProxy]; }
[ToScriptString]() {
return "invalid";
}
+ [ToString]() {
+ return "Doc";
+ }
private [CachedUpdates]: { [key: string]: () => void | Promise<any> } = {};
public static CurrentUserEmail: string = "";
@@ -254,9 +273,9 @@ export namespace Doc {
return GetT(doc, "isPrototype", "boolean", true);
}
export async function SetInPlace(doc: Doc, key: string, value: Field | undefined, defaultProto: boolean) {
- let hasProto = doc.proto instanceof Doc;
- let onDeleg = Object.getOwnPropertyNames(doc).indexOf(key) !== -1;
- let onProto = hasProto && Object.getOwnPropertyNames(doc.proto).indexOf(key) !== -1;
+ const hasProto = doc.proto instanceof Doc;
+ const onDeleg = Object.getOwnPropertyNames(doc).indexOf(key) !== -1;
+ const onProto = hasProto && Object.getOwnPropertyNames(doc.proto).indexOf(key) !== -1;
if (onDeleg || !hasProto || (!onProto && !defaultProto)) {
doc[key] = value;
} else doc.proto![key] = value;
@@ -289,14 +308,13 @@ export namespace Doc {
* @param fields the fields to project onto the target. Its type signature defines a mapping from some string key
* to a potentially undefined field, where each entry in this mapping is optional.
*/
- export function assign<K extends string>(doc: Doc, fields: Partial<Record<K, Opt<Field>>>) {
+ export function assign<K extends string>(doc: Doc, fields: Partial<Record<K, Opt<Field>>>, skipUndefineds: boolean = false) {
for (const key in fields) {
if (fields.hasOwnProperty(key)) {
const value = fields[key];
- // Do we want to filter out undefineds?
- // if (value !== undefined) {
- doc[key] = value;
- // }
+ if (!skipUndefineds || value !== undefined) { // Do we want to filter out undefineds?
+ doc[key] = value;
+ }
}
}
return doc;
@@ -305,10 +323,10 @@ export namespace Doc {
// compare whether documents or their protos match
export function AreProtosEqual(doc?: Doc, other?: Doc) {
if (!doc || !other) return false;
- let r = (doc === other);
- let r2 = (Doc.GetProto(doc) === other);
- let r3 = (Doc.GetProto(other) === doc);
- let r4 = (Doc.GetProto(doc) === Doc.GetProto(other) && Doc.GetProto(other) !== undefined);
+ const r = (doc === other);
+ const r2 = (Doc.GetProto(doc) === other);
+ const r3 = (Doc.GetProto(other) === doc);
+ const r4 = (Doc.GetProto(doc) === Doc.GetProto(other) && Doc.GetProto(other) !== undefined);
return r || r2 || r3 || r4;
}
@@ -317,7 +335,7 @@ export namespace Doc {
return doc && (Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : (doc.proto || doc));
}
export function GetDataDoc(doc: Doc): Doc {
- let proto = Doc.GetProto(doc);
+ const proto = Doc.GetProto(doc);
return proto === doc ? proto : Doc.GetDataDoc(proto);
}
@@ -342,9 +360,9 @@ export namespace Doc {
if (listDoc[key] === undefined) {
Doc.GetProto(listDoc)[key] = new List<Doc>();
}
- let list = Cast(listDoc[key], listSpec(Doc));
+ const list = Cast(listDoc[key], listSpec(Doc));
if (list) {
- let ind = list.indexOf(doc);
+ const ind = list.indexOf(doc);
if (ind !== -1) {
list.splice(ind, 1);
return true;
@@ -356,10 +374,10 @@ export namespace Doc {
if (listDoc[key] === undefined) {
Doc.GetProto(listDoc)[key] = new List<Doc>();
}
- let list = Cast(listDoc[key], listSpec(Doc));
+ const list = Cast(listDoc[key], listSpec(Doc));
if (list) {
if (allowDuplicates !== true) {
- let pind = list.reduce((l, d, i) => d instanceof Doc && d[Id] === doc[Id] ? i : l, -1);
+ const pind = list.reduce((l, d, i) => d instanceof Doc && d[Id] === doc[Id] ? i : l, -1);
if (pind !== -1) {
list.splice(pind, 1);
}
@@ -368,7 +386,7 @@ export namespace Doc {
list.splice(0, 0, doc);
}
else {
- let ind = relativeTo ? list.indexOf(relativeTo) : -1;
+ const ind = relativeTo ? list.indexOf(relativeTo) : -1;
if (ind === -1) {
if (reversed) list.splice(0, 0, doc);
else list.push(doc);
@@ -387,9 +405,9 @@ export namespace Doc {
// Computes the bounds of the contents of a set of documents.
//
export function ComputeContentBounds(docList: Doc[]) {
- let bounds = docList.reduce((bounds, doc) => {
- var [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)];
- let [bptX, bptY] = [sptX + doc[WidthSym](), sptY + doc[HeightSym]()];
+ const bounds = docList.reduce((bounds, doc) => {
+ const [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)];
+ const [bptX, bptY] = [sptX + doc[WidthSym](), sptY + doc[HeightSym]()];
return {
x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y),
r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b)
@@ -399,89 +417,80 @@ export namespace Doc {
}
export function MakeTitled(title: string) {
- let doc = new Doc();
+ const doc = new Doc();
doc.title = title;
return doc;
}
export function MakeAlias(doc: Doc) {
- let alias = !GetT(doc, "isPrototype", "boolean", true) ? Doc.MakeCopy(doc) : Doc.MakeDelegate(doc);
- if (alias.layout instanceof Doc) {
- alias.layout = Doc.MakeAlias(alias.layout);
+ const alias = !GetT(doc, "isPrototype", "boolean", true) ? Doc.MakeCopy(doc) : Doc.MakeDelegate(doc);
+ const layout = Doc.Layout(alias);
+ if (layout instanceof Doc && layout !== alias) {
+ Doc.SetLayout(alias, Doc.MakeAlias(layout));
}
- let aliasNumber = Doc.GetProto(doc).aliasNumber = NumCast(Doc.GetProto(doc).aliasNumber) + 1;
- alias.title = ComputedField.MakeFunction(`renameAlias(this, ${aliasNumber})`);
+ alias.title = ComputedField.MakeFunction(`renameAlias(this, ${Doc.GetProto(doc).aliasNumber = NumCast(Doc.GetProto(doc).aliasNumber) + 1})`);
return alias;
}
//
// Determines whether the combination of the layoutDoc and dataDoc represents
- // a template relationship. If so, the layoutDoc will be expanded into a new
- // document that inherits the properties of the original layout while allowing
- // for individual layout properties to be overridden in the expanded layout.
+ // a template relationship : there is a dataDoc and it doesn't match the layoutDoc an
+ // the lyouatDoc's layout is layout string (not a document)
//
export function WillExpandTemplateLayout(layoutDoc: Doc, dataDoc?: Doc) {
- return BoolCast(layoutDoc.isTemplateField) && dataDoc && layoutDoc !== dataDoc && !(layoutDoc[StrCast(layoutDoc.layoutKey, "layout")] instanceof Doc);
+ return layoutDoc.isTemplateForField && dataDoc && layoutDoc !== dataDoc && !(Doc.LayoutField(layoutDoc) instanceof Doc);
}
//
- // Returns an expanded template layout for a target data document.
- // First it checks if an expanded layout already exists -- if so it will be stored on the dataDoc
- // using the template layout doc's id as the field key.
- // If it doesn't find the expanded layout, then it makes a delegate of the template layout and
- // saves it on the data doc indexed by the template layout's id
+ // Returns an expanded template layout for a target data document if there is a template relationship
+ // between the two. If so, the layoutDoc is expanded into a new document that inherits the properties
+ // of the original layout while allowing for individual layout properties to be overridden in the expanded layout.
//
export function expandTemplateLayout(templateLayoutDoc: Doc, dataDoc?: Doc) {
if (!WillExpandTemplateLayout(templateLayoutDoc, dataDoc) || !dataDoc) return templateLayoutDoc;
- // if we have a data doc that doesn't match the layout, then we're rendering a template.
- // ... 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 expandedLayoutFieldKey = "Layout[" + templateLayoutDoc[Id] + "]";
- let expandedTemplateLayout = dataDoc[expandedLayoutFieldKey];
- if (expandedTemplateLayout instanceof Doc) {
- return expandedTemplateLayout;
- }
+ const templateField = StrCast(templateLayoutDoc.isTemplateForField); // the field that the template renders
+ // First it checks if an expanded layout already exists -- if so it will be stored on the dataDoc
+ // using the template layout doc's id as the field key.
+ // If it doesn't find the expanded layout, then it makes a delegate of the template layout and
+ // saves it on the data doc indexed by the template layout's id.
+ //
+ const expandedLayoutFieldKey = templateField + "-layout[" + templateLayoutDoc[Id] + "]";
+ const expandedTemplateLayout = dataDoc?.[expandedLayoutFieldKey];
if (expandedTemplateLayout === undefined) {
- setTimeout(() => dataDoc[expandedLayoutFieldKey] === undefined &&
- (dataDoc[expandedLayoutFieldKey] = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]")), 0);
+ setTimeout(() => {
+ if (!dataDoc[expandedLayoutFieldKey]) {
+ const newLayoutDoc = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]");
+ dataDoc[expandedLayoutFieldKey] = newLayoutDoc;
+ newLayoutDoc.resolvedDataDoc = dataDoc;
+ if (dataDoc[templateField] === undefined && templateLayoutDoc[templateField] instanceof List && Cast(templateLayoutDoc[templateField], listSpec(Doc), []).length) {
+ dataDoc[templateField] = ComputedField.MakeFunction(`ObjectField.MakeCopy(templateLayoutDoc["${templateField}"] as List)`, { templateLayoutDoc: Doc.name }, { templateLayoutDoc: templateLayoutDoc });
+ }
+ }
+ }, 0);
}
- return undefined; // use the templateLayout when it's not a template or the expandedTemplate is pending.
+ return expandedTemplateLayout instanceof Doc ? expandedTemplateLayout : undefined; // layout is undefined if the expandedTemplate is pending.
}
- export function GetLayoutDataDocPair(doc: Doc, dataDoc: Doc | undefined, fieldKey: string, childDocLayout: Doc) {
- let layoutDoc: Doc | undefined = childDocLayout;
- let resolvedDataDoc = !doc.isTemplateField && dataDoc !== doc && dataDoc ? Doc.GetDataDoc(dataDoc) : undefined;
- if (resolvedDataDoc && Doc.WillExpandTemplateLayout(childDocLayout, resolvedDataDoc)) {
- let extensionDoc = fieldExtensionDoc(resolvedDataDoc, StrCast(childDocLayout.templateField, StrCast(childDocLayout.title)));
- layoutDoc = Doc.expandTemplateLayout(childDocLayout, extensionDoc !== resolvedDataDoc ? extensionDoc : undefined);
- } else layoutDoc = childDocLayout;
- return { layout: layoutDoc, data: resolvedDataDoc };
+ // if the childDoc is a template for a field, then this will return the expanded layout with its data doc.
+ // otherwise, it just returns the childDoc
+ export function GetLayoutDataDocPair(containerDoc: Doc, containerDataDoc: Opt<Doc>, childDoc: Doc) {
+ const resolvedDataDoc = containerDataDoc === containerDoc || !containerDataDoc ? undefined : Doc.GetDataDoc(containerDataDoc);
+ return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc), data: resolvedDataDoc };
}
-
- //
- // Resolves a reference to a field by returning 'doc' if no field extension is specified,
- // otherwise, it returns the extension document stored in doc.<fieldKey>_ext.
- // This mechanism allows any fields to be extended with an extension document that can
- // be used to capture field-specific metadata. For example, an image field can be extended
- // to store annotations, ink, and other data.
- //
- export function fieldExtensionDoc(doc: Doc, fieldKey: string) {
- let extension = doc[fieldKey + "_ext"] as Doc;
- (extension === undefined) && setTimeout(() => CreateDocumentExtensionForField(doc, fieldKey), 0);
- return extension ? extension : undefined;
- }
-
export function CreateDocumentExtensionForField(doc: Doc, fieldKey: string) {
- let docExtensionForField = new Doc(doc[Id] + fieldKey, true);
- docExtensionForField.title = fieldKey + ".ext"; // courtesy field--- shouldn't be needed except maybe for debugging
- docExtensionForField.extendsDoc = doc; // this is used by search to map field matches on the extension doc back to the document it extends.
- docExtensionForField.extendsField = fieldKey; // this can be used by search to map matches on the extension doc back to the field that was extended.
- docExtensionForField.type = DocumentType.EXTENSION;
let proto: Doc | undefined = doc;
while (proto && !Doc.IsPrototype(proto) && proto.proto) {
proto = proto.proto;
}
- (proto ? proto : doc)[fieldKey + "_ext"] = new PrefetchProxy(docExtensionForField);
+ let docExtensionForField = ((proto || doc)[fieldKey + "_ext"] as Doc);
+ if (!docExtensionForField) {
+ docExtensionForField = new Doc(doc[Id] + fieldKey, true);
+ docExtensionForField.title = fieldKey + ".ext"; // courtesy field--- shouldn't be needed except maybe for debugging
+ docExtensionForField.extendsDoc = doc; // this is used by search to map field matches on the extension doc back to the document it extends.
+ docExtensionForField.extendsField = fieldKey; // this can be used by search to map matches on the extension doc back to the field that was extended.
+ docExtensionForField.type = DocumentType.EXTENSION;
+ (proto || doc)[fieldKey + "_ext"] = new PrefetchProxy(docExtensionForField);
+ }
return docExtensionForField;
}
@@ -510,8 +519,10 @@ export namespace Doc {
export function MakeCopy(doc: Doc, copyProto: boolean = false, copyProtoId?: string): Doc {
const copy = new Doc(copyProtoId, true);
+ const exclude = Cast(doc.excludeFields, listSpec("string"), []);
Object.keys(doc).forEach(key => {
- let cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
+ if (exclude.includes(key)) return;
+ const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
const field = ProxyField.WithoutProxy(() => doc[key]);
if (key === "proto" && copyProto) {
if (doc[key] instanceof Doc) {
@@ -550,7 +561,7 @@ export namespace Doc {
let _applyCount: number = 0;
export function ApplyTemplate(templateDoc: Doc) {
if (templateDoc) {
- let applied = ApplyTemplateTo(templateDoc, Doc.MakeDelegate(new Doc()), "layoutCustom", templateDoc.title + "(..." + _applyCount++ + ")");
+ const applied = ApplyTemplateTo(templateDoc, Doc.MakeDelegate(new Doc()), "layoutCustom", templateDoc.title + "(..." + _applyCount++ + ")");
applied && (Doc.GetProto(applied).layout = applied.layout);
return applied;
}
@@ -559,71 +570,78 @@ export namespace Doc {
export function ApplyTemplateTo(templateDoc: Doc, target: Doc, targetKey: string, titleTarget: string | undefined = undefined) {
if (!templateDoc) {
target.layout = undefined;
- target.nativeWidth = undefined;
- target.nativeHeight = undefined;
+ target._nativeWidth = undefined;
+ target._nativeHeight = undefined;
target.onClick = undefined;
target.type = undefined;
return;
}
- let layoutCustomLayout = Doc.MakeDelegate(templateDoc);
+ if ((target[targetKey] as Doc)?.proto !== templateDoc) {
+ const layoutCustomLayout = Doc.MakeDelegate(templateDoc);
- titleTarget && (Doc.GetProto(target).title = titleTarget);
- Doc.GetProto(target).type = DocumentType.TEMPLATE;
- target.onClick = templateDoc.onClick instanceof ObjectField && templateDoc.onClick[Copy]();
+ titleTarget && (Doc.GetProto(target).title = titleTarget);
+ Doc.GetProto(target).type = DocumentType.TEMPLATE;
+ target.onClick = templateDoc.onClick instanceof ObjectField && templateDoc.onClick[Copy]();
- Doc.GetProto(target)[targetKey] = layoutCustomLayout;
+ Doc.GetProto(target)[targetKey] = new PrefetchProxy(layoutCustomLayout);
+ }
target.layoutKey = targetKey;
return target;
}
- export function MakeMetadataFieldTemplate(fieldTemplate: Doc, templateDataDoc: Doc, suppressTitle: boolean = false): boolean {
- // move data doc fields to layout doc as needed (nativeWidth/nativeHeight, data, ??)
- let metadataFieldName = StrCast(fieldTemplate.title).replace(/^-/, "");
- let fieldLayoutDoc = fieldTemplate;
- if (fieldTemplate.layout instanceof Doc) {
- fieldLayoutDoc = Doc.MakeDelegate(fieldTemplate.layout);
- }
-
- fieldTemplate.templateField = metadataFieldName;
- fieldTemplate.title = metadataFieldName;
- fieldTemplate.isTemplateField = true;
- /* move certain layout properties from the original data doc to the template layout to avoid
- inheriting them from the template's data doc which may also define these fields for its own use.
- */
- fieldTemplate.ignoreAspect = fieldTemplate.ignoreAspect === undefined ? undefined : BoolCast(fieldTemplate.ignoreAspect);
- fieldTemplate.singleColumn = BoolCast(fieldTemplate.singleColumn);
- fieldTemplate.nativeWidth = Cast(fieldTemplate.nativeWidth, "number");
- fieldTemplate.nativeHeight = Cast(fieldTemplate.nativeHeight, "number");
- fieldTemplate.type = fieldTemplate.type;
- fieldTemplate.panX = 0;
- fieldTemplate.panY = 0;
- fieldTemplate.scale = 1;
- fieldTemplate.showTitle = suppressTitle ? undefined : "title";
- let data = fieldTemplate.data;
- setTimeout(action(() => {
- !templateDataDoc[metadataFieldName] && data instanceof ObjectField && (Doc.GetProto(templateDataDoc)[metadataFieldName] = ObjectField.MakeCopy(data));
- let layout = StrCast(fieldLayoutDoc.layout).replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metadataFieldName}"}`);
- let layoutDelegate = Doc.Layout(fieldTemplate);
- layoutDelegate.layout = layout;
- fieldTemplate.layout = layoutDelegate !== fieldTemplate ? layoutDelegate : layout;
- if (fieldTemplate.backgroundColor !== templateDataDoc.defaultBackgroundColor) fieldTemplate.defaultBackgroundColor = fieldTemplate.backgroundColor;
- fieldTemplate.proto = templateDataDoc;
- }), 0);
+ //
+ // This function converts a generic field layout display into a field layout that displays a specific
+ // metadata field indicated by the title of the template field (not the default field that it was rendering)
+ //
+ export function MakeMetadataFieldTemplate(templateField: Doc, templateDoc: Opt<Doc>): boolean {
+
+ // find the metadata field key that this template field doc will display (indicated by its title)
+ const metadataFieldKey = StrCast(templateField.title).replace(/^-/, "");
+
+ // update the original template to mark it as a template
+ templateField.isTemplateForField = metadataFieldKey;
+ templateField.title = metadataFieldKey;
+
+ // move any data that the template field had been rendering over to the template doc so that things will still be rendered
+ // when the template field is adjusted to point to the new metadatafield key.
+ // note 1: if the template field contained a list of documents, each of those documents will be converted to templates as well.
+ // note 2: this will not overwrite any field that already exists on the template doc at the field key
+ if (!templateDoc?.[metadataFieldKey] && templateField.data instanceof ObjectField) {
+ Cast(templateField.data, listSpec(Doc), [])?.map(d => d instanceof Doc && MakeMetadataFieldTemplate(d, templateDoc));
+ (Doc.GetProto(templateField)[metadataFieldKey] = ObjectField.MakeCopy(templateField.data));
+ }
+ if (templateField.data instanceof RichTextField && templateField.data.Text) {
+ templateField._textTemplate = ComputedField.MakeFunction(`copyField(this.${metadataFieldKey})`, { this: Doc.name });
+ }
+
+ // get the layout string that the template uses to specify its layout
+ const templateFieldLayoutString = StrCast(Doc.LayoutField(Doc.Layout(templateField)));
+
+ // change itto render the target metadata field instead of what it was rendering before and assign it to the template field layout document.
+ Doc.Layout(templateField).layout = templateFieldLayoutString.replace(/fieldKey={'[^']*'}/, `fieldKey={'${metadataFieldKey}'}`);
+
+ // assign the template field doc a delegate of any extension document that was previously used to render the template field (since extension doc's carry rendering informatino)
+ Doc.Layout(templateField)[metadataFieldKey + "_ext"] = Doc.MakeDelegate(templateField[templateFieldLayoutString?.split("'")[1] + "_ext"] as Doc);
+
+ if (templateField.backgroundColor !== templateDoc?.defaultBackgroundColor) {
+ templateField.defaultBackgroundColor = templateField.backgroundColor;
+ }
+
return true;
}
export function overlapping(doc1: Doc, doc2: Doc, clusterDistance: number) {
- let doc2Layout = Doc.Layout(doc2);
- let doc1Layout = Doc.Layout(doc1);
- var x2 = NumCast(doc2.x) - clusterDistance;
- var y2 = NumCast(doc2.y) - clusterDistance;
- var w2 = NumCast(doc2Layout.width) + clusterDistance;
- var h2 = NumCast(doc2Layout.height) + clusterDistance;
- var x = NumCast(doc1.x) - clusterDistance;
- var y = NumCast(doc1.y) - clusterDistance;
- var w = NumCast(doc1Layout.width) + clusterDistance;
- var h = NumCast(doc1Layout.height) + clusterDistance;
+ const doc2Layout = Doc.Layout(doc2);
+ const doc1Layout = Doc.Layout(doc1);
+ const x2 = NumCast(doc2.x) - clusterDistance;
+ const y2 = NumCast(doc2.y) - clusterDistance;
+ const w2 = NumCast(doc2Layout._width) + clusterDistance;
+ const h2 = NumCast(doc2Layout._height) + clusterDistance;
+ const x = NumCast(doc1.x) - clusterDistance;
+ const y = NumCast(doc1.y) - clusterDistance;
+ const w = NumCast(doc1Layout._width) + clusterDistance;
+ const h = NumCast(doc1Layout._height) + clusterDistance;
return doc1.z === doc2.z && intersectRect({ left: x, top: y, width: w, height: h }, { left: x2, top: y2, width: w2, height: h2 });
}
@@ -637,27 +655,39 @@ export namespace Doc {
}
export class DocBrush {
- @observable BrushedDoc: ObservableMap<Doc, boolean> = new ObservableMap();
+ BrushedDoc: ObservableMap<Doc, boolean> = new ObservableMap();
}
const brushManager = new DocBrush();
export class DocData {
@observable _user_doc: Doc = undefined!;
- @observable BrushedDoc: ObservableMap<Doc, boolean> = new ObservableMap();
+ @observable _searchQuery: string = "";
}
// the document containing the view layout information - will be the Document itself unless the Document has
// a layout field. In that case, all layout information comes from there unless overriden by Document
- export function Layout(doc: Doc) { return Doc.LayoutField(doc) instanceof Doc ? doc[StrCast(doc.layoutKey, "layout")] as Doc : doc; }
+ export function Layout(doc: Doc) { return Doc.LayoutField(doc) instanceof Doc ? Doc.LayoutField(doc) as Doc : doc; }
+ export function SetLayout(doc: Doc, layout: Doc | string) { doc[StrCast(doc.layoutKey, "layout")] = layout; }
export function LayoutField(doc: Doc) { return doc[StrCast(doc.layoutKey, "layout")]; }
+ export function LayoutFieldKey(doc: Doc) { return StrCast(Doc.Layout(doc).layout).split("'")[1]; }
const manager = new DocData();
+ export function SearchQuery(): string { return manager._searchQuery; }
+ export function SetSearchQuery(query: string) { runInAction(() => manager._searchQuery = query); }
export function UserDoc(): Doc { return manager._user_doc; }
export function SetUserDoc(doc: Doc) { manager._user_doc = doc; }
export function IsBrushed(doc: Doc) {
- return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetDataDoc(doc));
+ return computedFn(function IsBrushed(doc: Doc) {
+ return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetDataDoc(doc));
+ })(doc);
+ }
+ // don't bother memoizing (caching) the result if called from a non-reactive context. (plus this avoids a warning message)
+ export function IsBrushedDegreeUnmemoized(doc: Doc) {
+ return brushManager.BrushedDoc.has(doc) ? 2 : brushManager.BrushedDoc.has(Doc.GetDataDoc(doc)) ? 1 : 0;
}
export function IsBrushedDegree(doc: Doc) {
- return brushManager.BrushedDoc.has(Doc.GetDataDoc(doc)) ? 2 : brushManager.BrushedDoc.has(doc) ? 1 : 0;
+ return computedFn(function IsBrushDegree(doc: Doc) {
+ return brushManager.BrushedDoc.has(doc) ? 2 : brushManager.BrushedDoc.has(Doc.GetDataDoc(doc)) ? 1 : 0;
+ })(doc);
}
export function BrushDoc(doc: Doc) {
brushManager.BrushedDoc.set(doc, true);
@@ -671,19 +701,21 @@ export namespace Doc {
}
- export function LinkEndpoint(linkDoc: Doc, anchorDoc: Doc) { return Doc.AreProtosEqual(anchorDoc, Cast(linkDoc.anchor1, Doc) as Doc) ? "layoutKey1" : "layoutKey2"; }
+ export function LinkOtherAnchor(linkDoc: Doc, anchorDoc: Doc) { return Doc.AreProtosEqual(anchorDoc, Cast(linkDoc.anchor1, Doc) as Doc) ? Cast(linkDoc.anchor2, Doc) as Doc : Cast(linkDoc.anchor1, Doc) as Doc; }
+ export function LinkEndpoint(linkDoc: Doc, anchorDoc: Doc) { return Doc.AreProtosEqual(anchorDoc, Cast(linkDoc.anchor1, Doc) as Doc) ? "layout_key1" : "layout_key2"; }
+
export function linkFollowUnhighlight() {
Doc.UnhighlightAll();
document.removeEventListener("pointerdown", linkFollowUnhighlight);
}
let dt = 0;
- export function linkFollowHighlight(destDoc: Doc) {
+ export function linkFollowHighlight(destDoc: Doc, dataAndDisplayDocs = true) {
linkFollowUnhighlight();
- Doc.HighlightDoc(destDoc);
+ Doc.HighlightDoc(destDoc, dataAndDisplayDocs);
document.removeEventListener("pointerdown", linkFollowUnhighlight);
document.addEventListener("pointerdown", linkFollowUnhighlight);
- let x = dt = Date.now();
+ const x = dt = Date.now();
window.setTimeout(() => dt === x && linkFollowUnhighlight(), 5000);
}
@@ -692,13 +724,12 @@ export namespace Doc {
}
const highlightManager = new HighlightBrush();
export function IsHighlighted(doc: Doc) {
- let IsHighlighted = highlightManager.HighlightedDoc.get(doc) || highlightManager.HighlightedDoc.get(Doc.GetDataDoc(doc));
- return IsHighlighted;
+ return highlightManager.HighlightedDoc.get(doc) || highlightManager.HighlightedDoc.get(Doc.GetDataDoc(doc));
}
- export function HighlightDoc(doc: Doc) {
+ export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true) {
runInAction(() => {
highlightManager.HighlightedDoc.set(doc, true);
- highlightManager.HighlightedDoc.set(Doc.GetDataDoc(doc), true);
+ dataAndDisplayDocs && highlightManager.HighlightedDoc.set(Doc.GetDataDoc(doc), true);
});
}
export function UnHighlightDoc(doc: Doc) {
@@ -708,10 +739,10 @@ export namespace Doc {
});
}
export function UnhighlightAll() {
- let mapEntries = highlightManager.HighlightedDoc.keys();
+ const mapEntries = highlightManager.HighlightedDoc.keys();
let docEntry: IteratorResult<Doc>;
while (!(docEntry = mapEntries.next()).done) {
- let targetDoc = docEntry.value;
+ const targetDoc = docEntry.value;
targetDoc && Doc.UnHighlightDoc(targetDoc);
}
@@ -725,12 +756,27 @@ export namespace Doc {
source.dragFactory instanceof Doc && source.dragFactory.isTemplateDoc ? source.dragFactory :
source && source.layout instanceof Doc && source.layout.isTemplateDoc ? source.layout : undefined;
}
-}
+ export function setChildDetailedLayout(target: Doc, source?: Doc) {
+ target.childDetailed = source && source.isTemplateDoc ? source : source &&
+ source.dragFactory instanceof Doc && source.dragFactory.isTemplateDoc ? source.dragFactory :
+ source && source.layout instanceof Doc && source.layout.isTemplateDoc ? source.layout : undefined;
+ }
+ export function matchFieldValue(doc: Doc, key: string, value: any): boolean {
+ const fieldVal = doc[key] ? doc[key] : doc[key + "_ext"];
+ if (Cast(fieldVal, listSpec("string"), []).length) {
+ const vals = Cast(fieldVal, listSpec("string"), []);
+ return vals.some(v => v === value);
+ }
+ const fieldStr = Field.toString(fieldVal as Field);
+ return fieldStr === value;
+ }
+}
Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, "") + `(${n})`; });
Scripting.addGlobal(function getProto(doc: any) { return Doc.GetProto(doc); });
Scripting.addGlobal(function setChildLayout(target: any, source: any) { Doc.setChildLayout(target, source); });
+Scripting.addGlobal(function setChildDetailedLayout(target: any, source: any) { Doc.setChildDetailedLayout(target, source); });
Scripting.addGlobal(function getAlias(doc: any) { return Doc.MakeAlias(doc); });
Scripting.addGlobal(function getCopy(doc: any, copyProto: any) { return doc.isTemplateDoc ? Doc.ApplyTemplate(doc) : Doc.MakeCopy(doc, copyProto); });
Scripting.addGlobal(function copyField(field: any) { return ObjectField.MakeCopy(field); });
@@ -738,4 +784,24 @@ Scripting.addGlobal(function aliasDocs(field: any) { return new List<Doc>(field.
Scripting.addGlobal(function docList(field: any) { return DocListCast(field); });
Scripting.addGlobal(function sameDocs(doc1: any, doc2: any) { return Doc.AreProtosEqual(doc1, doc2); });
Scripting.addGlobal(function undo() { return UndoManager.Undo(); });
-Scripting.addGlobal(function redo() { return UndoManager.Redo(); }); \ No newline at end of file
+Scripting.addGlobal(function redo() { return UndoManager.Redo(); });
+Scripting.addGlobal(function selectDoc(doc: any) { Doc.UserDoc().SelectedDocs = new List([doc]); });
+Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: boolean, prevValue: any) {
+ const docs = DocListCast(Doc.UserDoc().SelectedDocs).filter(d => !Doc.AreProtosEqual(d, container) && !d.annotationOn && d.type !== DocumentType.DOCUMENT && d.type !== DocumentType.KVP && (!excludeCollections || !Cast(d.data, listSpec(Doc), null)));
+ return docs.length ? new List(docs) : prevValue;
+});
+Scripting.addGlobal(function setDocFilter(container: Doc, key: string, value: any, modifiers?: string) {
+ const docFilters = Cast(container._docFilter, listSpec("string"), []);
+ for (let i = 0; i < docFilters.length; i += 3) {
+ if (docFilters[i] === key && docFilters[i + 1] === value) {
+ docFilters.splice(i, 3);
+ break;
+ }
+ }
+ if (modifiers !== undefined) {
+ docFilters.push(key);
+ docFilters.push(value);
+ docFilters.push(modifiers);
+ container._docFilter = new List<string>(docFilters);
+ }
+}); \ No newline at end of file
diff --git a/src/new_fields/FieldSymbols.ts b/src/new_fields/FieldSymbols.ts
index 8e5161dac..8d040f493 100644
--- a/src/new_fields/FieldSymbols.ts
+++ b/src/new_fields/FieldSymbols.ts
@@ -8,4 +8,5 @@ export const OnUpdate = Symbol("OnUpdate");
export const Parent = Symbol("Parent");
export const Copy = Symbol("Copy");
export const ToScriptString = Symbol("ToScriptString");
-export const ToPlainText = Symbol("ToPlainText"); \ No newline at end of file
+export const ToPlainText = Symbol("ToPlainText");
+export const ToString = Symbol("ToString");
diff --git a/src/new_fields/HtmlField.ts b/src/new_fields/HtmlField.ts
index f952acff9..6e8bba977 100644
--- a/src/new_fields/HtmlField.ts
+++ b/src/new_fields/HtmlField.ts
@@ -1,7 +1,7 @@
import { Deserializable } from "../client/util/SerializationHelper";
import { serializable, primitive } from "serializr";
import { ObjectField } from "./ObjectField";
-import { Copy, ToScriptString } from "./FieldSymbols";
+import { Copy, ToScriptString, ToString} from "./FieldSymbols";
@Deserializable("html")
export class HtmlField extends ObjectField {
@@ -20,4 +20,7 @@ export class HtmlField extends ObjectField {
[ToScriptString]() {
return "invalid";
}
+ [ToString]() {
+ return this.html;
+ }
}
diff --git a/src/new_fields/IconField.ts b/src/new_fields/IconField.ts
index 62b2cd254..76c4ddf1b 100644
--- a/src/new_fields/IconField.ts
+++ b/src/new_fields/IconField.ts
@@ -1,7 +1,7 @@
import { Deserializable } from "../client/util/SerializationHelper";
import { serializable, primitive } from "serializr";
import { ObjectField } from "./ObjectField";
-import { Copy, ToScriptString } from "./FieldSymbols";
+import { Copy, ToScriptString, ToString } from "./FieldSymbols";
@Deserializable("icon")
export class IconField extends ObjectField {
@@ -20,4 +20,7 @@ export class IconField extends ObjectField {
[ToScriptString]() {
return "invalid";
}
+ [ToString]() {
+ return "ICONfield";
+ }
}
diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts
index d94834e91..4a44b4f55 100644
--- a/src/new_fields/InkField.ts
+++ b/src/new_fields/InkField.ts
@@ -1,30 +1,26 @@
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 { Copy, ToScriptString, ToString } from "./FieldSymbols";
export enum InkTool {
None,
Pen,
Highlighter,
Eraser,
- Scrubber
+ Scrubber,
+ Stamp
}
-export interface StrokeData {
- pathData: Array<{ x: number, y: number }>;
- color: string;
- width: string;
- tool: InkTool;
- displayTimecode: number;
- creationTime: number;
+export interface PointData {
+ X: number;
+ Y: number;
}
-export type InkData = Map<string, StrokeData>;
+export type InkData = Array<PointData>;
const pointSchema = createSimpleSchema({
- x: true, y: true
+ X: true, Y: true
});
const strokeDataSchema = createSimpleSchema({
@@ -34,19 +30,22 @@ const strokeDataSchema = createSimpleSchema({
@Deserializable("ink")
export class InkField extends ObjectField {
- @serializable(map(object(strokeDataSchema)))
+ @serializable(list(object(strokeDataSchema)))
readonly inkData: InkData;
- constructor(data?: InkData) {
+ constructor(data: InkData) {
super();
- this.inkData = data || new Map;
+ this.inkData = data;
}
[Copy]() {
- return new InkField(DeepCopy(this.inkData));
+ return new InkField(this.inkData);
}
[ToScriptString]() {
return "invalid";
}
+ [ToString]() {
+ return "InkField";
+ }
}
diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts
index 0c7b77fa5..a43f11e82 100644
--- a/src/new_fields/List.ts
+++ b/src/new_fields/List.ts
@@ -6,7 +6,7 @@ import { observable, action } from "mobx";
import { ObjectField } from "./ObjectField";
import { RefField } from "./RefField";
import { ProxyField } from "./Proxy";
-import { Self, Update, Parent, OnUpdate, SelfProxy, ToScriptString, Copy } from "./FieldSymbols";
+import { Self, Update, Parent, OnUpdate, SelfProxy, ToScriptString, ToString, Copy } from "./FieldSymbols";
import { Scripting } from "../client/util/Scripting";
const listHandlers: any = {
@@ -270,8 +270,8 @@ class ListImpl<T extends Field> extends ObjectField {
}
[Copy]() {
- let copiedData = this[Self].__fields.map(f => f instanceof ObjectField ? f[Copy]() : f);
- let deepCopy = new ListImpl<T>(copiedData as any);
+ const copiedData = this[Self].__fields.map(f => f instanceof ObjectField ? f[Copy]() : f);
+ const deepCopy = new ListImpl<T>(copiedData as any);
return deepCopy;
}
@@ -290,8 +290,10 @@ class ListImpl<T extends Field> extends ObjectField {
private [SelfProxy]: any;
[ToScriptString]() {
- return "invalid";
- // return `new List([${(this as any).map((field => Field.toScriptString(field))}])`;
+ return `new List([${(this as any).map((field: any) => Field.toScriptString(field))}])`;
+ }
+ [ToString]() {
+ return "List";
}
}
export type List<T extends Field> = ListImpl<T> & (T | (T extends RefField ? Promise<T> : never))[];
diff --git a/src/new_fields/ObjectField.ts b/src/new_fields/ObjectField.ts
index 65ada91c0..566104b40 100644
--- a/src/new_fields/ObjectField.ts
+++ b/src/new_fields/ObjectField.ts
@@ -1,6 +1,6 @@
import { Doc } from "./Doc";
import { RefField } from "./RefField";
-import { OnUpdate, Parent, Copy, ToScriptString } from "./FieldSymbols";
+import { OnUpdate, Parent, Copy, ToScriptString, ToString } from "./FieldSymbols";
import { Scripting } from "../client/util/Scripting";
export abstract class ObjectField {
@@ -9,11 +9,12 @@ export abstract class ObjectField {
abstract [Copy](): ObjectField;
abstract [ToScriptString](): string;
+ abstract [ToString](): string;
}
export namespace ObjectField {
export function MakeCopy<T extends ObjectField>(field: T) {
- return field[Copy]();
+ return field?.[Copy]();
}
}
diff --git a/src/new_fields/Proxy.ts b/src/new_fields/Proxy.ts
index c6292e37c..d50c0f14e 100644
--- a/src/new_fields/Proxy.ts
+++ b/src/new_fields/Proxy.ts
@@ -5,7 +5,7 @@ import { observable, action } from "mobx";
import { DocServer } from "../client/DocServer";
import { RefField } from "./RefField";
import { ObjectField } from "./ObjectField";
-import { Id, Copy, ToScriptString } from "./FieldSymbols";
+import { Id, Copy, ToScriptString, ToString } from "./FieldSymbols";
import { scriptingGlobal } from "../client/util/Scripting";
import { Plugins } from "./util";
@@ -32,6 +32,9 @@ export class ProxyField<T extends RefField> extends ObjectField {
[ToScriptString]() {
return "invalid";
}
+ [ToString]() {
+ return "ProxyField";
+ }
@serializable(primitive())
readonly fieldId: string = "";
diff --git a/src/new_fields/RefField.ts b/src/new_fields/RefField.ts
index f7bea8c94..b6ef69750 100644
--- a/src/new_fields/RefField.ts
+++ b/src/new_fields/RefField.ts
@@ -1,6 +1,6 @@
import { serializable, primitive, alias } from "serializr";
import { Utils } from "../Utils";
-import { Id, HandleUpdate, ToScriptString } from "./FieldSymbols";
+import { Id, HandleUpdate, ToScriptString, ToString } from "./FieldSymbols";
import { afterDocDeserialize } from "../client/util/SerializationHelper";
export type FieldId = string;
@@ -17,4 +17,5 @@ export abstract class RefField {
protected [HandleUpdate]?(diff: any): void | Promise<void>;
abstract [ToScriptString](): string;
+ abstract [ToString](): string;
}
diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts
index aa4908d51..7b6ce9b98 100644
--- a/src/new_fields/RichTextField.ts
+++ b/src/new_fields/RichTextField.ts
@@ -1,7 +1,7 @@
import { ObjectField } from "./ObjectField";
import { serializable } from "serializr";
import { Deserializable } from "../client/util/SerializationHelper";
-import { Copy, ToScriptString, ToPlainText } from "./FieldSymbols";
+import { Copy, ToScriptString, ToPlainText, ToString } from "./FieldSymbols";
import { scriptingGlobal } from "../client/util/Scripting";
const delimiter = "\n";
@@ -29,6 +29,9 @@ export class RichTextField extends ObjectField {
[ToScriptString]() {
return `new RichTextField("${this.Data}", "${this.Text}")`;
}
+ [ToString]() {
+ return this.Text;
+ }
[ToPlainText]() {
// Because we're working with plain text, just concatenate all paragraphs
diff --git a/src/new_fields/RichTextUtils.ts b/src/new_fields/RichTextUtils.ts
index c2cca859c..c50f8cc48 100644
--- a/src/new_fields/RichTextUtils.ts
+++ b/src/new_fields/RichTextUtils.ts
@@ -8,7 +8,6 @@ import { Opt, Doc } from "./Doc";
import Color = require('color');
import { sinkListItem } from "prosemirror-schema-list";
import { Utils } from "../Utils";
-import { RouteStore } from "../server/RouteStore";
import { Docs } from "../client/documents/Documents";
import { schema } from "../client/util/RichTextSchema";
import { GooglePhotos } from "../client/apis/google_docs/GooglePhotosClientUtils";
@@ -17,7 +16,7 @@ import { Cast, StrCast } from "./Types";
import { Id } from "./FieldSymbols";
import { DocumentView } from "../client/views/nodes/DocumentView";
import { AssertionError } from "assert";
-import { Identified } from "../client/Network";
+import { Networking } from "../client/Network";
export namespace RichTextUtils {
@@ -26,8 +25,8 @@ export namespace RichTextUtils {
export const Initialize = (initial?: string) => {
- let content: any[] = [];
- let state = {
+ const content: any[] = [];
+ const state = {
doc: {
type: "doc",
content,
@@ -57,32 +56,32 @@ export namespace RichTextUtils {
export const ToPlainText = (state: EditorState) => {
// Because we're working with plain text, just concatenate all paragraphs
- let content = state.doc.content;
- let paragraphs: Node<any>[] = [];
+ const content = state.doc.content;
+ const paragraphs: Node<any>[] = [];
content.forEach(node => node.type.name === "paragraph" && paragraphs.push(node));
// Functions to flatten ProseMirror paragraph objects (and their components) to plain text
// Concatentate paragraphs and string the result together
- let textParagraphs: string[] = paragraphs.map(paragraph => {
- let text: string[] = [];
+ const textParagraphs: string[] = paragraphs.map(paragraph => {
+ const text: string[] = [];
paragraph.content.forEach(node => node.text && text.push(node.text));
return text.join(joiner) + delimiter;
});
- let plainText = textParagraphs.join(joiner);
+ const plainText = textParagraphs.join(joiner);
return plainText.substring(0, plainText.length - 1);
};
export const ToProsemirrorState = (plainText: string, oldState?: RichTextField) => {
// Remap the text, creating blocks split on newlines
- let elements = plainText.split(delimiter);
+ const elements = plainText.split(delimiter);
// Google Docs adds in an extra carriage return automatically, so this counteracts it
!elements[elements.length - 1].length && elements.pop();
// Preserve the current state, but re-write the content to be the blocks
- let parsed = JSON.parse(oldState ? oldState.Data : Initialize());
+ const parsed = JSON.parse(oldState ? oldState.Data : Initialize());
parsed.doc.content = elements.map(text => {
- let paragraph: any = { type: "paragraph" };
+ const paragraph: any = { type: "paragraph" };
text.length && (paragraph.content = [{ type: "text", marks: [], text }]); // An empty paragraph gets treated as a line break
return paragraph;
});
@@ -98,7 +97,7 @@ export namespace RichTextUtils {
export const Export = async (state: EditorState): Promise<GoogleApiClientUtils.Docs.Content> => {
const nodes: (Node<any> | null)[] = [];
- let text = ToPlainText(state);
+ const text = ToPlainText(state);
state.doc.content.forEach(node => {
if (!node.childCount) {
nodes.push(null);
@@ -129,7 +128,7 @@ export namespace RichTextUtils {
return { baseUrl, filename };
});
- const uploads = await Identified.PostToServer(RouteStore.googlePhotosMediaDownload, { mediaItems });
+ const uploads = await Networking.PostToServer("/googlePhotosMediaDownload", { mediaItems });
if (uploads.length !== mediaItems.length) {
throw new AssertionError({ expected: mediaItems.length, actual: uploads.length, message: "Error with internally uploading inlineObjects!" });
@@ -169,20 +168,20 @@ export namespace RichTextUtils {
const title = document.title!;
const { text, paragraphs } = GoogleApiClientUtils.Docs.Utils.extractText(document);
let state = FormattedTextBox.blankState();
- let structured = parseLists(paragraphs);
+ const structured = parseLists(paragraphs);
let position = 3;
- let lists: ListGroup[] = [];
+ const lists: ListGroup[] = [];
const indentMap = new Map<ListGroup, BulletPosition[]>();
let globalOffset = 0;
const nodes: Node<any>[] = [];
- for (let element of structured) {
+ for (const element of structured) {
if (Array.isArray(element)) {
lists.push(element);
- let positions: BulletPosition[] = [];
- let items = element.map(paragraph => {
- let item = listItem(state.schema, paragraph.contents);
- let sinks = paragraph.bullet!;
+ const positions: BulletPosition[] = [];
+ const items = element.map(paragraph => {
+ const item = listItem(state.schema, paragraph.contents);
+ const sinks = paragraph.bullet!;
positions.push({
value: position + globalOffset,
sinks
@@ -209,7 +208,7 @@ export namespace RichTextUtils {
}
});
} else {
- let paragraph = paragraphNode(state.schema, element.contents);
+ const paragraph = paragraphNode(state.schema, element.contents);
nodes.push(paragraph);
position += paragraph.nodeSize;
}
@@ -217,11 +216,11 @@ export namespace RichTextUtils {
}
state = state.apply(state.tr.replaceWith(0, 2, nodes));
- let sink = sinkListItem(state.schema.nodes.list_item);
- let dispatcher = (tr: Transaction) => state = state.apply(tr);
- for (let list of lists) {
- for (let pos of indentMap.get(list)!) {
- let resolved = state.doc.resolve(pos.value);
+ const sink = sinkListItem(state.schema.nodes.list_item);
+ const dispatcher = (tr: Transaction) => state = state.apply(tr);
+ for (const list of lists) {
+ for (const pos of indentMap.get(list)!) {
+ const resolved = state.doc.resolve(pos.value);
state = state.apply(state.tr.setSelection(new TextSelection(resolved)));
for (let i = 0; i < pos.sinks; i++) {
sink(state, dispatcher);
@@ -237,9 +236,9 @@ export namespace RichTextUtils {
type PreparedParagraphs = (ListGroup | Paragraph)[];
const parseLists = (paragraphs: ListGroup) => {
- let groups: PreparedParagraphs = [];
+ const groups: PreparedParagraphs = [];
let group: ListGroup = [];
- for (let paragraph of paragraphs) {
+ for (const paragraph of paragraphs) {
if (paragraph.bullet !== undefined) {
group.push(paragraph);
} else {
@@ -263,8 +262,8 @@ export namespace RichTextUtils {
};
const paragraphNode = (schema: any, runs: docs_v1.Schema$TextRun[]): Node => {
- let children = runs.map(run => textNode(schema, run)).filter(child => child !== undefined);
- let fragment = children.length ? Fragment.from(children) : undefined;
+ const children = runs.map(run => textNode(schema, run)).filter(child => child !== undefined);
+ const fragment = children.length ? Fragment.from(children) : undefined;
return schema.node("paragraph", null, fragment);
};
@@ -274,8 +273,8 @@ export namespace RichTextUtils {
const guid = Utils.GenerateDeterministicGuid(src);
const backingDocId = StrCast(textNote[guid]);
if (!backingDocId) {
- const backingDoc = Docs.Create.ImageDocument(src, { width: 300, height: 300 });
- DocumentView.makeCustomViewClicked(backingDoc, undefined);
+ const backingDoc = Docs.Create.ImageDocument(src, { _width: 300, _height: 300 });
+ DocumentView.makeCustomViewClicked(backingDoc, undefined, Docs.Create.FreeformDocument);
docid = backingDoc[Id];
textNote[guid] = docid;
} else {
@@ -285,7 +284,7 @@ export namespace RichTextUtils {
};
const textNode = (schema: any, run: docs_v1.Schema$TextRun) => {
- let text = run.content!.removeTrailingNewlines();
+ const text = run.content!.removeTrailingNewlines();
return text.length ? schema.text(text, styleToMarks(schema, run.textStyle)) : undefined;
};
@@ -300,17 +299,17 @@ export namespace RichTextUtils {
if (!textStyle) {
return undefined;
}
- let marks: Mark[] = [];
+ const marks: Mark[] = [];
Object.keys(textStyle).forEach(key => {
let value: any;
- let targeted = key as keyof docs_v1.Schema$TextStyle;
+ const targeted = key as keyof docs_v1.Schema$TextStyle;
if (value = textStyle[targeted]) {
- let attributes: any = {};
+ const attributes: any = {};
let converted = StyleToMark.get(targeted) || targeted;
value.url && (attributes.href = value.url);
if (value.color) {
- let object = value.color.rgbColor;
+ const object = value.color.rgbColor;
attributes.color = Color.rgb(["red", "green", "blue"].map(color => object[color] * 255 || 0)).hex();
}
if (value.magnitude) {
@@ -321,13 +320,13 @@ export namespace RichTextUtils {
converted = ImportFontFamilyMapping.get(value.fontFamily) || "timesNewRoman";
}
- let mapped = schema.marks[converted];
+ const mapped = schema.marks[converted];
if (!mapped) {
alert(`No mapping found for ${converted}!`);
return;
}
- let mark = schema.mark(mapped, attributes);
+ const mark = schema.mark(mapped, attributes);
mark && marks.push(mark);
}
});
@@ -367,9 +366,9 @@ export namespace RichTextUtils {
const ignored = ["user_mark"];
const marksToStyle = async (nodes: (Node<any> | null)[]): Promise<docs_v1.Schema$Request[]> => {
- let requests: docs_v1.Schema$Request[] = [];
+ const requests: docs_v1.Schema$Request[] = [];
let position = 1;
- for (let node of nodes) {
+ for (const node of nodes) {
if (node === null) {
position += 2;
continue;
@@ -383,7 +382,7 @@ export namespace RichTextUtils {
};
let mark: Mark<any>;
const markMap = BuildMarkMap(marks);
- for (let markName of Object.keys(schema.marks)) {
+ for (const markName of Object.keys(schema.marks)) {
if (ignored.includes(markName) || !(mark = markMap[markName])) {
continue;
}
@@ -404,7 +403,7 @@ export namespace RichTextUtils {
let exported = (await Cast(linkDoc.anchor2, Doc))!;
if (!exported.customLayout) {
exported = Doc.MakeAlias(exported);
- DocumentView.makeCustomViewClicked(exported, undefined);
+ DocumentView.makeCustomViewClicked(exported, undefined, Docs.Create.FreeformDocument);
linkDoc.anchor2 = exported;
}
url = Utils.shareUrl(exported[Id]);
diff --git a/src/new_fields/Schema.ts b/src/new_fields/Schema.ts
index b1a449e08..3f0ff4284 100644
--- a/src/new_fields/Schema.ts
+++ b/src/new_fields/Schema.ts
@@ -23,7 +23,7 @@ export type makeInterface<T extends Interface[]> = AllToInterface<T> & Doc & { p
// export function makeInterface<T extends Interface[], U extends Doc>(schemas: T): (doc: U) => All<T, U>;
// export function makeInterface<T extends Interface, U extends Doc>(schema: T): (doc: U) => makeInterface<T, U>;
export function makeInterface<T extends Interface[]>(...schemas: T): InterfaceFunc<T> {
- let schema: Interface = {};
+ const schema: Interface = {};
for (const s of schemas) {
for (const key in s) {
schema[key] = s[key];
diff --git a/src/new_fields/SchemaHeaderField.ts b/src/new_fields/SchemaHeaderField.ts
index 42a8485ac..07c90f5a2 100644
--- a/src/new_fields/SchemaHeaderField.ts
+++ b/src/new_fields/SchemaHeaderField.ts
@@ -1,7 +1,7 @@
import { Deserializable } from "../client/util/SerializationHelper";
import { serializable, primitive } from "serializr";
import { ObjectField } from "./ObjectField";
-import { Copy, ToScriptString, OnUpdate } from "./FieldSymbols";
+import { Copy, ToScriptString, ToString, OnUpdate } from "./FieldSymbols";
import { scriptingGlobal } from "../client/util/Scripting";
import { ColumnType } from "../client/views/collections/CollectionSchemaView";
@@ -116,4 +116,7 @@ export class SchemaHeaderField extends ObjectField {
[ToScriptString]() {
return `invalid`;
}
+ [ToString]() {
+ return `SchemaHeaderField`;
+ }
} \ No newline at end of file
diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts
index cdc9871a8..f8a8d1226 100644
--- a/src/new_fields/ScriptField.ts
+++ b/src/new_fields/ScriptField.ts
@@ -1,9 +1,9 @@
import { ObjectField } from "./ObjectField";
import { CompiledScript, CompileScript, scriptingGlobal, ScriptOptions } from "../client/util/Scripting";
-import { Copy, ToScriptString, Parent, SelfProxy } from "./FieldSymbols";
+import { Copy, ToScriptString, ToString, Parent, SelfProxy } from "./FieldSymbols";
import { serializable, createSimpleSchema, map, primitive, object, deserialize, PropSchema, custom, SKIP } from "serializr";
import { Deserializable, autoObject } from "../client/util/SerializationHelper";
-import { Doc } from "../new_fields/Doc";
+import { Doc, Field } from "../new_fields/Doc";
import { Plugins } from "./util";
import { computedFn } from "mobx-utils";
import { ProxyField } from "./Proxy";
@@ -101,22 +101,26 @@ export class ScriptField extends ObjectField {
[ToScriptString]() {
return "script field";
}
- public static CompileScript(script: string, params: object = {}, addReturn = false) {
- let compiled = CompileScript(script, {
- params: { this: Doc.name, ...params },
+ [ToString]() {
+ return "script field";
+ }
+ public static CompileScript(script: string, params: object = {}, addReturn = false, capturedVariables?: { [name: string]: Field }) {
+ const compiled = CompileScript(script, {
+ params: { this: Doc.name, _last_: "any", ...params },
typecheck: false,
editable: true,
- addReturn: addReturn
+ addReturn: addReturn,
+ capturedVariables
});
return compiled;
}
public static MakeFunction(script: string, params: object = {}) {
- let compiled = ScriptField.CompileScript(script, params, true);
+ const compiled = ScriptField.CompileScript(script, params, true);
return compiled.compiled ? new ScriptField(compiled) : undefined;
}
public static MakeScript(script: string, params: object = {}) {
- let compiled = ScriptField.CompileScript(script, params, false);
+ const compiled = ScriptField.CompileScript(script, params, false);
return compiled.compiled ? new ScriptField(compiled) : undefined;
}
}
@@ -124,14 +128,15 @@ export class ScriptField extends ObjectField {
@scriptingGlobal
@Deserializable("computed", deserializeScript)
export class ComputedField extends ScriptField {
+ _lastComputedResult: any;
//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 = computedFn((doc: Doc) => this.script.run({ this: doc }, console.log).result);
- public static MakeScript(script: string, params: object = {}, ) {
- let compiled = ScriptField.CompileScript(script, params, false);
+ value = computedFn((doc: Doc) => this._lastComputedResult = this.script.run({ this: doc, _last_: this._lastComputedResult }, console.log).result);
+ public static MakeScript(script: string, params: object = {}) {
+ const compiled = ScriptField.CompileScript(script, params, false);
return compiled.compiled ? new ComputedField(compiled) : undefined;
}
- public static MakeFunction(script: string, params: object = {}) {
- let compiled = ScriptField.CompileScript(script, params, true);
+ public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Field }) {
+ const compiled = ScriptField.CompileScript(script, params, true, capturedVariables);
return compiled.compiled ? new ComputedField(compiled) : undefined;
}
}
diff --git a/src/new_fields/URLField.ts b/src/new_fields/URLField.ts
index 35ef6dd02..cfab36906 100644
--- a/src/new_fields/URLField.ts
+++ b/src/new_fields/URLField.ts
@@ -1,7 +1,7 @@
import { Deserializable } from "../client/util/SerializationHelper";
import { serializable, custom } from "serializr";
import { ObjectField } from "./ObjectField";
-import { ToScriptString, Copy } from "./FieldSymbols";
+import { ToScriptString, ToString, Copy } from "./FieldSymbols";
import { Scripting, scriptingGlobal } from "../client/util/Scripting";
function url() {
@@ -32,6 +32,9 @@ export abstract class URLField extends ObjectField {
[ToScriptString]() {
return `new ${this.constructor.name}("${this.url.href}")`;
}
+ [ToString]() {
+ return this.url.href;
+ }
[Copy](): this {
return new (this.constructor as any)(this.url);
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index fa47374f1..4a5c1fdb0 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -4,29 +4,36 @@ import { Doc } from "./Doc";
import { DateField } from "./DateField";
export const documentSchema = createSchema({
- layout: "string", // this is the native layout string for the document. templates can be added using other fields and setting layoutKey below (see layoutCustom as an example)
+ layout: "string", // this is the native layout string for the document. templates can be added using other fields and setting layoutKey below (see layout_custom as an example)
layoutKey: "string", // holds the field key for the field that actually holds the current lyoat
- layoutCustom: Doc, // used to hold a custom layout (there's nothing special about this field .. any field could hold a custom layout that can be selected by setting 'layoutKey')
+ layout_custom: Doc, // used to hold a custom layout (there's nothing special about this field .. any field could hold a custom layout that can be selected by setting 'layoutKey')
title: "string", // document title (can be on either data document or layout)
- nativeWidth: "number", // native width of document which determines how much document contents are scaled when the document's width is set
- nativeHeight: "number", // "
- width: "number", // width of document in its container's coordinate system
- height: "number", // "
+ _dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias" or "copy")
+ _nativeWidth: "number", // native width of document which determines how much document contents are scaled when the document's width is set
+ _nativeHeight: "number", // "
+ _width: "number", // width of document in its container's coordinate system
+ _height: "number", // "
+ _freeformLayoutEngine: "string",// the string ID for the layout engine to use to layout freeform view documents
+ _LODdisable: "boolean", // whether to disbale LOD switching for CollectionFreeFormViews
color: "string", // foreground color of document
backgroundColor: "string", // background color of document
opacity: "number", // opacity of document
creationDate: DateField, // when the document was created
links: listSpec(Doc), // computed (readonly) list of links associated with this document
- dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias" or "copy")
removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped
onClick: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop)
+ onPointerDown: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop)
+ onPointerUp: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop)
onDragStart: ScriptField, // script to run when document is dragged (without being selected). the script should return the Doc to be dropped.
dragFactory: Doc, // the document that serves as the "template" for the onDragStart script. ie, to drag out copies of the dragFactory document.
ignoreAspect: "boolean", // whether aspect ratio should be ignored when laying out or manipulating the document
autoHeight: "boolean", // whether the height of the document should be computed automatically based on its contents
- isTemplateField: "boolean", // whether this document acts as a template layout for describing how other documents should be displayed
+ isTemplateForField: "string",// when specifies a field key, then the containing document is a template that renders the specified field
isBackground: "boolean", // whether document is a background element and ignores input events (can only selet with marquee)
type: "string", // enumerated type of document
+ treeViewOpen: "boolean", // flag denoting whether the documents sub-tree (contents) is visible or hidden
+ treeViewExpandedView: "string", // name of field whose contents are being displayed as the document's subtree
+ preventTreeViewOpen: "boolean", // ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document)
currentTimecode: "number", // current play back time of a temporal document (video / audio)
summarizedDocs: listSpec(Doc), // documents that are summarized by this document (and which will typically be opened by clicking this document)
maximizedDocs: listSpec(Doc), // documents to maximize when clicking this document (generally this document will be an icon)
@@ -38,12 +45,21 @@ export const documentSchema = createSchema({
searchFields: "string", // the search fields to display when this document matches a search in its metadata
heading: "number", // the logical layout 'heading' of this document (used by rule provider to stylize h1 header elements, from h2, etc)
showCaption: "string", // whether editable caption text is overlayed at the bottom of the document
- showTitle: "string", // whether an editable title banner is displayed at tht top of the document
+ showTitle: "string", // the fieldkey whose contents should be displayed at the top of the document
+ showTitleHover: "string", // the showTitle should be shown only on hover
isButton: "boolean", // whether document functions as a button (overiding native interactions of its content)
ignoreClick: "boolean", // whether documents ignores input clicks (but does not ignore manipulation and other events)
- isAnimating: "boolean", // whether the document is in the midst of animating between two layouts (used by icons to de/iconify documents).
+ isAnimating: "string", // whether the document is in the midst of animating between two layouts (used by icons to de/iconify documents). value is undefined|"min"|"max"
animateToDimensions: listSpec("number"), // layout information about the target rectangle a document is animating towards
scrollToLinkID: "string", // id of link being traversed. allows this doc to scroll/highlight/etc its link anchor. scrollToLinkID should be set to undefined by this doc after it sets up its scroll,etc.
+ strokeWidth: "number",
+ fontSize: "string",
+ fitToBox: "boolean", // whether freeform view contents should be zoomed/panned to fill the area of the document view
+ xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set
+ yPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set
+ LODarea: "number", // area (width*height) where CollectionFreeFormViews switch from a label to rendering contents
+ letterSpacing: "string",
+ textTransform: "string"
});
export const positionSchema = createSchema({
@@ -53,6 +69,13 @@ export const positionSchema = createSchema({
z: "number",
});
+export const collectionSchema = createSchema({
+ childLayout: Doc, // layout template for children of a collecion
+ childDetailed: Doc, // layout template to apply to a child when its clicked on in a collection and opened (requires onChildClick or other script to use this field)
+ onChildClick: ScriptField, // script to run for each child when its clicked
+ onCheckedClick: ScriptField, // script to run when a checkbox is clicked next to a child in a tree view
+});
+
export type Document = makeInterface<[typeof documentSchema]>;
export const Document = makeInterface(documentSchema);
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 04194509c..2cedda7a6 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -1,17 +1,22 @@
import { UndoManager } from "../client/util/UndoManager";
import { Doc, Field, FieldResult, UpdatingFromServer } from "./Doc";
import { SerializationHelper } from "../client/util/SerializationHelper";
-import { ProxyField } from "./Proxy";
+import { ProxyField, PrefetchProxy } from "./Proxy";
import { RefField } from "./RefField";
import { ObjectField } from "./ObjectField";
-import { action } from "mobx";
+import { action, trace } from "mobx";
import { Parent, OnUpdate, Update, Id, SelfProxy, Self } from "./FieldSymbols";
import { DocServer } from "../client/DocServer";
+import { props } from "bluebird";
function _readOnlySetter(): never {
throw new Error("Documents can't be modified in read-only mode");
}
+export function TraceMobx() {
+ //trace();
+}
+
export interface GetterResult {
value: FieldResult;
shouldReturn?: boolean;
@@ -31,6 +36,7 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
target[prop] = value;
return true;
}
+
if (typeof prop === "symbol") {
target[prop] = value;
return true;
@@ -48,7 +54,7 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
value = new ProxyField(value);
}
if (value instanceof ObjectField) {
- if (value[Parent] && value[Parent] !== receiver) {
+ if (value[Parent] && value[Parent] !== receiver && !(value instanceof PrefetchProxy)) {
throw new Error("Can't put the same object in multiple documents at the same time");
}
value[Parent] = receiver;
@@ -94,11 +100,38 @@ export function makeEditable() {
_setter = _setterImpl;
}
-export function setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean {
+let layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "fitWidth", "fitToBox",
+ "LODdisable", "dropAction", "chromeStatus", "viewType", "gridGap", "xMargin", "yMargin", "autoHeight"];
+export function setter(target: any, in_prop: string | symbol | number, value: any, receiver: any): boolean {
+ let prop = in_prop;
+ if (typeof prop === "string" && prop !== "__id" && prop !== "__fields" &&
+ ((prop as string).startsWith("_") || layoutProps.includes(prop))) {
+ if (!prop.startsWith("_")) {
+ console.log(prop + " is deprecated - switch to _" + prop);
+ prop = "_" + prop;
+ }
+ const resolvedLayout = getFieldImpl(target, getFieldImpl(target, "layoutKey", receiver), receiver);
+ if (resolvedLayout instanceof Doc) {
+ resolvedLayout[prop] = value;
+ return true;
+ }
+ }
return _setter(target, prop, value, receiver);
}
-export function getter(target: any, prop: string | symbol | number, receiver: any): any {
+export function getter(target: any, in_prop: string | symbol | number, receiver: any): any {
+ let prop = in_prop;
+ if (typeof prop === "string" && prop !== "__id" && prop !== "__fields" &&
+ ((prop as string).startsWith("_") || layoutProps.includes(prop))) {
+ if (!prop.startsWith("_")) {
+ console.log(prop + " is deprecated - switch to _" + prop);
+ prop = "_" + prop;
+ }
+ const resolvedLayout = getFieldImpl(target, getFieldImpl(target, "layoutKey", receiver), receiver);
+ if (resolvedLayout instanceof Doc) {
+ return resolvedLayout[prop];
+ }
+ }
if (prop === "then") {//If we're being awaited
return undefined;
}