aboutsummaryrefslogtreecommitdiff
path: root/src/new_fields/Doc.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/new_fields/Doc.ts')
-rw-r--r--src/new_fields/Doc.ts103
1 files changed, 77 insertions, 26 deletions
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 4fe52fd30..921891799 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -6,7 +6,7 @@ import { DocumentType } from "../client/documents/DocumentTypes";
import { Scripting, scriptingGlobal } from "../client/util/Scripting";
import { afterDocDeserialize, autoObject, Deserializable, SerializationHelper } from "../client/util/SerializationHelper";
import { UndoManager } from "../client/util/UndoManager";
-import { intersectRect } from "../Utils";
+import { intersectRect, Utils } from "../Utils";
import { HandleUpdate, Id, OnUpdate, Parent, Self, SelfProxy, ToScriptString, ToString, Update, Copy } from "./FieldSymbols";
import { List } from "./List";
import { ObjectField } from "./ObjectField";
@@ -19,6 +19,7 @@ import { Cast, FieldValue, NumCast, StrCast, ToConstructor, ScriptCast } from ".
import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util";
import { Docs, DocumentOptions } from "../client/documents/Documents";
import { PdfField, VideoField, AudioField, ImageField } from "./URLField";
+import { LinkManager } from "../client/util/LinkManager";
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
@@ -183,7 +184,7 @@ export class Doc extends RefField {
let renderFieldKey: any;
const layoutField = templateLayoutDoc[StrCast(templateLayoutDoc.layoutKey, "layout")];
if (typeof layoutField === "string") {
- renderFieldKey = layoutField.split("'")[1];
+ renderFieldKey = layoutField.split("fieldKey={'")[1].split("'")[0];//layoutField.split("'")[1];
} else {
return Cast(layoutField, Doc, null);
}
@@ -292,6 +293,9 @@ export namespace Doc {
export function IsPrototype(doc: Doc) {
return GetT(doc, "isPrototype", "boolean", true);
}
+ export function IsBaseProto(doc: Doc) {
+ return GetT(doc, "baseProto", "boolean", true);
+ }
export async function SetInPlace(doc: Doc, key: string, value: Field | undefined, defaultProto: boolean) {
const hasProto = doc.proto instanceof Doc;
const onDeleg = Object.getOwnPropertyNames(doc).indexOf(key) !== -1;
@@ -463,6 +467,7 @@ export namespace Doc {
return (layoutDoc.isTemplateForField || layoutDoc.isTemplateDoc) && dataDoc && layoutDoc !== dataDoc;
}
+ const _pendingMap: Map<string, boolean> = new Map();
//
// 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
@@ -488,13 +493,16 @@ export namespace Doc {
const layoutFielddKey = Doc.LayoutFieldKey(templateLayoutDoc);
const expandedLayoutFieldKey = (templateField || layoutFielddKey) + "-layout[" + templateLayoutDoc[Id] + (args ? `(${args})` : "") + "]";
let expandedTemplateLayout = targetDoc?.[expandedLayoutFieldKey];
+
if (templateLayoutDoc.resolvedDataDoc instanceof Promise) {
expandedTemplateLayout = undefined;
+ _pendingMap.set(targetDoc[Id] + expandedLayoutFieldKey, true);
}
- else if (expandedTemplateLayout === undefined) {
- if (templateLayoutDoc.resolvedDataDoc === Doc.GetProto(targetDoc) && templateLayoutDoc.PARAMS === StrCast(targetDoc.PARAMS)) {
+ else if (expandedTemplateLayout === undefined && !_pendingMap.get(targetDoc[Id] + expandedLayoutFieldKey + args)) {
+ if (templateLayoutDoc.resolvedDataDoc === (targetDoc.rootDocument || Doc.GetProto(targetDoc)) && templateLayoutDoc.PARAMS === StrCast(targetDoc.PARAMS)) {
expandedTemplateLayout = templateLayoutDoc; // reuse an existing template layout if its for the same document with the same params
} else {
+ _pendingMap.set(targetDoc[Id] + expandedLayoutFieldKey + args, true);
templateLayoutDoc.resolvedDataDoc && (templateLayoutDoc = Cast(templateLayoutDoc.proto, Doc, null) || templateLayoutDoc); // if the template has already been applied (ie, a nested template), then use the template's prototype
setTimeout(action(() => {
if (!targetDoc[expandedLayoutFieldKey]) {
@@ -509,6 +517,7 @@ export namespace Doc {
if (dataDoc[templateField] === undefined && templateLayoutDoc[templateField] instanceof List) {
dataDoc[templateField] = ComputedField.MakeFunction(`ObjectField.MakeCopy(templateLayoutDoc["${templateField}"] as List)`, { templateLayoutDoc: Doc.name }, { templateLayoutDoc });
}
+ _pendingMap.delete(targetDoc[Id] + expandedLayoutFieldKey + args);
}
}), 0);
}
@@ -581,32 +590,64 @@ export namespace Doc {
return copy;
}
- export function MakeClone(doc: Doc, cloneProto: boolean = true): Doc {
+ export function MakeClone(doc: Doc): Doc {
+ const cloneMap = new Map<string, Doc>();
+ const rtfMap: { copy: Doc, key: string, field: RichTextField }[] = [];
+ const copy = Doc.makeClone(doc, cloneMap, rtfMap);
+ rtfMap.map(({ copy, key, field }) => {
+ const replacer = (match: any, attr: string, id: string, offset: any, string: any) => {
+ const mapped = cloneMap.get(id);
+ return attr + "\"" + (mapped ? mapped[Id] : id) + "\"";
+ };
+ const replacer2 = (match: any, href: string, id: string, offset: any, string: any) => {
+ const mapped = cloneMap.get(id);
+ return href + (mapped ? mapped[Id] : id);
+ };
+ const regex = `(${Utils.prepend("/doc/")})([^"]*)`;
+ const re = new RegExp(regex, "g");
+ copy[key] = new RichTextField(field.Data.replace(/("docid":|"targetId":|"linkId":)"([^"]+)"/g, replacer).replace(re, replacer2), field.Text);
+ });
+ return copy;
+ }
+
+ export function makeClone(doc: Doc, cloneMap: Map<string, Doc>, rtfs: { copy: Doc, key: string, field: RichTextField }[]): Doc {
+ if (Doc.IsBaseProto(doc)) return doc;
+ if (cloneMap.get(doc[Id])) return cloneMap.get(doc[Id])!;
const copy = new Doc(undefined, true);
+ cloneMap.set(doc[Id], copy);
+ if (LinkManager.Instance.getAllLinks().includes(doc) && LinkManager.Instance.getAllLinks().indexOf(copy) === -1) LinkManager.Instance.addLink(copy);
const exclude = Cast(doc.excludeFields, listSpec("string"), []);
Object.keys(doc).forEach(key => {
if (exclude.includes(key)) return;
const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
const field = ProxyField.WithoutProxy(() => doc[key]);
- if (key === "proto" && cloneProto) {
+ const copyObjectField = (field: ObjectField) => {
+ const list = Cast(doc[key], listSpec(Doc));
+ if (list !== undefined && !(list instanceof Promise)) {
+ copy[key] = new List<Doc>(list.filter(d => d instanceof Doc).map(d => Doc.makeClone(d as Doc, cloneMap, rtfs)));
+ } else if (doc[key] instanceof Doc) {
+ copy[key] = key.includes("layout[") ? undefined : Doc.makeClone(doc[key] as Doc, cloneMap, rtfs); // reference documents except copy documents that are expanded teplate fields
+ } else {
+ copy[key] = ObjectField.MakeCopy(field);
+ if (field instanceof RichTextField) {
+ if (field.Data.includes('"docid":') || field.Data.includes('"targetId":') || field.Data.includes('"linkId":')) {
+ rtfs.push({ copy, key, field });
+ }
+ }
+ }
+ };
+ if (key === "proto") {
if (doc[key] instanceof Doc) {
- copy[key] = Doc.MakeClone(doc[key]!, false);
+ copy[key] = Doc.makeClone(doc[key]!, cloneMap, rtfs);
}
} else {
if (field instanceof RefField) {
copy[key] = field;
} else if (cfield instanceof ComputedField) {
copy[key] = ComputedField.MakeFunction(cfield.script.originalScript);
+ (key === "links" && field instanceof ObjectField) && copyObjectField(field);
} else if (field instanceof ObjectField) {
- const list = Cast(doc[key], listSpec(Doc));
- if (list !== undefined && !(list instanceof Promise)) {
- copy[key] = new List<Doc>(list.filter(d => d instanceof Doc).map(d => Doc.MakeCopy(d as Doc, false)));
- } else {
- copy[key] = doc[key] instanceof Doc ?
- key.includes("layout[") ?
- Doc.MakeCopy(doc[key] as Doc, false) : doc[key] : // reference documents except copy documents that are expanded teplate fields
- ObjectField.MakeCopy(field);
- }
+ copyObjectField(field);
} else if (field instanceof Promise) {
debugger; //This shouldn't happend...
} else {
@@ -616,6 +657,7 @@ export namespace Doc {
});
Doc.SetInPlace(copy, "title", "CLONE: " + doc.title, true);
copy.cloneOf = doc;
+ cloneMap.set(doc[Id], copy);
return copy;
}
@@ -772,7 +814,7 @@ export namespace Doc {
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 LinkEndpoint(linkDoc: Doc, anchorDoc: Doc) { return Doc.AreProtosEqual(anchorDoc, Cast(linkDoc.anchor1, Doc) as Doc) ? "1" : "2"; }
export function linkFollowUnhighlight() {
Doc.UnhighlightAll();
@@ -893,19 +935,28 @@ export namespace Doc {
}
}
}
-
- export function freezeNativeDimensions(layoutDoc: Doc, width: number, height: number): void {
- layoutDoc._autoHeight = false;
- if (!layoutDoc._nativeWidth) {
- layoutDoc._nativeWidth = NumCast(layoutDoc._width, width);
- layoutDoc._nativeHeight = NumCast(layoutDoc._height, height);
- }
- }
export function assignDocToField(doc: Doc, field: string, id: string) {
DocServer.GetRefField(id).then(layout => layout instanceof Doc && (doc[field] = layout));
return id;
}
+ export function toggleNativeDimensions(layoutDoc: Doc, contentScale: number, panelWidth: number, panelHeight: number) {
+ runInAction(() => {
+ if (layoutDoc._nativeWidth || layoutDoc._nativeHeight) {
+ layoutDoc.scale = NumCast(layoutDoc.scale, 1) * contentScale;
+ layoutDoc._nativeWidth = undefined;
+ layoutDoc._nativeHeight = undefined;
+ }
+ else {
+ layoutDoc._autoHeight = false;
+ if (!layoutDoc._nativeWidth) {
+ layoutDoc._nativeWidth = NumCast(layoutDoc._width, panelWidth);
+ layoutDoc._nativeHeight = NumCast(layoutDoc._height, panelHeight);
+ }
+ }
+ });
+ }
+
export function isDocPinned(doc: Doc) {
//add this new doc to props.Document
const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc;
@@ -997,7 +1048,7 @@ export namespace Doc {
//newCollection.borderRounding = "40px";
newCollection._jitterRotation = 10;
newCollection._backgroundColor = "gray";
- newCollection.overflow = "visible";
+ newCollection._overflow = "visible";
return newCollection;
}