diff options
author | bobzel <zzzman@gmail.com> | 2023-11-07 13:48:26 -0500 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2023-11-07 13:48:26 -0500 |
commit | a6cc25e5d03ffed16bfaa32e48e9cc2eaff7deaf (patch) | |
tree | 1322ef9a743457f23851ba7c9d5d3dd090f1f75d /src/fields/Doc.ts | |
parent | a4e3b645317c4589cf49f8007f6e6b57cf2c12d3 (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.ts | 95 |
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); }); |