diff options
author | Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> | 2025-03-11 17:43:05 +0100 |
---|---|---|
committer | Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> | 2025-03-11 17:43:05 +0100 |
commit | fa937182bc93aa2c6faadda80ea998cdfd479b4e (patch) | |
tree | cba8e16edcccc6fd2932173484ac444cb79abea2 /src/fields/Doc.ts | |
parent | cf91c46cfec6e3e36b9184764016f9c1b5c997d4 (diff) | |
parent | 04669ffeb163688c7aefd7b5face7998252abdca (diff) |
Merge branch 'master' of https://github.com/brown-dash/Dash-Web into DocCreatorMenu-work
Diffstat (limited to 'src/fields/Doc.ts')
-rw-r--r-- | src/fields/Doc.ts | 79 |
1 files changed, 54 insertions, 25 deletions
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 3f8de2988..bb7df75fc 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -7,14 +7,14 @@ import { CollectionViewType, DocumentType } from '../client/documents/DocumentTy import { scriptingGlobal, ScriptingGlobals } from '../client/util/ScriptingGlobals'; import { afterDocDeserialize, autoObject, Deserializable, SerializationHelper } from '../client/util/SerializationHelper'; import { undoable, UndoManager } from '../client/util/UndoManager'; -import { ClientUtils, incrementTitleCopy } from '../ClientUtils'; +import { ClientUtils, imageUrlToBase64, incrementTitleCopy } from '../ClientUtils'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, Animation, AudioPlay, Brushed, CachedUpdates, DirectLinks, DocAcl, DocCss, DocData, DocLayout, DocViews, FieldKeys, FieldTuples, ForceServerWrite, Height, Highlight, Initializing, Self, SelfProxy, TransitionTimer, UpdatingFromServer, Width } from './DocSymbols'; // prettier-ignore import { Copy, FieldChanged, HandleUpdate, Id, Parent, ToJavascriptString, ToScriptString, ToString } from './FieldSymbols'; -import { InkTool } from './InkField'; +import { InkEraserTool, InkInkTool, InkTool } from './InkField'; import { List } from './List'; import { ObjectField, serverOpType } from './ObjectField'; import { PrefetchProxy, ProxyField } from './Proxy'; @@ -22,8 +22,9 @@ import { FieldId, RefField } from './RefField'; import { RichTextField } from './RichTextField'; import { listSpec } from './Schema'; import { ComputedField, ScriptField } from './ScriptField'; -import { BoolCast, Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor, toList } from './Types'; +import { BoolCast, Cast, DocCast, FieldValue, ImageCastWithSuffix, NumCast, RTFCast, StrCast, ToConstructor, toList } from './Types'; import { containedFieldChangedHandler, deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, setter, SharingPermissions } from './util'; +import { gptImageLabel } from '../client/apis/gpt/GPT'; export let ObjGetRefField: (id: string, force?: boolean) => Promise<Doc | undefined>; export let ObjGetRefFields: (ids: string[]) => Promise<Map<string, Doc | undefined>>; @@ -97,9 +98,8 @@ export namespace Field { }); return script; } - export function toString(fieldIn: unknown) { - const field = fieldIn as FieldType; - if (typeof field === 'string' || typeof field === 'number' || typeof field === 'boolean') return String(field); + export function toString(field: FieldResult<FieldType> | FieldType | undefined) { + if (field instanceof Promise || typeof field === 'string' || typeof field === 'number' || typeof field === 'boolean') return String(field); return field?.[ToString]?.() || ''; } export function IsField(field: unknown): field is FieldType; @@ -111,7 +111,7 @@ export namespace Field { export function Copy(field: unknown) { return field instanceof ObjectField ? ObjectField.MakeCopy(field) : (field as FieldType); } - UndoManager.SetFieldPrinter(toString); + UndoManager.SetFieldPrinter((val: unknown) => (IsField(val) ? toString(val) : '')); } export type FieldType = number | string | boolean | ObjectField | RefField; export type Opt<T> = T | undefined; @@ -237,7 +237,7 @@ export class Doc extends RefField { public static get MyPublishedDocs() { return DocListCast(Doc.ActiveDashboard?.myPublishedDocs).concat(DocListCast(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 MyAnnos() { return DocCast(Doc.UserDoc().myAnnos); } // prettier-ignore + public static get MyStickers() { return DocCast(Doc.UserDoc().myStickers); } // prettier-ignore public static get MyLightboxDrawings() { return DocCast(Doc.UserDoc().myLightboxDrawings); } // prettier-ignore public static get MyImports() { return DocCast(Doc.UserDoc().myImports); } // prettier-ignore public static get MyFilesystem() { return DocCast(Doc.UserDoc().myFilesystem); } // prettier-ignore @@ -254,6 +254,10 @@ export class Doc extends RefField { 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 ActiveInk(): InkInkTool { return StrCast(Doc.UserDoc().activeInkTool, InkTool.None) as InkInkTool; } // prettier-ignore + public static set ActiveInk(tool:InkInkTool){ Doc.UserDoc().activeInkTool = tool; } // prettier-ignore + public static get ActiveEraser(): InkEraserTool { return StrCast(Doc.UserDoc().activeEraserTool, InkTool.None) as InkEraserTool; } // prettier-ignore + public static set ActiveEraser(tool:InkEraserTool){ Doc.UserDoc().activeEraserTool = 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 @@ -337,7 +341,6 @@ export class Doc extends RefField { if (!id || forceSave) { 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 } @@ -464,13 +467,7 @@ export class Doc extends RefField { }); } } - -// eslint-disable-next-line no-redeclare export namespace Doc { - export let SelectOnLoad: Doc | undefined; - export function SetSelectOnLoad(doc: Doc | undefined) { - SelectOnLoad = doc; - } export let DocDragDataName: string = ''; export function SetDocDragDataName(name: string) { DocDragDataName = name; @@ -661,7 +658,6 @@ export namespace Doc { if (reversed) list.splice(0, 0, doc); else list.push(doc); } else { - // eslint-disable-next-line no-lonely-if if (reversed) list.splice(before ? list.length - ind + 1 : list.length - ind, 0, doc); else list.splice(before ? ind : ind + 1, 0, doc); } @@ -965,6 +961,19 @@ export namespace Doc { } } else if (field instanceof PrefetchProxy) { Doc.FindReferences(field.value, references, system); + } else if (field instanceof RichTextField) { + const re = /"docId"\s*:\s*"(.*?)"/g; + let match: string[] | null; + while ((match = re.exec(field.Data)) !== null) { + const urlString = match[1]; + if (urlString) { + const rdoc = DocServer.GetCachedRefField(urlString); + if (rdoc) { + references.add(rdoc); + Doc.FindReferences(rdoc, references, system); + } + } + } } } else if (field instanceof Promise) { // eslint-disable-next-line no-debugger @@ -995,7 +1004,7 @@ export namespace Doc { } else if (field instanceof ObjectField) { const docAtKey = doc[key]; copy[key] = - docAtKey instanceof Doc && key.includes('layout[') + docAtKey instanceof Doc && (key.includes('layout[') || docAtKey.cloneOnCopy) ? new ProxyField(Doc.MakeCopy(docAtKey)) // copy the expanded render template : ObjectField.MakeCopy(field); } else if (field instanceof Promise) { @@ -1194,7 +1203,6 @@ export namespace Doc { return Cast(Doc.UserDoc().myLinkDatabase, Doc, null); } export function SetUserDoc(doc: Doc) { - // eslint-disable-next-line no-return-assign return (manager._user_doc = doc); } @@ -1369,6 +1377,13 @@ export namespace Doc { export const FilterAny = '--any--'; export const FilterNone = '--undefined--'; + export function hasDocFilter(container: Opt<Doc>, key: string, value: string | undefined, fieldPrefix?: string) { + if (!container) return; + const filterField = '_' + (fieldPrefix ? fieldPrefix + '_' : '') + 'childFilters'; + const childFilters = StrListCast(container[filterField]); + return childFilters.some(filter => filter.split(FilterSep)[0] === key && (value === undefined || value === Doc.FilterAny || filter.split(FilterSep)[1] === value)); + } + // 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 @@ -1379,8 +1394,8 @@ export namespace Doc { 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() || value === Doc.FilterAny || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) { + if (fields[2] === modifiers && modifiers && (fields[1] === value?.toString() || value === Doc.FilterAny)) { // eslint-disable-next-line no-param-reassign if (toggle) modifiers = 'remove'; else return; @@ -1449,6 +1464,25 @@ export namespace Doc { }); } + /** + * text description of a Doc. RTF documents will have just their text and pdf documents will have the first 50 words. + * Image documents are converted to bse64 and gpt generates a description for them. all other documents use their title. + * @param doc + * @returns + */ + export function getDescription(doc: Doc) { + const curDescription = StrCast(doc[DocData][Doc.LayoutFieldKey(doc) + '_description']); + const docText = (async (tdoc:Doc) => { + switch (tdoc.type) { + case DocumentType.PDF: return curDescription || StrCast(tdoc.text).split(/\s+/).slice(0, 50).join(' '); // first 50 words of pdf text + case DocumentType.IMG: return curDescription || imageUrlToBase64(ImageCastWithSuffix(Doc.LayoutField(tdoc), '_o') ?? '') + .then(hrefBase64 => gptImageLabel(hrefBase64, 'Give three to five labels to describe this image.')); + case DocumentType.RTF: return RTFCast(tdoc[Doc.LayoutFieldKey(tdoc)]).Text; + default: return StrCast(tdoc.title).startsWith("Untitled") ? "" : StrCast(tdoc.title); + }}); // prettier-ignore + return docText(doc).then(text => (doc[DocData][Doc.LayoutFieldKey(doc) + '_description'] = text)); + } + // prettier-ignore export function toIcon(doc?: Doc, isOpen?: Opt<boolean>) { if (isOpen) return doc?.isFolder ? 'chevron-down' : 'folder-open'; @@ -1483,7 +1517,6 @@ export namespace Doc { case DocumentType.MAP: return 'map-marker-alt'; case DocumentType.DATAVIZ: return 'chart-bar'; case DocumentType.EQUATION: return 'calculator'; - case DocumentType.SIMULATION: return 'rocket'; case DocumentType.CONFIG: return 'folder-closed'; default: } @@ -1763,7 +1796,3 @@ ScriptingGlobals.add(function setDocRangeFilter(container: Doc, key: string, ran ScriptingGlobals.add(function toJavascriptString(str: string) { return Field.toJavascriptString(str as FieldType); }); -// eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function RtfField() { - return RichTextField.RTFfield(); -}); |