aboutsummaryrefslogtreecommitdiff
path: root/src/fields/Doc.ts
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-09-02 09:26:37 -0400
committerbobzel <zzzman@gmail.com>2024-09-02 09:26:37 -0400
commitcda69e48361fce8d71a4dc66edd9dd976a27f52d (patch)
tree82b9a1a5967ae88a9534f89f7eaed3aeb289652f /src/fields/Doc.ts
parentc01828308714874589d1f60c33ca59df4c656c0c (diff)
parenta958577d4c27b276aa37484e3f895e196138b17c (diff)
Merge branch 'master' into alyssa-starter
Diffstat (limited to 'src/fields/Doc.ts')
-rw-r--r--src/fields/Doc.ts189
1 files changed, 100 insertions, 89 deletions
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 2792f3aba..7abba7679 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1,6 +1,3 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-/* eslint-disable @typescript-eslint/no-namespace */
-/* eslint-disable default-param-last */
/* eslint-disable no-use-before-define */
import { action, computed, makeObservable, observable, ObservableMap, ObservableSet, runInAction } from 'mobx';
import { computedFn } from 'mobx-utils';
@@ -19,7 +16,7 @@ import {
import { Copy, FieldChanged, HandleUpdate, Id, Parent, ToJavascriptString, ToScriptString, ToString } from './FieldSymbols';
import { InkTool } from './InkField';
import { List } from './List';
-import { ObjectField } from './ObjectField';
+import { ObjectField, serverOpType } from './ObjectField';
import { PrefetchProxy, ProxyField } from './Proxy';
import { FieldId, RefField } from './RefField';
import { RichTextField } from './RichTextField';
@@ -28,6 +25,15 @@ import { ComputedField, ScriptField } from './ScriptField';
import { BoolCast, Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor, toList } from './Types';
import { containedFieldChangedHandler, deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, setter, SharingPermissions } from './util';
+export let ObjGetRefField: (id: string, force?: boolean) => Promise<Doc | undefined>;
+export let ObjGetRefFields: (ids: string[]) => Promise<Map<string, Doc | undefined>>;
+
+export function SetObjGetRefField(func: (id: string, force?: boolean) => Promise<Doc | undefined>) {
+ ObjGetRefField = func;
+}
+export function SetObjGetRefFields(func: (ids: string[]) => Promise<Map<string, Doc | undefined>>) {
+ ObjGetRefFields = func;
+}
export const LinkedTo = '-linkedTo';
export namespace Field {
/**
@@ -91,18 +97,19 @@ export namespace Field {
});
return script;
}
- export function toString(field: FieldType) {
+ export function toString(fieldIn: unknown) {
+ const field = fieldIn as FieldType;
if (typeof field === 'string' || typeof field === 'number' || typeof field === 'boolean') return String(field);
return field?.[ToString]?.() || '';
}
- export function IsField(field: any): field is FieldType;
- export function IsField(field: any, includeUndefined: true): field is FieldType | undefined;
- export function IsField(field: any, includeUndefined: boolean = false): field is FieldType | undefined {
+ export function IsField(field: unknown): field is FieldType;
+ export function IsField(field: unknown, includeUndefined: true): field is FieldType | undefined;
+ export function IsField(field: unknown, includeUndefined: boolean = false): field is FieldType | undefined {
return ['string', 'number', 'boolean'].includes(typeof field) || field instanceof ObjectField || field instanceof RefField || (includeUndefined && field === undefined);
}
// eslint-disable-next-line @typescript-eslint/no-shadow
- export function Copy(field: any) {
- return field instanceof ObjectField ? ObjectField.MakeCopy(field) : field;
+ export function Copy(field: unknown) {
+ return field instanceof ObjectField ? ObjectField.MakeCopy(field) : (field as FieldType);
}
UndoManager.SetFieldPrinter(toString);
}
@@ -118,9 +125,7 @@ export type FieldResult<T extends FieldType = FieldType> = Opt<T> | FieldWaiting
* If no default value is given, and the returned value is not undefined, it can be safely modified.
*/
export function DocListCastAsync(field: FieldResult): Promise<Doc[] | undefined>;
-// eslint-disable-next-line no-redeclare
export function DocListCastAsync(field: FieldResult, defaultValue: Doc[]): Promise<Doc[]>;
-// eslint-disable-next-line no-redeclare
export function DocListCastAsync(field: FieldResult, defaultValue?: Doc[]) {
const list = Cast(field, listSpec(Doc));
return list ? Promise.all(list).then(() => list) : Promise.resolve(defaultValue);
@@ -157,7 +162,7 @@ export const ReverseHierarchyMap: Map<string, { level: aclLevel; acl: symbol; im
// this recursively updates all protos as well.
export function updateCachedAcls(doc: Doc) {
if (doc) {
- const target = (doc as any)?.__fieldTuples ?? doc;
+ const target = doc[FieldTuples] ?? doc;
const permissions: { [key: string]: symbol } = !target.author || target.author === ClientUtils.CurrentUserEmail() ? { acl_Me: AclAdmin } : {};
Object.keys(target).forEach(key => {
key.startsWith('acl_') && (permissions[key] = ReverseHierarchyMap.get(StrCast(target[key]))!.acl);
@@ -177,12 +182,11 @@ export function updateCachedAcls(doc: Doc) {
}
@scriptingGlobal
-@Deserializable('Doc', updateCachedAcls, ['id'])
+@Deserializable('Doc', (obj: unknown) => updateCachedAcls(obj as Doc), ['id'])
export class Doc extends RefField {
@observable public static RecordingEvent = 0;
@observable public static GuestDashboard: Doc | undefined = undefined;
@observable public static GuestTarget: Doc | undefined = undefined;
- @observable public static GuestMobile: Doc | undefined = undefined;
@observable.shallow public static CurrentlyLoading: Doc[] = observable([]);
// DocServer api
public static FindDocByTitle(title: string) {
@@ -219,6 +223,8 @@ export class Doc extends RefField {
public static get MyUserDocView() { return DocCast(Doc.UserDoc().myUserDocView); } // prettier-ignore
public static get MyDockedBtns() { return DocCast(Doc.UserDoc().myDockedBtns); } // prettier-ignore
public static get MySearcher() { return DocCast(Doc.UserDoc().mySearcher); } // prettier-ignore
+ public static get MyImageGrouper() { return DocCast(Doc.UserDoc().myImageGrouper); } //prettier-ignore
+ public static get MyFaceCollection() { return DocCast(Doc.UserDoc().myFaceCollection); } //prettier-ignore
public static get MyHeaderBar() { return DocCast(Doc.UserDoc().myHeaderBar); } // prettier-ignore
public static get MyLeftSidebarMenu() { return DocCast(Doc.UserDoc().myLeftSidebarMenu); } // prettier-ignore
public static get MyLeftSidebarPanel() { return DocCast(Doc.UserDoc().myLeftSidebarPanel); } // prettier-ignore
@@ -252,16 +258,16 @@ export class Doc extends RefField {
public static set ActiveDashboard(val: Opt<Doc>) { Doc.UserDoc().activeDashboard = val; } // prettier-ignore
public static IsInMyOverlay(doc: Doc) { return Doc.MyOverlayDocs.includes(doc); } // prettier-ignore
- public static AddToMyOverlay(doc: Doc) { return Doc.ActiveDashboard?.myOverlayDocs ? Doc.AddDocToList(Doc.ActiveDashboard, 'myOverlayDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore
- public static RemFromMyOverlay(doc: Doc) { return Doc.ActiveDashboard?.myOverlayDocs ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myOverlayDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore
+ public static AddToMyOverlay(doc: Doc) { return Doc.ActiveDashboard ? Doc.AddDocToList(Doc.ActiveDashboard, 'myOverlayDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore
+ public static RemFromMyOverlay(doc: Doc) { return Doc.ActiveDashboard ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myOverlayDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore
public static AddToMyPublished(doc: Doc) {
doc[DocData].title_custom = true;
doc[DocData].layout_showTitle = 'title';
- Doc.ActiveDashboard?.myPublishedDocs ? Doc.AddDocToList(Doc.ActiveDashboard, 'myPublishedDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore
+ Doc.ActiveDashboard ? Doc.AddDocToList(Doc.ActiveDashboard, 'myPublishedDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore
public static RemFromMyPublished(doc: Doc){
doc[DocData].title_custom = false;
doc[DocData].layout_showTitle = undefined;
- Doc.ActiveDashboard?.myPublishedDocs ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myPublishedDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore
+ Doc.ActiveDashboard ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myPublishedDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore
public static IsComicStyle(doc?: Doc) { return doc && Doc.ActiveDashboard && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === 'comic' ; } // prettier-ignore
constructor(id?: FieldId, forceSave?: boolean) {
@@ -321,19 +327,22 @@ export class Doc extends RefField {
});
this[SelfProxy] = docProxy;
if (!id || forceSave) {
- DocServer.CreateField(docProxy);
+ DocServer.CreateDocField(docProxy);
}
// eslint-disable-next-line no-constructor-return
return docProxy; // need to return the proxy from the constructor so that all our added fields will get called
}
[key: string]: FieldResult;
+ [key2: symbol]: unknown;
@serializable(alias('fields', map(autoObject(), { afterDeserialize: afterDocDeserialize })))
- private get __fieldTuples() {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ get __fieldTuples(): any {
+ // __fieldTuples does not follow the index signature pattern which requires a FieldResult return value -- so this hack suppresses the error
return this[FieldTuples];
}
- private set __fieldTuples(value) {
+ set __fieldTuples(value) {
// called by deserializer to set all fields in one shot
this[FieldTuples] = value;
Object.keys(value).forEach(key => {
@@ -348,33 +357,33 @@ export class Doc extends RefField {
});
}
- @observable private [FieldTuples]: any = {};
- @observable private [FieldKeys]: any = {};
+ @observable private [FieldTuples]: { [key: string]: FieldResult } = {};
+ @observable private [FieldKeys]: { [key: string]: boolean } = {};
/// all of the raw acl's that have been set on this document. Use GetEffectiveAcl to determine the actual ACL of the doc for editing
@observable public [DocAcl]: { [key: string]: symbol } = {};
@observable public [DocCss]: number = 0; // incrementer denoting a change to CSS layout
@observable public [DirectLinks] = new ObservableSet<Doc>();
- @observable public [AudioPlay]: any = undefined; // meant to store sound object from Howl
+ @observable public [AudioPlay]: unknown = undefined; // meant to store sound object from Howl
@observable public [Animation]: Opt<Doc> = undefined;
@observable public [Highlight]: boolean = false;
@observable public [Brushed]: boolean = false;
- @observable public [DocViews] = new ObservableSet<any /* DocumentView */>();
+ @observable public [DocViews] = new ObservableSet<unknown /* DocumentView */>();
private [Self] = this;
- private [SelfProxy]: any;
+ private [SelfProxy]: Doc;
private [UpdatingFromServer]: boolean = false;
private [ForceServerWrite]: boolean = false;
- private [CachedUpdates]: { [key: string]: () => void | Promise<any> } = {};
+ private [CachedUpdates]: { [key: string]: () => void | Promise<void> } = {};
public [Initializing]: boolean = false;
- public [FieldChanged] = (diff: undefined | { op: '$addToSet' | '$remFromSet' | '$set'; items: FieldType[] | undefined; length: number | undefined; hint?: any }, serverOp: any) => {
+ public [FieldChanged] = (diff: { op: '$addToSet' | '$remFromSet' | '$set'; items: FieldType[] | undefined; length: number | undefined; hint?: { start: number; deleteCount: number } } | undefined, serverOp: serverOpType) => {
if (!this[UpdatingFromServer] || this[ForceServerWrite]) {
DocServer.UpdateField(this[Id], serverOp);
}
};
public [Width] = () => NumCast(this[SelfProxy]._width);
public [Height] = () => NumCast(this[SelfProxy]._height);
- public [TransitionTimer]: any = undefined;
+ public [TransitionTimer]: NodeJS.Timeout | undefined = undefined;
public [ToJavascriptString] = () => `idToDoc("${this[Self][Id]}")`; // what should go here?
public [ToScriptString] = () => `idToDoc("${this[Self][Id]}")`;
public [ToString] = () => `Doc(${GetEffectiveAcl(this[SelfProxy]) === AclPrivate ? '-inaccessible-' : this[SelfProxy].title})`;
@@ -387,7 +396,7 @@ export class Doc extends RefField {
const self = this[SelfProxy];
const templateLayoutDoc = Cast(Doc.LayoutField(self), Doc, null);
if (templateLayoutDoc) {
- let renderFieldKey: any;
+ let renderFieldKey: string = '';
const layoutField = templateLayoutDoc[StrCast(templateLayoutDoc.layout_fieldKey, 'layout')];
if (typeof layoutField === 'string') {
[renderFieldKey] = layoutField.split("fieldKey={'")[1].split("'"); // layoutField.split("'")[1];
@@ -399,16 +408,17 @@ export class Doc extends RefField {
return undefined;
}
- public async [HandleUpdate](diff: any) {
- const set = diff.$set;
+ public async [HandleUpdate](diff: { $set: { [key: string]: FieldType } } | { $unset?: unknown }) {
+ const $set = '$set' in diff ? diff.$set : undefined;
+ const $unset = '$unset' in diff ? diff.$unset : undefined;
const sameAuthor = this.author === ClientUtils.CurrentUserEmail();
const fprefix = 'fields.';
- Object.keys(set ?? {})
+ Object.keys($set ?? {})
.filter(key => key.startsWith(fprefix))
.forEach(async key => {
const fKey = key.substring(fprefix.length);
const fn = async () => {
- const value = await SerializationHelper.Deserialize(set[key]);
+ const value = (await SerializationHelper.Deserialize($set?.[key])) as FieldType;
const prev = GetEffectiveAcl(this);
this[UpdatingFromServer] = true;
this[fKey] = value;
@@ -423,14 +433,12 @@ export class Doc extends RefField {
const writeMode = DocServer.getFieldWriteMode(fKey);
if (fKey.startsWith('acl_') || writeMode !== DocServer.WriteMode.Playground) {
delete this[CachedUpdates][fKey];
- // eslint-disable-next-line no-await-in-loop
await fn();
} else {
this[CachedUpdates][fKey] = fn;
}
});
- const unset = diff.$unset;
- Object.keys(unset ?? {})
+ Object.keys($unset ?? {})
.filter(key => key.startsWith(fprefix))
.forEach(async key => {
const fKey = key.substring(7);
@@ -451,12 +459,10 @@ export class Doc extends RefField {
// eslint-disable-next-line no-redeclare
export namespace Doc {
- // eslint-disable-next-line import/no-mutable-exports
export let SelectOnLoad: Doc | undefined;
export function SetSelectOnLoad(doc: Doc | undefined) {
SelectOnLoad = doc;
}
- // eslint-disable-next-line import/no-mutable-exports
export let DocDragDataName: string = '';
export function SetDocDragDataName(name: string) {
DocDragDataName = name;
@@ -474,7 +480,7 @@ export namespace Doc {
delete doc[CachedUpdates][field];
}
}
- export function AddCachedUpdate(doc: Doc, field: string, oldValue: any) {
+ export function AddCachedUpdate(doc: Doc, field: string, oldValue: FieldType) {
const val = oldValue;
doc[CachedUpdates][field] = () => {
doc[UpdatingFromServer] = true;
@@ -493,7 +499,7 @@ export namespace Doc {
export function Get(doc: Doc, key: string, ignoreProto: boolean = false): FieldResult {
try {
- return getField(doc[Self], key, ignoreProto);
+ return getField(doc[Self], key, ignoreProto) as FieldResult;
} catch {
return doc;
}
@@ -558,9 +564,12 @@ export namespace Doc {
export function assign<K extends string>(doc: Doc, fields: Partial<Record<K, Opt<FieldType>>>, skipUndefineds: boolean = false, isInitializing = false) {
isInitializing && (doc[Initializing] = true);
Object.keys(fields).forEach(key => {
- const value = (fields as any)[key];
+ const value = (fields as { [key: string]: Opt<FieldType> })[key];
if (!skipUndefineds || value !== undefined) {
// Do we want to filter out undefineds?
+ if (typeof value === 'object' && 'values' in value) {
+ console.log(value);
+ }
doc[key] = value;
}
});
@@ -712,7 +721,7 @@ export namespace Doc {
await Promise.all(
Object.keys(doc).map(async key => {
if (filter.includes(key)) return;
- const assignKey = (val: any) => {
+ const assignKey = (val: Opt<FieldType>) => {
copy[key] = val;
};
const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
@@ -735,7 +744,7 @@ export namespace Doc {
.trim()
);
const results = docids && (await DocServer.GetRefFields(docids));
- const rdocs = results && Array.from(Object.keys(results)).map(rkey => DocCast(results[rkey]));
+ const rdocs = results && Array.from(Object.keys(results)).map(rkey => DocCast(results.get(rkey)));
rdocs?.map(d => d && Doc.makeClone(d, cloneMap, linkMap, rtfs, exclusions, pruneDocs, cloneLinks, cloneTemplates));
rtfs.push({ copy, key, field: objField });
}
@@ -782,9 +791,9 @@ export namespace Doc {
linkMap.set(link[Id], await Doc.makeClone(link, cloneMap, linkMap, rtfs, exclusions, pruneDocs, cloneLinks, cloneTemplates));
}
});
- if (Doc.Get(copy, 'title', true)) copy.title = '>:' + doc.title;
- // Doc.SetInPlace(copy, 'title', '>:' + doc.title, true);
copy.cloneOf = doc;
+ const cfield = ComputedField.WithoutComputed(() => FieldValue(doc.title));
+ if (Doc.Get(copy, 'title', true) && !(cfield instanceof ComputedField)) copy.title = '>:' + doc.title;
cloneMap.set(doc[Id], copy);
return copy;
@@ -818,11 +827,11 @@ export namespace Doc {
const linkedDocs = Array.from(linkMap.values());
linkedDocs.forEach(link => Doc.AddLink?.(link, true));
rtfMap.forEach(({ copy, key, field }) => {
- const replacer = (match: any, attr: string, id: string /* , offset: any, string: any */) => {
+ const replacer = (match: string, 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 replacer2 = (match: string, href: string, id: string /* , offset: any, string: any */) => {
const mapped = cloneMap.get(id);
return href + (mapped ? mapped[Id] : id);
};
@@ -874,7 +883,7 @@ export namespace Doc {
newLayoutDoc.embedContainer = targetDoc;
newLayoutDoc.resolvedDataDoc = dataDoc;
newLayoutDoc.acl_Guest = SharingPermissions.Edit;
- if (dataDoc[templateField] === undefined && (templateLayoutDoc[templateField] as any)?.length) {
+ if (dataDoc[templateField] === undefined && (templateLayoutDoc[templateField] as List<Doc>)?.length) {
dataDoc[templateField] = ObjectField.MakeCopy(templateLayoutDoc[templateField] as List<Doc>);
// ComputedField.MakeFunction(`ObjectField.MakeCopy(templateLayoutDoc["${templateField}"])`, { templateLayoutDoc: Doc.name }, { templateLayoutDoc });
}
@@ -901,7 +910,7 @@ export namespace Doc {
return { layout: Doc.expandTemplateLayout(childDoc, templateRoot), data: resolvedDataDoc };
}
- export function FindReferences(infield: Doc | List<any>, references: Set<Doc>, system: boolean | undefined) {
+ export function FindReferences(infield: Doc | List<Doc>, references: Set<Doc>, system: boolean | undefined) {
if (infield instanceof Promise) return;
if (!(infield instanceof Doc)) {
infield?.forEach(val => (val instanceof Doc || val instanceof List) && FindReferences(val, references, system));
@@ -976,9 +985,10 @@ export namespace Doc {
} else if (cfield instanceof ComputedField) {
copy[key] = cfield[Copy](); // ComputedField.MakeFunction(cfield.script.originalScript);
} else if (field instanceof ObjectField) {
+ const docAtKey = doc[key];
copy[key] =
- doc[key] instanceof Doc && key.includes('layout[')
- ? new ProxyField(Doc.MakeCopy(doc[key] as any)) // copy the expanded render template
+ docAtKey instanceof Doc && key.includes('layout[')
+ ? new ProxyField(Doc.MakeCopy(docAtKey)) // copy the expanded render template
: ObjectField.MakeCopy(field);
} else if (field instanceof Promise) {
// eslint-disable-next-line no-debugger
@@ -1235,7 +1245,7 @@ export namespace Doc {
}
const UnhighlightWatchers: (() => void)[] = [];
- let UnhighlightTimer: any;
+ let UnhighlightTimer: NodeJS.Timeout | undefined;
export function IsUnhighlightTimerSet() { return UnhighlightTimer; } // prettier-ignore
export function AddUnHighlightWatcher(watcher: () => void) {
if (UnhighlightTimer) {
@@ -1244,7 +1254,7 @@ export namespace Doc {
}
export function linkFollowUnhighlight() {
clearTimeout(UnhighlightTimer);
- UnhighlightTimer = 0;
+ UnhighlightTimer = undefined;
UnhighlightWatchers.forEach(watcher => watcher());
UnhighlightWatchers.length = 0;
highlightedDocs.forEach(doc => Doc.UnHighlightDoc(doc));
@@ -1258,10 +1268,7 @@ export namespace Doc {
if (UnhighlightTimer) clearTimeout(UnhighlightTimer);
const presTransition = Number(presentationEffect?.presentation_transition);
const duration = isNaN(presTransition) ? 5000 : presTransition;
- UnhighlightTimer = window.setTimeout(() => {
- linkFollowUnhighlight();
- UnhighlightTimer = 0;
- }, duration);
+ UnhighlightTimer = setTimeout(linkFollowUnhighlight, duration);
}
export const highlightedDocs = new ObservableSet<Doc>();
@@ -1319,7 +1326,7 @@ export namespace Doc {
StrCast(doc.layout_fieldKey).split('_')[1] === 'icon' && setNativeView(doc);
}
- export function setNativeView(doc: any) {
+ export function setNativeView(doc: Doc) {
const prevLayout = StrCast(doc.layout_fieldKey).split('_')[1];
const deiconify = prevLayout === 'icon' && StrCast(doc.deiconifyLayout) ? 'layout_' + StrCast(doc.deiconifyLayout) : '';
prevLayout === 'icon' && (doc.deiconifyLayout = undefined);
@@ -1356,15 +1363,15 @@ export namespace Doc {
// filters document in a container collection:
// all documents with the specified value for the specified key are included/excluded
// based on the modifiers :"check", "x", undefined
- export function setDocFilter(container: Opt<Doc>, key: string, value: any, modifiers: 'remove' | 'match' | 'check' | 'x' | 'exists' | 'unset', toggle?: boolean, fieldPrefix?: string, append: boolean = true) {
+ export function setDocFilter(container: Opt<Doc>, key: string, value: FieldType | undefined, modifiers: 'remove' | 'match' | 'check' | 'x' | 'exists' | 'unset', toggle?: boolean, fieldPrefix?: string, append: boolean = true) {
if (!container) return;
const filterField = '_' + (fieldPrefix ? fieldPrefix + '_' : '') + 'childFilters';
const childFilters = StrListCast(container[filterField]);
runInAction(() => {
for (let i = 0; i < childFilters.length; i++) {
const fields = childFilters[i].split(FilterSep); // split key:value:modifier
- if (fields[0] === key && (fields[1] === value.toString() || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) {
- if (fields[2] === modifiers && modifiers && fields[1] === value.toString()) {
+ if (fields[0] === key && (fields[1] === value?.toString() || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) {
+ if (fields[2] === modifiers && modifiers && fields[1] === value?.toString()) {
// eslint-disable-next-line no-param-reassign
if (toggle) modifiers = 'remove';
else return;
@@ -1393,7 +1400,7 @@ export namespace Doc {
return undefined;
}
export function assignDocToField(doc: Doc, field: string, id: string) {
- DocServer.GetRefField(id).then(layout => {
+ DocServer.GetRefField(id)?.then(layout => {
layout instanceof Doc && (doc[field] = layout);
});
return id;
@@ -1417,7 +1424,7 @@ export namespace Doc {
export function Paste(docids: string[], clone: boolean, addDocument: (doc: Doc | Doc[]) => boolean, ptx?: number, pty?: number, newPoint?: number[]) {
DocServer.GetRefFields(docids).then(async fieldlist => {
- const list = Array.from(Object.values(fieldlist))
+ const list = Array.from(fieldlist.values())
.map(d => DocCast(d))
.filter(d => d);
const docs = clone ? (await Promise.all(Doc.MakeClones(list, false, false))).map(res => res.clone) : list;
@@ -1460,7 +1467,6 @@ export namespace Doc {
case DocumentType.BUTTON: return 'bolt';
case DocumentType.PRES: return 'route';
case DocumentType.SCRIPTING: return 'terminal';
- case DocumentType.IMPORT: return 'cloud-upload-alt';
case DocumentType.VID: return 'video';
case DocumentType.INK: return 'pen-nib';
case DocumentType.PDF: return 'file-pdf';
@@ -1494,7 +1500,7 @@ export namespace Doc {
const doc = DocCast(await DocServer.GetRefField(json.id));
const links = await DocServer.GetRefFields(json.linkids as string[]);
Array.from(Object.keys(links))
- .map(key => links[key])
+ .map(key => links.get(key))
.forEach(link => link instanceof Doc && Doc.AddLink?.(link));
return doc;
}
@@ -1506,7 +1512,7 @@ export namespace Doc {
const primitives = ['string', 'number', 'boolean'];
export interface JsonConversionOpts {
- data: any;
+ data: unknown;
title?: string;
appendToExisting?: { targetDoc: Doc; fieldKey?: string };
excludeEmptyObjects?: boolean;
@@ -1561,15 +1567,16 @@ export namespace Doc {
if (data === undefined || data === null || ![...primitives, 'object'].includes(typeof data)) {
return undefined;
}
- let resolved: any;
+ let resolved: unknown;
try {
resolved = JSON.parse(typeof data === 'string' ? data : JSON.stringify(data));
} catch (e) {
+ console.error(e);
return undefined;
}
let output: Opt<Doc>;
if (typeof resolved === 'object' && !(resolved instanceof Array)) {
- output = convertObject(resolved, excludeEmptyObjects, title, appendToExisting?.targetDoc);
+ output = convertObject(resolved as { [key: string]: FieldType }, excludeEmptyObjects, title, appendToExisting?.targetDoc);
} else {
// give the proper types to the data extracted from the JSON
const result = toField(resolved, excludeEmptyObjects);
@@ -1590,7 +1597,7 @@ export namespace Doc {
* @returns the object mapped from JSON to field values, where each mapping
* might involve arbitrary recursion (since toField might itself call convertObject)
*/
- const convertObject = (object: any, excludeEmptyObjects: boolean, title?: string, target?: Doc): Opt<Doc> => {
+ const convertObject = (object: { [key: string]: FieldType }, excludeEmptyObjects: boolean, title?: string, target?: Doc): Opt<Doc> => {
const hasEntries = Object.keys(object).length;
if (hasEntries || !excludeEmptyObjects) {
const resolved = target ?? new Doc();
@@ -1618,7 +1625,7 @@ export namespace Doc {
* @returns the list mapped from JSON to field values, where each mapping
* might involve arbitrary recursion (since toField might itself call convertList)
*/
- const convertList = (list: Array<any>, excludeEmptyObjects: boolean): Opt<List<FieldType>> => {
+ const convertList = (list: Array<unknown>, excludeEmptyObjects: boolean): Opt<List<FieldType>> => {
const target = new List();
let result: Opt<FieldType>;
// if excludeEmptyObjects is true, any qualifying conversions from toField will
@@ -1633,29 +1640,33 @@ export namespace Doc {
return undefined;
};
- const toField = (data: any, excludeEmptyObjects: boolean, title?: string): Opt<FieldType> => {
+ const toField = (data: unknown, excludeEmptyObjects: boolean, title?: string): Opt<FieldType> => {
if (data === null || data === undefined) {
return undefined;
}
if (primitives.includes(typeof data)) {
- return data;
+ return data as FieldType;
}
if (typeof data === 'object') {
- return data instanceof Array ? convertList(data, excludeEmptyObjects) : convertObject(data, excludeEmptyObjects, title, undefined);
+ return data instanceof Array ? convertList(data, excludeEmptyObjects) : convertObject(data as { [key: string]: FieldType }, excludeEmptyObjects, title, undefined);
}
throw new Error(`How did ${data} of type ${typeof data} end up in JSON?`);
};
}
}
+export function returnEmptyDoclist() {
+ return [] as Doc[];
+}
+
export function RTFIsFragment(html: string) {
return html.indexOf('data-pm-slice') !== -1;
}
export function GetHrefFromHTML(html: string): string {
const parser = new DOMParser();
const parsedHtml = parser.parseFromString(html, 'text/html');
- if (parsedHtml.body.childNodes.length === 1 && parsedHtml.body.childNodes[0].childNodes.length === 1 && (parsedHtml.body.childNodes[0].childNodes[0] as any).href) {
- return (parsedHtml.body.childNodes[0].childNodes[0] as any).href;
+ if (parsedHtml.body.childNodes.length === 1 && parsedHtml.body.childNodes[0].childNodes.length === 1 && (parsedHtml.body.childNodes[0].childNodes[0] as HTMLAnchorElement).href) {
+ return (parsedHtml.body.childNodes[0].childNodes[0] as HTMLAnchorElement).href;
}
return '';
}
@@ -1675,35 +1686,35 @@ export function IdToDoc(id: string) {
return DocCast(DocServer.GetCachedRefField(id));
}
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function idToDoc(id: string): any {
+ScriptingGlobals.add(function idToDoc(id: string): Doc {
return IdToDoc(id);
});
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function renameEmbedding(doc: any) {
+ScriptingGlobals.add(function renameEmbedding(doc: Doc) {
return StrCast(doc[DocData].title).replace(/\([0-9]*\)/, '') + `(${doc.proto_embeddingId})`;
});
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function getProto(doc: any) {
+ScriptingGlobals.add(function getProto(doc: Doc) {
return Doc.GetProto(doc);
});
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function getDocTemplate(doc?: any) {
+ScriptingGlobals.add(function getDocTemplate(doc?: Doc) {
return Doc.getDocTemplate(doc);
});
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function getEmbedding(doc: any) {
+ScriptingGlobals.add(function getEmbedding(doc: Doc) {
return Doc.MakeEmbedding(doc);
});
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function getCopy(doc: any, copyProto: any) {
+ScriptingGlobals.add(function getCopy(doc: Doc, copyProto: boolean) {
return doc.isTemplateDoc ? Doc.MakeDelegateWithProto(doc) : Doc.MakeCopy(doc, copyProto);
});
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function copyField(field: any) {
+ScriptingGlobals.add(function copyField(field: FieldResult) {
return Field.Copy(field);
});
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function docList(field: any) {
+ScriptingGlobals.add(function docList(field: FieldResult) {
return DocListCast(field);
});
// eslint-disable-next-line prefer-arrow-callback
@@ -1711,11 +1722,11 @@ ScriptingGlobals.add(function addDocToList(doc: Doc, field: string, added: Doc)
return Doc.AddDocToList(doc, field, added);
});
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function setInPlace(doc: any, field: any, value: any) {
+ScriptingGlobals.add(function setInPlace(doc: Doc, field: string, value: string) {
return Doc.SetInPlace(doc, field, value, false);
});
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function sameDocs(doc1: any, doc2: any) {
+ScriptingGlobals.add(function sameDocs(doc1: Doc, doc2: Doc) {
return Doc.AreProtosEqual(doc1, doc2);
});
// eslint-disable-next-line prefer-arrow-callback
@@ -1723,7 +1734,7 @@ ScriptingGlobals.add(function assignDoc(doc: Doc, field: string, id: string) {
return Doc.assignDocToField(doc, field, id);
});
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function docCastAsync(doc: FieldResult): any {
+ScriptingGlobals.add(function docCastAsync(doc: FieldResult): FieldResult<Doc> {
return Cast(doc, Doc);
});
// eslint-disable-next-line prefer-arrow-callback
@@ -1732,7 +1743,7 @@ ScriptingGlobals.add(function activePresentationItem() {
return curPres && DocListCast(curPres[Doc.LayoutFieldKey(curPres)])[NumCast(curPres._itemIndex)];
});
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function setDocFilter(container: Doc, key: string, value: any, modifiers: 'match' | 'check' | 'x' | 'remove') {
+ScriptingGlobals.add(function setDocFilter(container: Doc, key: string, value: string, modifiers: 'match' | 'check' | 'x' | 'remove') {
Doc.setDocFilter(container, key, value, modifiers);
});
// eslint-disable-next-line prefer-arrow-callback