aboutsummaryrefslogtreecommitdiff
path: root/src/fields/Doc.ts
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-11-07 13:48:26 -0500
committerbobzel <zzzman@gmail.com>2023-11-07 13:48:26 -0500
commita6cc25e5d03ffed16bfaa32e48e9cc2eaff7deaf (patch)
tree1322ef9a743457f23851ba7c9d5d3dd090f1f75d /src/fields/Doc.ts
parenta4e3b645317c4589cf49f8007f6e6b57cf2c12d3 (diff)
Changed how selection works to avoid invalidations. Fixed Cast problem with ProxyFields that caused renameEmbedding to infinite loop.. Changed brushing for the same reason. Cleaned up a few things with filter code.
Diffstat (limited to 'src/fields/Doc.ts')
-rw-r--r--src/fields/Doc.ts95
1 files changed, 28 insertions, 67 deletions
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index feacdc9c5..2f9eea492 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -11,7 +11,7 @@ import { afterDocDeserialize, autoObject, Deserializable, SerializationHelper }
import { undoable } from '../client/util/UndoManager';
import { decycle } from '../decycler/decycler';
import * as JSZipUtils from '../JSZipUtils';
-import { DashColor, incrementTitleCopy, intersectRect, Utils } from '../Utils';
+import { incrementTitleCopy, intersectRect, Utils } from '../Utils';
import { DateField } from './DateField';
import {
AclAdmin,
@@ -21,6 +21,7 @@ import {
AclReadonly,
Animation,
AudioPlay,
+ Brushed,
CachedUpdates,
DirectLinks,
DocAcl,
@@ -28,6 +29,7 @@ import {
DocData,
DocFields,
DocLayout,
+ DocViews,
FieldKeys,
FieldTuples,
ForceServerWrite,
@@ -52,6 +54,7 @@ import { BoolCast, Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor }
import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField } from './URLField';
import { containedFieldChangedHandler, deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions, TraceMobx } from './util';
import JSZip = require('jszip');
+import { DocumentView } from '../client/views/nodes/DocumentView';
export const LinkedTo = '-linkedTo';
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
@@ -354,6 +357,8 @@ export class Doc extends RefField {
@observable public [AudioPlay]: any; // meant to store sound object from Howl
@observable public [Animation]: Opt<Doc>;
@observable public [Highlight]: boolean = false;
+ @observable public [Brushed]: boolean = false;
+ @observable public [DocViews] = new ObservableSet<DocumentView>();
static __Anim(Doc: Doc) {
// for debugging to print AnimationSym field easily.
return Doc[Animation];
@@ -808,9 +813,7 @@ export namespace Doc {
const docAtKey = DocCast(clone[key]);
if (docAtKey && !Doc.IsSystem(docAtKey)) {
if (!Array.from(cloneMap.values()).includes(docAtKey)) {
- if (cloneMap.has(docAtKey[Id])) {
- clone[key] = cloneMap.get(docAtKey[Id]);
- } else clone[key] = undefined;
+ clone[key] = cloneMap.get(docAtKey[Id]);
} else {
repairClone(docAtKey, cloneMap, visited);
}
@@ -1020,7 +1023,7 @@ export namespace Doc {
references.add(doc);
return;
}
- const excludeLists = ['My Recently Closed', 'My Header Bar', 'My Dashboards'].includes(StrCast(doc.title));
+ const excludeLists = [Doc.MyRecentlyClosed, Doc.MyHeaderBar, Doc.MyDashboards].includes(doc);
if (system !== undefined && ((system && !Doc.IsSystem(doc)) || (!system && Doc.IsSystem(doc)))) return;
references.add(doc);
Object.keys(doc).forEach(key => {
@@ -1202,9 +1205,6 @@ export namespace Doc {
// change it to 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);
-
return true;
}
@@ -1234,13 +1234,13 @@ export namespace Doc {
export function isBrushedHighlightedDegree(doc: Doc) {
return Doc.IsHighlighted(doc) ? DocBrushStatus.highlighted : Doc.IsBrushedDegree(doc);
}
- export function isBrushedHighlightedDegreeUnmemoized(doc: Doc) {
- return Doc.IsHighlighted(doc) ? DocBrushStatus.highlighted : Doc.IsBrushedDegreeUnmemoized(doc);
- }
-
export class DocBrush {
- BrushedDoc: ObservableMap<Doc, boolean> = new ObservableMap();
+ BrushedDoc = new Set<Doc>();
SearchMatchDoc: ObservableMap<Doc, { searchMatch: number }> = new ObservableMap();
+ brushDoc = action((doc: Doc, unbrush: boolean) => {
+ unbrush ? this.BrushedDoc.delete(doc) : this.BrushedDoc.add(doc);
+ doc[Brushed] = !unbrush;
+ });
}
export const brushManager = new DocBrush();
@@ -1330,45 +1330,25 @@ export namespace Doc {
brushManager.SearchMatchDoc.clear();
}
- const isBrushedCache = computedFn(function IsBrushed(doc: Doc) {
- return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetProto(doc));
- });
- export function IsBrushed(doc: Doc) {
- return isBrushedCache(doc);
- }
-
export enum DocBrushStatus {
unbrushed = 0,
protoBrushed = 1,
selfBrushed = 2,
highlighted = 3,
}
- // 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) {
- if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate || doc.opacity === 0) return DocBrushStatus.unbrushed;
- const status = brushManager.BrushedDoc.has(doc) ? DocBrushStatus.selfBrushed : brushManager.BrushedDoc.has(Doc.GetProto(doc)) ? DocBrushStatus.protoBrushed : DocBrushStatus.unbrushed;
- return status;
- }
+ // returns 'how' a Doc has been brushed over - whether the document itself was brushed, it's prototype, or neither
export function IsBrushedDegree(doc: Doc) {
- return computedFn(function IsBrushDegree(doc: Doc) {
- return Doc.IsBrushedDegreeUnmemoized(doc);
- })(doc);
+ if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate || doc.opacity === 0) return DocBrushStatus.unbrushed;
+ return doc[Brushed] ? DocBrushStatus.selfBrushed : Doc.GetProto(doc)[Brushed] ? DocBrushStatus.protoBrushed : DocBrushStatus.unbrushed;
}
- export function BrushDoc(doc: Doc) {
+ export function BrushDoc(doc: Doc, unbrush = false) {
if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc;
- runInAction(() => {
- brushManager.BrushedDoc.set(doc, true);
- brushManager.BrushedDoc.set(Doc.GetProto(doc), true);
- });
+ brushManager.brushDoc(doc, unbrush);
+ brushManager.brushDoc(Doc.GetProto(doc), unbrush);
return doc;
}
export function UnBrushDoc(doc: Doc) {
- if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc;
- runInAction(() => {
- brushManager.BrushedDoc.delete(doc);
- brushManager.BrushedDoc.delete(Doc.GetProto(doc));
- });
- return doc;
+ return BrushDoc(doc, true);
}
export function LinkEndpoint(linkDoc: Doc, anchorDoc: Doc) {
@@ -1436,7 +1416,7 @@ export namespace Doc {
});
}
export function UnBrushAllDocs() {
- runInAction(() => brushManager.BrushedDoc.clear());
+ Array.from(brushManager.BrushedDoc).forEach(action(doc => (doc[Brushed] = false)));
}
export function getDocTemplate(doc?: Doc) {
@@ -1454,9 +1434,9 @@ export namespace Doc {
}
export function matchFieldValue(doc: Doc, key: string, value: any): boolean {
- if (Utils.HasTransparencyFilter(value)) {
- const isTransparent = (color: string) => color !== '' && DashColor(color).alpha() !== 1;
- return isTransparent(StrCast(doc[key]));
+ const hasFunctionFilter = Utils.HasFunctionFilter(value);
+ if (hasFunctionFilter) {
+ return hasFunctionFilter(StrCast(doc[key]));
}
if (key === LinkedTo) {
// links are not a field value, so handled here. value is an expression of form ([field=]idToDoc("..."))
@@ -1481,11 +1461,9 @@ export namespace Doc {
(value === Doc.FilterNone && fieldVal === undefined)) {
return true;
}
- if (Cast(fieldVal, listSpec('string'), []).length) {
- const vals = StrListCast(fieldVal);
- const docs = vals.some(v => (v as any) instanceof Doc);
- if (docs) return value === Field.toString(fieldVal as Field);
- return vals.some(v => v.includes(value)); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
+ const vals = StrListCast(fieldVal); // list typing is very imperfect. casting to a string list doesn't mean that the entries will actually be strings
+ if (vals.length) {
+ return vals.some(v => typeof v === 'string' && v.includes(value)); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
}
return Field.toString(fieldVal as Field).includes(value); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
}
@@ -1501,34 +1479,27 @@ export namespace Doc {
doc.layout_fieldKey = deiconify || 'layout';
}
export function setDocRangeFilter(container: Opt<Doc>, key: string, range?: readonly number[], modifiers?: 'remove') {
- //, modifiers: 'remove' | 'set'
if (!container) return;
const childFiltersByRanges = Cast(container._childFiltersByRanges, listSpec('string'), []);
for (let i = 0; i < childFiltersByRanges.length; i += 3) {
if (childFiltersByRanges[i] === key) {
- console.log('this is key inside childfilters by range ' + key);
childFiltersByRanges.splice(i, 3);
- console.log('this is child filters by range ' + childFiltersByRanges);
break;
}
}
if (range !== undefined) {
- console.log('in doc.ts in set range filter');
childFiltersByRanges.push(key);
childFiltersByRanges.push(range[0].toString());
childFiltersByRanges.push(range[1].toString());
container._childFiltersByRanges = new List<string>(childFiltersByRanges);
- console.log('this is child filters by range ' + childFiltersByRanges[0] + ',' + childFiltersByRanges[1] + ',' + childFiltersByRanges[2]);
- console.log('this is new list ' + container._childFiltersByRange);
}
if (modifiers) {
childFiltersByRanges.splice(0, 3);
container._childFiltersByRanges = new List<string>(childFiltersByRanges);
}
- console.log('this is child filters by range END' + childFiltersByRanges[0] + ',' + childFiltersByRanges[1] + ',' + childFiltersByRanges[2]);
}
export const FilterSep = '::';
@@ -1599,12 +1570,6 @@ export namespace Doc {
});
}
- export function isDocPinned(doc: Doc) {
- //add this new doc to props.Document
- const curPres = Doc.ActivePresentation;
- return !curPres ? false : DocListCast(curPres.data).findIndex(val => Doc.AreProtosEqual(val, doc)) !== -1;
- }
-
export function styleFromLayoutString(rootDoc: Doc, layoutDoc: Doc, props: any, scale: number) {
const style: { [key: string]: any } = {};
const divKeys = ['width', 'height', 'fontSize', 'transform', 'left', 'backgroundColor', 'left', 'right', 'top', 'bottom', 'pointerEvents', 'position'];
@@ -1628,7 +1593,7 @@ export namespace Doc {
if (ptx !== undefined && pty !== undefined && newPoint !== undefined) {
const firstx = list.length ? NumCast(list[0].x) + ptx - newPoint[0] : 0;
const firsty = list.length ? NumCast(list[0].y) + pty - newPoint[1] : 0;
- docs.map(doc => {
+ docs.forEach(doc => {
doc.x = NumCast(doc.x) - firstx;
doc.y = NumCast(doc.y) - firsty;
});
@@ -1871,10 +1836,6 @@ ScriptingGlobals.add(function setInPlace(doc: any, field: any, value: any) {
ScriptingGlobals.add(function sameDocs(doc1: any, doc2: any) {
return Doc.AreProtosEqual(doc1, doc2);
});
-ScriptingGlobals.add(function DOC(id: string) {
- console.log("Can't parse a document id in a script");
- return 'invalid';
-});
ScriptingGlobals.add(function assignDoc(doc: Doc, field: string, id: string) {
return Doc.assignDocToField(doc, field, id);
});