diff options
Diffstat (limited to 'src/fields')
-rw-r--r-- | src/fields/Doc.ts | 464 | ||||
-rw-r--r-- | src/fields/RichTextUtils.ts | 2 | ||||
-rw-r--r-- | src/fields/util.ts | 2 |
3 files changed, 109 insertions, 359 deletions
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 2f9eea492..6dece87b5 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1,46 +1,23 @@ -import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { saveAs } from 'file-saver'; import { action, computed, observable, ObservableMap, ObservableSet, runInAction } from 'mobx'; import { computedFn } from 'mobx-utils'; import { alias, map, serializable } from 'serializr'; import { DocServer } from '../client/DocServer'; -import { DocumentType } from '../client/documents/DocumentTypes'; +import { CollectionViewType, DocumentType } from '../client/documents/DocumentTypes'; import { LinkManager } from '../client/util/LinkManager'; import { scriptingGlobal, ScriptingGlobals } from '../client/util/ScriptingGlobals'; import { afterDocDeserialize, autoObject, Deserializable, SerializationHelper } from '../client/util/SerializationHelper'; import { undoable } from '../client/util/UndoManager'; +import { DocumentView } from '../client/views/nodes/DocumentView'; import { decycle } from '../decycler/decycler'; import * as JSZipUtils from '../JSZipUtils'; -import { incrementTitleCopy, intersectRect, Utils } from '../Utils'; +import { incrementTitleCopy, Utils } from '../Utils'; import { DateField } from './DateField'; import { - AclAdmin, - AclAugment, - AclEdit, - AclPrivate, - AclReadonly, - Animation, - AudioPlay, - Brushed, - CachedUpdates, - DirectLinks, - DocAcl, - DocCss, - DocData, - DocFields, - DocLayout, - DocViews, - FieldKeys, - FieldTuples, - ForceServerWrite, - Height, - Highlight, - Initializing, - Self, - SelfProxy, - UpdatingFromServer, - Width, -} from './DocSymbols'; + AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, Animation, AudioPlay, Brushed, CachedUpdates, DirectLinks, + DocAcl, DocCss, DocData, DocFields, DocLayout, DocViews, FieldKeys, FieldTuples, ForceServerWrite, Height, Highlight, + Initializing, Self, SelfProxy, UpdatingFromServer, Width +} from './DocSymbols'; // prettier-ignore import { Copy, FieldChanged, HandleUpdate, Id, Parent, ToScriptString, ToString } from './FieldSymbols'; import { InkField, InkTool } from './InkField'; import { List, ListFieldName } from './List'; @@ -52,9 +29,8 @@ import { listSpec } from './Schema'; import { ComputedField, ScriptField } from './ScriptField'; import { BoolCast, Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor } from './Types'; import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField } from './URLField'; -import { containedFieldChangedHandler, deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions, TraceMobx } from './util'; +import { containedFieldChangedHandler, deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, setter, SharingPermissions } 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 { @@ -66,25 +42,23 @@ export namespace Field { : '' : (onDelegate ? '=' : '') + (field instanceof ComputedField ? `:=${field.script.originalScript}` : field instanceof ScriptField ? `$=${field.script.originalScript}` : Field.toScriptString(field)); } - export function toScriptString(field: Field): string { + export function toScriptString(field: Field) { switch (typeof field) { - case 'string': - if (field.startsWith('{"')) return `'${field}'`; // bcz: hack ... want to quote the string the right way. if there are nested "'s, then use ' instead of ". In this case, test for the start of a JSON string of the format {"property": ... } and use outer 's instead of "s - return !field.includes('`') ? `\`${field}\`` : `"${field}"`; + case 'string': if (field.startsWith('{"')) return `'${field}'`; // bcz: hack ... want to quote the string the right way. if there are nested "'s, then use ' instead of ". In this case, test for the start of a JSON string of the format {"property": ... } and use outer 's instead of "s + return !field.includes('`') ? `\`${field}\`` : `"${field}"`; case 'number': - case 'boolean': - return String(field); - } - return field?.[ToScriptString]?.() ?? 'null'; + case 'boolean':return String(field); + default: return field?.[ToScriptString]?.() ?? 'null'; + } // prettier-ignore } - export function toString(field: Field): string { + export function toString(field: Field) { if (typeof field === 'string' || typeof field === 'number' || typeof field === 'boolean') return String(field); return field?.[ToString]?.() || ''; } 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 { - return typeof field === 'string' || typeof field === 'number' || typeof field === 'boolean' || field instanceof ObjectField || field instanceof RefField || (includeUndefined && field === undefined); + return ['string', 'number', 'boolean'].includes(typeof field) || field instanceof ObjectField || field instanceof RefField || (includeUndefined && field === undefined); } export function Copy(field: any) { return field instanceof ObjectField ? ObjectField.MakeCopy(field) : field; @@ -107,11 +81,6 @@ export function DocListCastAsync(field: FieldResult, defaultValue?: Doc[]) { const list = Cast(field, listSpec(Doc)); return list ? Promise.all(list).then(() => list) : Promise.resolve(defaultValue); } - -export async function DocCastAsync(field: FieldResult): Promise<Opt<Doc>> { - return Cast(field, Doc); -} - export function NumListCast(field: FieldResult, defaultVal: number[] = []) { return Cast(field, listSpec('number'), defaultVal); } @@ -162,140 +131,51 @@ export function updateCachedAcls(doc: Doc) { @Deserializable('Doc', updateCachedAcls, ['id']) export class Doc extends RefField { @observable public static RecordingEvent = 0; - - // this isn't really used at the moment, but is intended to indicate whether ink stroke are passed through a gesture recognizer - static GetRecognizeGestures() { - return BoolCast(Doc.UserDoc()._recognizeGestures); - } - static SetRecognizeGestures(show: boolean) { - Doc.UserDoc()._recognizeGestures = show; - } - - // - // This controls whether fontIconButtons will display labels under their icons or not - // - static GetShowIconLabels() { - return BoolCast(Doc.UserDoc()._showLabel); - } - static SetShowIconLabels(show: boolean) { - Doc.UserDoc()._showLabel = show; - } - @observable public static CurrentlyLoading: Doc[] = []; // this assignment doesn't work. the actual assignment happens in DocumentManager's constructor - // removes from currently loading display - @action - public static removeCurrentlyLoading(doc: Doc) { - if (Doc.CurrentlyLoading) { - const index = Doc.CurrentlyLoading.indexOf(doc); - index !== -1 && Doc.CurrentlyLoading.splice(index, 1); - } - } - - // adds doc to currently loading display - @action - public static addCurrentlyLoading(doc: Doc) { - if (Doc.CurrentlyLoading.indexOf(doc) === -1) { - Doc.CurrentlyLoading.push(doc); - } - } - @observable public static GuestDashboard: Doc | undefined; @observable public static GuestTarget: Doc | undefined; @observable public static GuestMobile: Doc | undefined; - public static get MySharedDocs() { - return DocCast(Doc.UserDoc().mySharedDocs); - } - public static get MyUserDocView() { - return DocCast(Doc.UserDoc().myUserDocView); - } - public static get MyDockedBtns() { - return DocCast(Doc.UserDoc().myDockedBtns); - } - public static get MySearcher() { - return DocCast(Doc.UserDoc().mySearcher); - } - public static get MyHeaderBar() { - return DocCast(Doc.UserDoc().myHeaderBar); - } - public static get MyLeftSidebarMenu() { - return DocCast(Doc.UserDoc().myLeftSidebarMenu); - } - public static get MyLeftSidebarPanel() { - return DocCast(Doc.UserDoc().myLeftSidebarPanel); - } - public static get MyContextMenuBtns() { - return DocCast(Doc.UserDoc().myContextMenuBtns); - } - public static get MyTopBarBtns() { - return DocCast(Doc.UserDoc().myTopBarBtns); - } - public static get MyRecentlyClosed() { - return DocCast(Doc.UserDoc().myRecentlyClosed); - } - public static get MyTrails() { - return DocCast(Doc.ActiveDashboard?.myTrails); - } - public static IsInMyOverlay(doc: Doc) { - return DocListCast(Doc.MyOverlayDocs?.data).includes(doc); - } - public static AddToMyOverlay(doc: Doc) { - Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc); - } - public static RemFromMyOverlay(doc: Doc) { - Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, doc); - } - public static get MyOverlayDocs() { - return DocCast(Doc.UserDoc().myOverlayDocs); - } - public static get MyPublishedDocs() { - return DocCast(Doc.UserDoc().myPublishedDocs); - } - public static get MyDashboards() { - return DocCast(Doc.UserDoc().myDashboards); - } - public static get MyTemplates() { - return DocCast(Doc.UserDoc().myTemplates); - } - public static get MyImports() { - return DocCast(Doc.UserDoc().myImports); - } - public static get MyFilesystem() { - return DocCast(Doc.UserDoc().myFilesystem); - } - public static get MyTools() { - return DocCast(Doc.UserDoc().myTools); - } - public static get ActivePage() { - return StrCast(Doc.UserDoc().activePage); - } - public static set ActivePage(val) { - Doc.UserDoc().activePage = val; - DocServer.UPDATE_SERVER_CACHE(); - } - public static IsComicStyle(doc?: Doc) { - return doc && Doc.ActiveDashboard && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === 'comic'; - } - public static get ActiveDashboard() { - return DocCast(Doc.UserDoc().activeDashboard); - } - public static set ActiveDashboard(val: Doc | undefined) { - const overlays = Cast(Doc.MyOverlayDocs.data, listSpec(Doc), null); - overlays && (overlays.length = 0); - Doc.UserDoc().activeDashboard = val; - } - public static set ActiveTool(tool: InkTool) { - Doc.UserDoc().activeTool = tool; - } - public static get ActiveTool(): InkTool { - return StrCast(Doc.UserDoc().activeTool, InkTool.None) as InkTool; - } - public static get ActivePresentation(): Opt<Doc> { - return DocCast(Doc.ActiveDashboard?.activePresentation); - } - public static set ActivePresentation(val) { - if (Doc.ActiveDashboard) { - Doc.ActiveDashboard.activePresentation = val; - } - } + public static CurrentUserEmail: string = ''; + + public static get MySharedDocs() { return DocCast(Doc.UserDoc().mySharedDocs); } // prettier-ignore + 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 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 + public static get MyContextMenuBtns() { return DocCast(Doc.UserDoc().myContextMenuBtns); } // prettier-ignore + public static get MyTopBarBtns() { return DocCast(Doc.UserDoc().myTopBarBtns); } // prettier-ignore + public static get MyRecentlyClosed() { return DocCast(Doc.UserDoc().myRecentlyClosed); } // prettier-ignore + public static get MyTrails() { return DocCast(Doc.ActiveDashboard?.myTrails); } // prettier-ignore + public static get MyOverlayDocs() { return DocListCast(Doc.ActiveDashboard?.myOverlayDocs ?? DocCast(Doc.UserDoc().myOverlayDocs).data); } // prettier-ignore + public static get MyPublishedDocs() { return DocListCast(Doc.ActiveDashboard?.myPublishedDocs ?? DocCast(Doc.UserDoc().myPublishedDocs).data); } // prettier-ignore + public static get MyDashboards() { return DocCast(Doc.UserDoc().myDashboards); } // prettier-ignore + public static get MyTemplates() { return DocCast(Doc.UserDoc().myTemplates); } // prettier-ignore + public static get MyImports() { return DocCast(Doc.UserDoc().myImports); } // prettier-ignore + public static get MyFilesystem() { return DocCast(Doc.UserDoc().myFilesystem); } // prettier-ignore + public static get MyTools() { return DocCast(Doc.UserDoc().myTools); } // prettier-ignore + public static get noviceMode() { return BoolCast(Doc.UserDoc().noviceMode); } // prettier-ignore + public static set noviceMode(val) { Doc.UserDoc().noviceMode = val; } // prettier-ignore + public static get IsSharingEnabled() { return BoolCast(Doc.UserDoc().isSharingEnabled); } // prettier-ignore + public static set IsSharingEnabled(val) { Doc.UserDoc().isSharingEnabled = val; } // prettier-ignore + public static get defaultAclPrivate() { return Doc.UserDoc().defaultAclPrivate; } // prettier-ignore + public static set defaultAclPrivate(val) { Doc.UserDoc().defaultAclPrivate = val; } // prettier-ignore + public static get ActivePage() { return StrCast(Doc.UserDoc().activePage); } // prettier-ignore + public static set ActivePage(val) { Doc.UserDoc().activePage = val; } // prettier-ignore + public static get ActiveTool(): InkTool { return StrCast(Doc.UserDoc().activeTool, InkTool.None) as InkTool; } // prettier-ignore + public static set ActiveTool(tool:InkTool){ Doc.UserDoc().activeTool = tool; } // prettier-ignore + public static get ActivePresentation() { return DocCast(Doc.ActiveDashboard?.activePresentation) as Opt<Doc>; } // prettier-ignore + public static set ActivePresentation(val) { Doc.ActiveDashboard && (Doc.ActiveDashboard.activePresentation = val) } // prettier-ignore + public static get ActiveDashboard() { return DocCast(Doc.UserDoc().activeDashboard); } // prettier-ignore + 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) { Doc.ActiveDashboard?.myOverlayDocs ? Doc.AddDocToList(Doc.ActiveDashboard, 'myOverlayDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore + public static RemFromMyOverlay(doc: Doc) { Doc.ActiveDashboard?.myOverlayDocs ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myOverlayDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore + public static AddToMyPublished(doc: Doc) { Doc.ActiveDashboard?.myPublishedDocs ? Doc.AddDocToList(Doc.ActiveDashboard, 'myPublishedDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore + public static RemFromMyPublished(doc: Doc){ Doc.ActiveDashboard?.myPublishedDocs ? 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) { super(id); const docProxy = new Proxy<this>(this, { @@ -359,17 +239,14 @@ export class Doc extends RefField { @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]; - } + private [Self] = this; + private [SelfProxy]: any; private [UpdatingFromServer]: boolean = false; private [ForceServerWrite]: boolean = false; - public [Initializing]: boolean = false; + private [CachedUpdates]: { [key: string]: () => void | Promise<any> } = {}; - private [Self] = this; - private [SelfProxy]: any; + public [Initializing]: boolean = false; public [FieldChanged] = (diff: undefined | { op: '$addToSet' | '$remFromSet' | '$set'; items: Field[] | undefined; length: number | undefined; hint?: any }, serverOp: any) => { if (!this[UpdatingFromServer] || this[ForceServerWrite]) { DocServer.UpdateField(this[Id], serverOp); @@ -380,9 +257,7 @@ export class Doc extends RefField { public [Height] = () => NumCast(this[SelfProxy]._height); public [ToScriptString] = () => `idToDoc("${this[Self][Id]}")`; public [ToString] = () => `Doc(${GetEffectiveAcl(this[SelfProxy]) === AclPrivate ? '-inaccessible-' : this[SelfProxy].title})`; - public get [DocLayout]() { - return this[SelfProxy].__LAYOUT__; - } + public get [DocLayout]() { return this[SelfProxy].__LAYOUT__; } // prettier-ignore public get [DocData](): Doc { const self = this[SelfProxy]; return self.resolvedDataDoc && !self.isTemplateForField ? self : Doc.GetProto(Cast(Doc.Layout(self).resolvedDataDoc, Doc, null) || self); @@ -403,29 +278,6 @@ export class Doc extends RefField { return undefined; } - private [CachedUpdates]: { [key: string]: () => void | Promise<any> } = {}; - public static get noviceMode() { - return Doc.UserDoc().noviceMode as boolean; - } - public static set noviceMode(val) { - Doc.UserDoc().noviceMode = val; - } - public static get IsSharingEnabled() { - return Doc.UserDoc().isSharingEnabled as boolean; - } - public static set IsSharingEnabled(val) { - Doc.UserDoc().isSharingEnabled = val; - } - public static get defaultAclPrivate() { - return Doc.UserDoc().defaultAclPrivate; - } - public static set defaultAclPrivate(val) { - Doc.UserDoc().defaultAclPrivate = val; - } - public static CurrentUserEmail: string = ''; - public static get CurrentUserEmailNormalized() { - return normalizeEmail(Doc.CurrentUserEmail); - } public async [HandleUpdate](diff: any) { const set = diff.$set; const sameAuthor = this.author === Doc.CurrentUserEmail; @@ -482,17 +334,6 @@ export class Doc extends RefField { } export namespace Doc { - // export function GetAsync(doc: Doc, key: string, ignoreProto: boolean = false): Promise<Field | undefined> { - // const self = doc[Self]; - // return new Promise(res => getField(self, key, ignoreProto, res)); - // } - // export function GetTAsync<T extends Field>(doc: Doc, key: string, ctor: ToConstructor<T>, ignoreProto: boolean = false): Promise<T | undefined> { - // return new Promise(async res => { - // const field = await GetAsync(doc, key, ignoreProto); - // return Cast(field, ctor); - // }); - // } - export function SetContainer(doc: Doc, container: Doc) { doc.embedContainer = container; } @@ -626,10 +467,9 @@ export namespace Doc { /** * @returns the index of doc toFind in list of docs, -1 otherwise */ - export function IndexOf(toFind: Doc, list: Doc[], allowProtos: boolean = true) { - let index = list.reduce((p, v, i) => (v instanceof Doc && v === toFind ? i : p), -1); - index = allowProtos && index !== -1 ? index : list.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, toFind) ? i : p), -1); - return index; // list.findIndex(doc => doc === toFind || Doc.AreProtosEqual(doc, toFind)); + export function IndexOf(toFind: Doc, list: Doc[]) { + const index = list.indexOf(toFind); + return index !== -1 ? index : list.findIndex(doc => Doc.AreProtosEqual(doc, toFind)); } /** @@ -663,11 +503,10 @@ export namespace Doc { } const list = Cast(listDoc[key], listSpec(Doc)); if (list) { - if (allowDuplicates !== true) { - const pind = list.reduce((l, d, i) => (d instanceof Doc && d[Id] === doc[Id] ? i : l), -1); + if (!allowDuplicates) { + const pind = list.findIndex(d => d instanceof Doc && d[Id] === doc[Id]); if (pind !== -1) { return true; - //list.splice(pind, 1); // bcz: this causes schemaView docs in the Catalog to move to the bottom of the schema view when they are dragged even though they haven't left the collection } } if (first) { @@ -687,22 +526,6 @@ export namespace Doc { return false; } - /** - * Computes the bounds of the contents of a set of documents. - */ - export function ComputeContentBounds(docList: Doc[]) { - const bounds = docList.reduce( - (bounds, doc) => ({ - x: Math.min(NumCast(doc.x), bounds.x), - y: Math.min(NumCast(doc.y), bounds.y), - r: Math.max(NumCast(doc.x) + doc[Width](), bounds.r), - b: Math.max(NumCast(doc.y) + doc[Height](), bounds.b), - }), - { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: -Number.MAX_VALUE, b: -Number.MAX_VALUE } - ); - return bounds; - } - export function MakeEmbedding(doc: Doc, id?: string) { const embedding = !GetT(doc, 'isDataDoc', 'boolean', true) && doc.proto ? Doc.MakeCopy(doc, undefined, id) : Doc.MakeDelegate(doc, id); const layout = Doc.LayoutField(embedding); @@ -779,7 +602,7 @@ export namespace Doc { } else if (field instanceof RefField) { assignKey(field); } else if (cfield instanceof ComputedField) { - assignKey(cfield[Copy]()); // ComputedField.MakeFunction(cfield.script.originalScript)); + assignKey(cfield[Copy]()); } else if (field instanceof ObjectField) { await copyObjectField(field); } else if (field instanceof Promise) { @@ -990,29 +813,6 @@ export namespace Doc { return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc), data: resolvedDataDoc }; } - export function Overwrite(doc: Doc, overwrite: Doc, copyProto: boolean = false): Doc { - Object.keys(doc).forEach(key => { - const field = ProxyField.WithoutProxy(() => doc[key]); - if (key === 'proto' && copyProto) { - if (doc.proto instanceof Doc && overwrite.proto instanceof Doc) { - overwrite[key] = Doc.Overwrite(doc.proto, overwrite.proto); - } - } else { - if (field instanceof RefField) { - overwrite[key] = field; - } else if (field instanceof ObjectField) { - overwrite[key] = ObjectField.MakeCopy(field); - } else if (field instanceof Promise) { - debugger; //This shouldn't happend... - } else { - overwrite[key] = field; - } - } - }); - - return overwrite; - } - export function FindReferences(infield: Doc | List<any>, references: Set<Doc>, system: boolean | undefined) { if (infield instanceof List<any>) { infield.forEach(val => (val instanceof Doc || val instanceof List) && FindReferences(val, references, system)); @@ -1217,22 +1017,8 @@ export namespace Doc { return '/doc/' + (doc ? doc[Id] : ''); } - export function overlapping(doc1: Doc, doc2: Doc, clusterDistance: number) { - 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 }); - } - - export function isBrushedHighlightedDegree(doc: Doc) { - return Doc.IsHighlighted(doc) ? DocBrushStatus.highlighted : Doc.IsBrushedDegree(doc); + export function GetBrushHighlightStatus(doc: Doc) { + return Doc.IsHighlighted(doc) ? DocBrushStatus.highlighted : Doc.GetBrushStatus(doc); } export class DocBrush { BrushedDoc = new Set<Doc>(); @@ -1269,12 +1055,12 @@ export namespace Doc { return Doc.NativeWidth(doc, dataDoc, useDim) / (Doc.NativeHeight(doc, dataDoc, useDim) || 1); } export function NativeWidth(doc?: Doc, dataDoc?: Doc, useWidth?: boolean) { - return !doc ? 0 : NumCast(doc._nativeWidth, NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeWidth'], useWidth ? doc[Width]() : 0)); + return !doc ? 0 : NumCast(doc._nativeWidth, NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeWidth'], useWidth ? NumCast(doc._width) : 0)); } export function NativeHeight(doc?: Doc, dataDoc?: Doc, useHeight?: boolean) { if (!doc) return 0; - const nheight = (Doc.NativeWidth(doc, dataDoc, useHeight) * doc[Height]()) / doc[Width](); - const dheight = NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeHeight'], useHeight ? doc[Height]() : 0); + const nheight = (Doc.NativeWidth(doc, dataDoc, useHeight) * NumCast(doc._height)) / NumCast(doc._width); + const dheight = NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeHeight'], useHeight ? NumCast(doc._height) : 0); return NumCast(doc._nativeHeight, nheight || dheight); } export function SetNativeWidth(doc: Doc, width: number | undefined, fieldKey?: string) { @@ -1337,36 +1123,22 @@ export namespace Doc { highlighted = 3, } // returns 'how' a Doc has been brushed over - whether the document itself was brushed, it's prototype, or neither - export function IsBrushedDegree(doc: Doc) { + export function GetBrushStatus(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, unbrush = false) { - if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc; - brushManager.brushDoc(doc, unbrush); - brushManager.brushDoc(Doc.GetProto(doc), unbrush); + if (doc && GetEffectiveAcl(doc) !== AclPrivate && GetEffectiveAcl(Doc.GetProto(doc)) !== AclPrivate) { + brushManager.brushDoc(doc, unbrush); + brushManager.brushDoc(Doc.GetProto(doc), unbrush); + } return doc; } export function UnBrushDoc(doc: Doc) { return BrushDoc(doc, true); } - - export function LinkEndpoint(linkDoc: Doc, anchorDoc: Doc) { - const linkAnchor2 = DocCast(linkDoc.link_anchor_2); - const linkAnchor1 = DocCast(linkDoc.link_anchor_1); - if (linkDoc.link_matchEmbeddings) { - return [linkAnchor2, linkAnchor2.annotationOn].includes(anchorDoc) ? '2' : '1'; - } - if (Doc.AreProtosEqual(linkAnchor2, anchorDoc) || Doc.AreProtosEqual(linkAnchor2.annotationOn as Doc, anchorDoc)) return '2'; - return Doc.AreProtosEqual(linkAnchor1, anchorDoc) || Doc.AreProtosEqual(linkAnchor1.annotationOn as Doc, anchorDoc) ? '1' : '2'; - } - - export function linkFollowUnhighlight() { - clearTimeout(UnhighlightTimer); - UnhighlightWatchers.forEach(watcher => watcher()); - UnhighlightWatchers.length = 0; - highlightedDocs.forEach(doc => Doc.UnHighlightDoc(doc)); - document.removeEventListener('pointerdown', linkFollowUnhighlight); + export function UnBrushAllDocs() { + Array.from(brushManager.BrushedDoc).forEach(action(doc => (doc[Brushed] = false))); } let UnhighlightWatchers: (() => void)[] = []; @@ -1376,6 +1148,13 @@ export namespace Doc { UnhighlightWatchers.push(watcher); } else watcher(); } + export function linkFollowUnhighlight() { + clearTimeout(UnhighlightTimer); + UnhighlightWatchers.forEach(watcher => watcher()); + UnhighlightWatchers.length = 0; + highlightedDocs.forEach(doc => Doc.UnHighlightDoc(doc)); + document.removeEventListener('pointerdown', linkFollowUnhighlight); + } export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true, presentation_effect?: Doc) { linkFollowUnhighlight(); (destDoc instanceof Doc ? [destDoc] : destDoc).forEach(doc => Doc.HighlightDoc(doc, dataAndDisplayDocs, presentation_effect)); @@ -1415,9 +1194,6 @@ export namespace Doc { }); }); } - export function UnBrushAllDocs() { - Array.from(brushManager.BrushedDoc).forEach(action(doc => (doc[Brushed] = false))); - } export function getDocTemplate(doc?: Doc) { return !doc @@ -1433,41 +1209,6 @@ export namespace Doc { : undefined; } - export function matchFieldValue(doc: Doc, key: string, value: any): boolean { - 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("...")) - const allLinks = LinkManager.Instance.getAllRelatedLinks(doc); - const matchLink = (value: string, anchor: Doc) => { - const linkedToExp = value?.split('='); - if (linkedToExp.length === 1) return Field.toScriptString(anchor) === value; - return Field.toScriptString(DocCast(anchor[linkedToExp[0]])) === linkedToExp[1]; - }; - // prettier-ignore - return (value === Doc.FilterNone && !allLinks.length) || - (value === Doc.FilterAny && !!allLinks.length) || - (allLinks.some(link => matchLink(value,DocCast(link.link_anchor_1)) || - matchLink(value,DocCast(link.link_anchor_2)) )); - } - if (typeof value === 'string') { - value = value.replace(`,${Utils.noRecursionHack}`, ''); - } - const fieldVal = doc[key]; - // prettier-ignore - if ((value === Doc.FilterAny && fieldVal !== undefined) || - (value === Doc.FilterNone && fieldVal === undefined)) { - return true; - } - 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 - } - export function deiconifyView(doc: Doc) { StrCast(doc.layout_fieldKey).split('_')[1] === 'icon' && setNativeView(doc); } @@ -1603,15 +1344,25 @@ export namespace Doc { } // prettier-ignore - export function toIcon(doc?: Doc, isOpen?: boolean) { - switch (isOpen !== undefined ? DocumentType.COL: StrCast(doc?.type)) { + export function toIcon(doc?: Doc, isOpen?: Opt<boolean>) { + if (isOpen) return doc?.isFolder ? 'chevron-down' : 'folder-open'; + switch (StrCast(doc?.type)) { case DocumentType.IMG: return 'image'; case DocumentType.COMPARISON: return 'columns'; case DocumentType.RTF: return 'sticky-note'; case DocumentType.COL: - const folder: IconProp = isOpen === true ? 'folder-open' : isOpen === false ? 'folder' : doc?.title==='Untitled Collection'? 'object-group': 'chalkboard'; - const chevron: IconProp = isOpen === true ? 'chevron-down' : isOpen === false ? 'chevron-right' : 'question'; - return !doc?.isFolder ? folder : chevron; + if (doc?.isFolder) { + switch (doc.type_collection) { + default: return isOpen === false ? 'chevron-right' : 'question'; + } // prettier-ignore + } + switch (doc?.type_collection) { + case CollectionViewType.Freeform : return 'object-group'; + case CollectionViewType.NoteTaking : return 'chalkboard'; + case CollectionViewType.Schema : return 'table-cells'; + case CollectionViewType.Docking: return 'solar-panel'; + default: return 'folder'; + } // prettier-ignore case DocumentType.WEB: return 'globe-asia'; case DocumentType.SCREENSHOT: return 'photo-video'; case DocumentType.WEBCAM: return 'video'; @@ -1628,9 +1379,9 @@ export namespace Doc { case DocumentType.DATAVIZ: return 'chart-bar'; case DocumentType.EQUATION: return 'calculator'; case DocumentType.SIMULATION: return 'rocket'; - case DocumentType.CONFIG: return 'question-circle'; - default: return 'question'; + case DocumentType.CONFIG: return 'folder-closed'; } + return 'question'; } /// @@ -1839,14 +1590,13 @@ ScriptingGlobals.add(function sameDocs(doc1: any, doc2: any) { ScriptingGlobals.add(function assignDoc(doc: Doc, field: string, id: string) { return Doc.assignDocToField(doc, field, id); }); -ScriptingGlobals.add(function docCast(doc: FieldResult): any { - return DocCastAsync(doc); +ScriptingGlobals.add(function docCastAsync(doc: FieldResult): any { + return Cast(doc, Doc); }); ScriptingGlobals.add(function activePresentationItem() { const curPres = Doc.ActivePresentation; return curPres && DocListCast(curPres[Doc.LayoutFieldKey(curPres)])[NumCast(curPres._itemIndex)]; }); - ScriptingGlobals.add(function setDocFilter(container: Doc, key: string, value: any, modifiers: 'match' | 'check' | 'x' | 'remove') { Doc.setDocFilter(container, key, value, modifiers); }); diff --git a/src/fields/RichTextUtils.ts b/src/fields/RichTextUtils.ts index 5ecf25e08..dfd02dbc0 100644 --- a/src/fields/RichTextUtils.ts +++ b/src/fields/RichTextUtils.ts @@ -275,7 +275,7 @@ export namespace RichTextUtils { } else { docId = backingDocId; } - return schema.node('image', { src, agnostic, width, docId, float: null, location: 'add:right' }); + return schema.node('image', { src, agnostic, width, docId, float: null }); }; const textNode = (schema: any, run: docs_v1.Schema$TextRun) => { diff --git a/src/fields/util.ts b/src/fields/util.ts index 28db77c65..ca02284da 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -234,7 +234,7 @@ function getEffectiveAcl(target: any, user?: string): symbol { * @param layoutOnly just sets the layout doc's ACL (unless the data doc has no entry for the ACL, in which case it will be set as well) */ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc, visited?: Doc[], allowUpgrade?: boolean, layoutOnly = false) { - const selfKey = `acl-${Doc.CurrentUserEmailNormalized}`; + const selfKey = `acl-${normalizeEmail(Doc.CurrentUserEmail)}`; if (!visited) visited = [] as Doc[]; if (!target || visited.includes(target) || key === selfKey) return; visited.push(target); |