From 5dda7cf8c9244a5d00e459d539d6178592b40336 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 12 Mar 2025 18:12:27 -0400 Subject: made @... create dashField views instead of [@..]. minor cleanup of dashFieldView and schemaCellField. made schemaCellField call focus() when SetIsFocused is called so that dashFieldView boxes are editable when clicked. Made overlay of documentIcons appear whenever cells are focused and disappear on blur. --- src/client/views/nodes/formattedText/RichTextRules.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client/views/nodes/formattedText/RichTextRules.ts') diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index c332c592b..f3ec6cc9d 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -319,10 +319,10 @@ export class RichTextRules { }), // create a text display of a metadata field on this or another document, or create a hyperlink portal to another document - // [@{this,doctitle,}.fieldKey{:,=,:=,=:=}value] - // [@{this,doctitle,}.fieldKey] + // @{this,doctitle,}.fieldKey{:,=,:=,=:=}value + // @{this,doctitle,}.fieldKey new InputRule( - /\[(@|@this\.|@[a-zA-Z_? \-0-9]+\.)([a-zA-Z_?\-0-9]+)((:|=|:=|=:=)([a-zA-Z,_().@?+\-*/ 0-9()]*))?\]/, + /(@|@this\.|@[a-zA-Z_? \-0-9]+\.)([a-zA-Z_?\-0-9]+)((:|=|:=|=:=)([a-zA-Z,_().@?+\-*/ 0-9()]*))?\s/, (state, match, start, end) => { const docTitle = match[1].substring(1).replace(/\.$/, ''); const fieldKey = match[2]; -- cgit v1.2.3-70-g09d2 From 7e4d793eaa7e5b6b564355a11fa02a5611645f20 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 21 Mar 2025 18:58:21 -0400 Subject: trying to improve how data / layout / root and templtae docs are accessed. --- src/client/documents/DocUtils.ts | 11 +++--- src/client/util/CalendarManager.tsx | 11 ++---- src/client/util/CurrentUserUtils.ts | 17 +++++---- src/client/util/DictationManager.ts | 6 ++-- src/client/util/DocumentManager.ts | 11 ++---- src/client/util/DragManager.ts | 5 +-- src/client/util/History.ts | 2 +- src/client/util/Import & Export/ImageUtils.ts | 14 ++++---- src/client/views/DashboardView.tsx | 26 +++++++------- src/client/views/DocComponent.tsx | 14 ++++---- src/client/views/DocumentDecorations.tsx | 4 +-- src/client/views/FilterPanel.tsx | 3 +- src/client/views/InkStrokeProperties.ts | 3 +- src/client/views/MainView.tsx | 3 +- src/client/views/MarqueeAnnotator.tsx | 22 ++++++------ src/client/views/PinFuncs.ts | 3 +- src/client/views/PropertiesButtons.tsx | 6 ++-- src/client/views/PropertiesView.tsx | 42 +++++++++++----------- src/client/views/ScriptBox.tsx | 6 ++-- .../views/collections/CollectionDockingView.tsx | 13 ++++--- src/client/views/nodes/DocumentView.tsx | 36 +++++++++---------- src/client/views/nodes/KeyValueBox.tsx | 36 +++++++++++-------- src/client/views/nodes/KeyValuePair.tsx | 18 +++++----- .../views/nodes/formattedText/FormattedTextBox.tsx | 9 +++-- .../views/nodes/formattedText/RichTextRules.ts | 36 ++++++++----------- src/client/views/nodes/trails/PresBox.tsx | 10 +++--- src/client/views/pdf/PDFViewer.tsx | 2 +- src/client/views/search/FaceRecognitionHandler.tsx | 21 ++++++----- src/client/views/search/SearchBox.tsx | 1 - src/client/views/smartdraw/DrawingFillHandler.tsx | 6 ++-- src/fields/Doc.ts | 14 +++++--- src/fields/util.ts | 10 ++++++ 32 files changed, 203 insertions(+), 218 deletions(-) (limited to 'src/client/views/nodes/formattedText/RichTextRules.ts') diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts index 1c7ccadd1..13f6f6920 100644 --- a/src/client/documents/DocUtils.ts +++ b/src/client/documents/DocUtils.ts @@ -8,7 +8,6 @@ import * as JSZipUtils from '../../JSZipUtils'; import { decycle } from '../../decycler/decycler'; import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Field, FieldResult, FieldType, LinkedTo, Opt, StrListCast } from '../../fields/Doc'; -import { DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { InkData, InkDataFieldName, InkField } from '../../fields/InkField'; import { List, ListFieldName } from '../../fields/List'; @@ -383,10 +382,10 @@ export namespace DocUtils { event: undoable(() => { const newDoc = DocUtils.copyDragFactory(dragDoc); if (newDoc) { - newDoc.author = ClientUtils.CurrentUserEmail(); - newDoc.x = x; - newDoc.y = y; - newDoc[DocData].backgroundColor = Doc.UserDoc().textBackgroundColor; + newDoc._author = ClientUtils.CurrentUserEmail(); + newDoc._x = x; + newDoc._y = y; + newDoc.$backgroundColor = Doc.UserDoc().textBackgroundColor; DocumentView.SetSelectOnLoad(newDoc); if (pivotField) { newDoc[pivotField] = pivotValue; @@ -745,7 +744,7 @@ export namespace DocUtils { if (defaultTextTemplate) { tbox.layout_fieldKey = 'layout_' + StrCast(defaultTextTemplate.title); Doc.GetProto(tbox)[StrCast(tbox.layout_fieldKey)] = defaultTextTemplate; // set the text doc's layout to render with the text template - tbox[DocData].proto = defaultTextTemplate; // and also set the text doc to inherit from the template (this allows the template to specify default field values) + tbox.$proto = defaultTextTemplate; // and also set the text doc to inherit from the template (this allows the template to specify default field values) } return tbox; } diff --git a/src/client/util/CalendarManager.tsx b/src/client/util/CalendarManager.tsx index d28b3a2c9..a0db4e32e 100644 --- a/src/client/util/CalendarManager.tsx +++ b/src/client/util/CalendarManager.tsx @@ -8,7 +8,6 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import Select from 'react-select'; import { Doc, DocListCast } from '../../fields/Doc'; -import { DocData } from '../../fields/DocSymbols'; import { StrCast } from '../../fields/Types'; import { Docs } from '../documents/Documents'; import { MainViewModal } from '../views/MainViewModal'; @@ -51,8 +50,6 @@ export class CalendarManager extends ObservableReactComponent { @observable private targetDocView: DocumentView | undefined = undefined; // the DocumentView of the target doc @observable private dialogueBoxOpacity = 1; // for the modal - @observable private layoutDocAcls: boolean = false; // whether the layout doc or data doc's acls are to be used - @observable private creationType: CreationType = 'new-calendar'; @observable private existingCalendars: Doc[] = DocListCast(Doc.MyCalendars?.data); @@ -97,7 +94,6 @@ export class CalendarManager extends ObservableReactComponent { }), 500 ); - this.layoutDocAcls = false; }); constructor(props: object) { @@ -122,9 +118,8 @@ export class CalendarManager extends ObservableReactComponent { // TODO: Make undoable private addToCalendar = () => { const docs = DocumentView.Selected().length < 2 ? [this.targetDoc] : DocumentView.Selected().map(docView => docView.Document); - const targetDoc = this.layoutDocAcls ? docs[0] : docs[0]?.[DocData]; // doc to add to calendar + const targetDoc = docs[0]; // doc to add to calendar - console.log(targetDoc); if (targetDoc) { let calendar: Doc; if (this.creationType === 'new-calendar') { @@ -234,7 +229,7 @@ export class CalendarManager extends ObservableReactComponent { @computed get calendarInterface() { const docs = DocumentView.Selected().length < 2 ? [this.targetDoc] : DocumentView.Selected().map(docView => docView.Document); - const targetDoc = this.layoutDocAcls ? docs[0] : docs[0]?.[DocData]; + const targetDoc = docs[0]; return (
{
Select a date range:
- this.setSelectedDateRange(v)} /> + v && this.setSelectedDateRange(v)} />
{this.createButtonActive && ( diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 21e1d3e12..924041552 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -3,7 +3,6 @@ import { reaction, runInAction } from "mobx"; import * as rp from 'request-promise'; import { ClientUtils, OmitKeys } from "../../ClientUtils"; import { Doc, DocListCast, DocListCastAsync, FieldType, Opt } from "../../fields/Doc"; -import { DocData } from "../../fields/DocSymbols"; import { InkEraserTool, InkInkTool, InkProperty, InkTool } from "../../fields/InkField"; import { List } from "../../fields/List"; import { PrefetchProxy } from "../../fields/Proxy"; @@ -323,10 +322,10 @@ export class CurrentUserUtils { type: 'scatter' }`); const slide = Docs.Create.TextDocument("", opts); - slide[DocData].text = rtfield; - slide[DocData].layout_textPainted = ``; - slide[DocData]._type_collection = CollectionViewType.Freeform; - slide.onPaint = ScriptField.MakeScript(`toggleDetail(documentView, "textPainted")`, {documentView:"any"}); + slide.$text = rtfield; + slide.$layout_textPainted = ``; + slide.$type_collection = CollectionViewType.Freeform; + slide._onPaint = ScriptField.MakeScript(`toggleDetail(documentView, "textPainted")`, {documentView:"any"}); return slide; } const mermaidsApi = () => { @@ -374,10 +373,10 @@ pie title Minerals in my tap water "Potassium" : 50 "Magnesium" : 10.01`); const slide = Docs.Create.TextDocument("", opts); - slide[DocData].text = rtfield; - slide[DocData].layout_textPainted = ``; - slide[DocData]._type_collection = CollectionViewType.Freeform; - slide.onPaint = ScriptField.MakeScript(`toggleDetail(documentView, "textPainted")`, {documentView:"any"}); + slide.$text = rtfield; + slide.$layout_textPainted = ``; + slide.$_type_collection = CollectionViewType.Freeform; + slide._onPaint = ScriptField.MakeScript(`toggleDetail(documentView, "textPainted")`, {documentView:"any"}); return slide; } plotlyApi(); mermaidsApi(); diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index 897366757..44fbda319 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -2,7 +2,6 @@ import * as interpreter from 'words-to-numbers'; import { ClientUtils } from '../../ClientUtils'; import { Doc, Opt } from '../../fields/Doc'; -import { DocData } from '../../fields/DocSymbols'; import { List } from '../../fields/List'; import { RichTextField } from '../../fields/RichTextField'; import { listSpec } from '../../fields/Schema'; @@ -339,13 +338,12 @@ export namespace DictationManager { { action: (target: DocumentView) => { const newBox = Docs.Create.TextDocument('', { _width: 400, _height: 200, title: 'My Outline', _layout_autoHeight: true }); - const proto = newBox[DocData]; const prompt = 'Press alt + r to start dictating here...'; const head = 3; const anchor = head + prompt.length; const proseMirrorState = `{"doc":{"type":"doc","content":[{"type":"ordered_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","text":"${prompt}"}]}]}]}]},"selection":{"type":"text","anchor":${anchor},"head":${head}}}`; - proto.data = new RichTextField(proseMirrorState, prompt); - proto.backgroundColor = '#eeffff'; + newBox.$data = new RichTextField(proseMirrorState, prompt); + newBox.$backgroundColor = '#eeffff'; target.props.addDocTab(newBox, OpenWhere.addRight); }, }, diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index e33449782..5ce005811 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -2,7 +2,6 @@ import { Howl } from 'howler'; import { action, computed, makeObservable, observable, ObservableSet, observe } from 'mobx'; import { Doc, Opt } from '../../fields/Doc'; import { Animation, DocData } from '../../fields/DocSymbols'; -import { Id } from '../../fields/FieldSymbols'; import { listSpec } from '../../fields/Schema'; import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { AudioField } from '../../fields/URLField'; @@ -108,16 +107,16 @@ export class DocumentManager { }); // gets all views - public getDocumentViewsById(id: string) { + public getAllDocumentViews(doc: Doc) { const toReturn: DocumentView[] = []; DocumentManager.Instance.DocumentViews.forEach(view => { - if (view.Document[Id] === id) { + if (view.Document === doc) { toReturn.push(view); } }); if (toReturn.length === 0) { DocumentManager.Instance.DocumentViews.forEach(view => { - if (view.Document[DocData]?.[Id] === id) { + if (view.Document[DocData] === doc) { toReturn.push(view); } }); @@ -125,10 +124,6 @@ export class DocumentManager { return toReturn; } - public getAllDocumentViews(doc: Doc) { - return this.getDocumentViewsById(doc[Id]); - } - public getDocumentView(target: Doc | undefined, preferredCollection?: DocumentView): DocumentView | undefined { const docViewArray = DocumentManager.Instance.DocumentViews; const passes = !target ? [] : preferredCollection ? [preferredCollection, undefined] : [undefined]; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 2a7859f09..e2e4c0fe4 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -280,11 +280,12 @@ export namespace DragManager { export function StartButtonDrag(eles: HTMLElement[], script: string, title: string, vars: { [name: string]: FieldType }, params: string[], initialize: (button: Doc) => void, downX: number, downY: number, options?: DragOptions) { const finishDrag = (e: DragCompleteEvent) => { const bd = Docs.Create.ButtonDocument({ toolTip: title, z: 1, _width: 150, _height: 50, title, onClick: ScriptField.MakeScript(script) }); + const bdData = bd[DocData]; params.forEach(p => { - Object.keys(vars).indexOf(p) !== -1 && (bd[DocData][p] = new PrefetchProxy(vars[p] as Doc)); + Object.keys(vars).indexOf(p) !== -1 && (bdData[p] = new PrefetchProxy(vars[p] as Doc)); }); // copy all "captured" arguments into document parameterfields initialize?.(bd); - bd[DocData]['onClick-paramFieldKeys'] = new List(params); + bd.$onClick_paramFieldKeys = new List(params); e.docDragData && (e.docDragData.droppedDocuments = [bd]); return e; }; diff --git a/src/client/util/History.ts b/src/client/util/History.ts index 9728e3177..0df0ec337 100644 --- a/src/client/util/History.ts +++ b/src/client/util/History.ts @@ -94,7 +94,7 @@ export namespace HistoryUtil { } if (Array.isArray(value)) { } else if (parser === true || parser === 'json') { - value = JSON.parse(value); + value = value === 'undefined' ? undefined : JSON.parse(value); } else if (parser === 'none') { } else { value = parser(value); diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts index 43807397f..9c32ca25a 100644 --- a/src/client/util/Import & Export/ImageUtils.ts +++ b/src/client/util/Import & Export/ImageUtils.ts @@ -1,6 +1,5 @@ import { ClientUtils } from '../../../ClientUtils'; import { Doc } from '../../../fields/Doc'; -import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; @@ -16,13 +15,12 @@ export namespace ImageUtils { export const AssignImgInfo = (document: Doc, data?: Upload.InspectionResults) => { if (data) { data.nativeWidth && (document._height = (NumCast(document._width) * data.nativeHeight) / data.nativeWidth); - const proto = document[DocData]; - const field = Doc.LayoutFieldKey(document); - proto[`${field}_nativeWidth`] = data.nativeWidth; - proto[`${field}_nativeHeight`] = data.nativeHeight; - proto[`${field}_path`] = data.source; - proto[`${field}_exif`] = JSON.stringify(data.exifData.data); - proto[`${field}_contentSize`] = data.contentSize ? data.contentSize : undefined; + const field = '$' + Doc.LayoutFieldKey(document); + document[`${field}_nativeWidth`] = data.nativeWidth; + document[`${field}_nativeHeight`] = data.nativeHeight; + document[`${field}_path`] = data.source; + document[`${field}_exif`] = JSON.stringify(data.exifData.data); + document[`${field}_contentSize`] = data.contentSize ? data.contentSize : undefined; } return document; }; diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 7f0118ed3..f61f6db18 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -6,7 +6,7 @@ import * as React from 'react'; import { FaPlus } from 'react-icons/fa'; import { ClientUtils } from '../../ClientUtils'; import { Doc, DocListCast } from '../../fields/Doc'; -import { AclPrivate, DocAcl, DocData } from '../../fields/DocSymbols'; +import { AclPrivate, DocAcl } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { List } from '../../fields/List'; import { PrefetchProxy } from '../../fields/Proxy'; @@ -113,7 +113,7 @@ export class DashboardView extends ObservableReactComponent { getDashboards = (whichGroup: DashboardGroup) => { if (whichGroup === DashboardGroup.MyDashboards) { - return DocListCast(Doc.MyDashboards.data).filter(dashboard => dashboard[DocData].author === ClientUtils.CurrentUserEmail()); + return DocListCast(Doc.MyDashboards.data).filter(dashboard => dashboard.$author === ClientUtils.CurrentUserEmail()); } return DocListCast(Doc.MySharedDocs.data_dashboards).filter(doc => doc.dockingConfig); }; @@ -226,7 +226,7 @@ export class DashboardView extends ObservableReactComponent { color={color} val={StrCast(dashboard.title)} setVal={val => { - dashboard[DocData].title = val; + dashboard.$title = val; }} /> {this.selectedDashboardGroup === DashboardGroup.SharedDashboards && this.isUnviewedSharedDashboard(dashboard) ?
unviewed
:
} @@ -403,8 +403,8 @@ export class DashboardView extends ObservableReactComponent { }, ], }; - if (dashboard.dockingConfig && dashboard.dockingConfig !== dashboard[DocData].dockingConfig) dashboard.dockingConfig = JSON.stringify(reset); - else Doc.SetInPlace(dashboard, 'dockingConfig', JSON.stringify(reset), true); + const dockingOnLayout = dashboard._dockingConfig && dashboard._dockingConfig !== dashboard.$dockingConfig; + dashboard[`${dockingOnLayout ? '_' : '$'}dockingConfig`] = JSON.stringify(reset); return reset; }; @@ -427,14 +427,14 @@ export class DashboardView extends ObservableReactComponent { Doc.AddDocToList(Doc.MyHeaderBar, 'data', freeformDoc, undefined, undefined, true); Doc.AddDocToList(Doc.MyDashboards, 'data', dashboardDoc); - dashboardDoc.pane_count = 1; - freeformDoc.embedContainer = dashboardDoc; - dashboardDoc.myOverlayDocs = new List(); - dashboardDoc[DocData].myPublishedDocs = new List(); - dashboardDoc[DocData].myTagCollections = new List(); - dashboardDoc[DocData].myUniqueFaces = new List(); - dashboardDoc[DocData].myTrails = DashboardView.SetupDashboardTrails(); - dashboardDoc[DocData].myCalendars = DashboardView.SetupDashboardCalendars(); + freeformDoc._embedContainer = dashboardDoc; + dashboardDoc.$myPaneCount = 1; + dashboardDoc.$myOverlayDocs = new List(); + dashboardDoc.$myPublishedDocs = new List(); + dashboardDoc.$myTagCollections = new List(); + dashboardDoc.$myUniqueFaces = new List(); + dashboardDoc.$myTrails = DashboardView.SetupDashboardTrails(); + dashboardDoc.$myCalendars = DashboardView.SetupDashboardCalendars(); // open this new dashboard Doc.ActiveDashboard = dashboardDoc; Doc.ActivePage = 'dashboard'; diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index e351e2dec..064906530 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -5,7 +5,7 @@ import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, DocData } from '../../fields/DocSymbols'; import { List } from '../../fields/List'; -import { toList } from '../../fields/Types'; +import { DocCast, toList } from '../../fields/Types'; import { GetEffectiveAcl, inheritParentAcls } from '../../fields/util'; import { DocumentType } from '../documents/DocumentTypes'; import { ObservableReactComponent } from './ObservableReactComponent'; @@ -35,14 +35,14 @@ export function DocComponent

() { * Rather, it specifies the shared properties of all layouts of the document (eg, x,y,) */ get Document() { - return this._props.Document; + return DocCast(this._props.Document.rootDocument, this._props.Document); } /** * This is the document being rendered. It may be a template so it may or may no inherit from the data doc. */ @computed get layoutDoc() { - return this._props.LayoutTemplateString ? this.Document : Doc.Layout(this.Document, this._props.LayoutTemplate?.()); + return this._props.LayoutTemplateString ? this.Document : Doc.Layout(this._props.Document, this._props.LayoutTemplate?.()); } /** @@ -80,13 +80,13 @@ export function ViewBoxBaseComponent

() { * Rather, it specifies the shared properties of all layouts of the document (eg, x,y,) */ get Document() { - return this._props.Document; + return DocCast(this._props.Document.rootDocument, this._props.Document); } /** * This is the document being rendered. It may be a template so it may or may no inherit from the data doc. */ @computed get layoutDoc() { - return Doc.Layout(this.Document); + return Doc.Layout(this._props.Document); } /** @@ -138,13 +138,13 @@ export function ViewBoxAnnotatableComponent

() { * Rather, it specifies the shared properties of all layouts of the document (eg, x,y,) */ @computed get Document() { - return this._props.Document; + return DocCast(this._props.Document.rootDocument, this._props.Document); } /** * This is the document being rendered. It may be a template so it may or may no inherit from the data doc. */ @computed get layoutDoc() { - return Doc.Layout(this.Document); + return Doc.Layout(this._props.Document); } /** diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 54e050f9f..92b4d6fbf 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -127,7 +127,7 @@ export class DocumentDecorations extends ObservableReactComponent#')) { DocumentView.SelectedDocs().forEach(doc => { - doc[DocData].onViewMounted = ScriptField.MakeScript(`updateTagsCollection(this)`); + doc.$onViewMounted = ScriptField.MakeScript(`updateTagsCollection(this)`); }); } const titleFieldKey = this._titleControlString.substring(1); @@ -621,7 +621,7 @@ export class DocumentDecorations extends ObservableReactComponent ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] })) .forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => { - doc[DocData].data = new InkField(inkPts.map( + doc.$data = new InkField(inkPts.map( (ipt) => ({// (new x — oldx) + newWidth * (oldxpoint /oldWidth) X: NumCast(doc.x) - x + (NumCast(doc.width) * ipt.X) / width, Y: NumCast(doc.y) - y + (NumCast(doc.height) * ipt.Y) / height, diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx index 99738052d..4fc8d7a68 100644 --- a/src/client/views/FilterPanel.tsx +++ b/src/client/views/FilterPanel.tsx @@ -9,7 +9,6 @@ import { Handles, Rail, Slider, Ticks, Tracks } from 'react-compound-slider'; import { AiOutlineMinusSquare, AiOutlinePlusSquare } from 'react-icons/ai'; import { CiCircleRemove } from 'react-icons/ci'; import { Doc, DocListCast, Field, FieldType, LinkedTo, StrListCast } from '../../fields/Doc'; -import { DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { List } from '../../fields/List'; import { RichTextField } from '../../fields/RichTextField'; @@ -89,7 +88,7 @@ const HotKeyIconButton: React.FC = observer(({ hotKey /*, sel key={icon.toString()} onClick={undoable(e => { e.stopPropagation; - hotKey[DocData].icon = icon.toString(); + hotKey.$icon = icon.toString(); }, '')} className="icon-panel-button"> diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index 358274f0e..6854476e2 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -3,7 +3,6 @@ import * as fitCurve from 'fit-curve'; import * as _ from 'lodash'; import { action, makeObservable, observable, reaction, runInAction } from 'mobx'; import { Doc, NumListCast, Opt } from '../../fields/Doc'; -import { DocData } from '../../fields/DocSymbols'; import { InkData, InkField, InkTool } from '../../fields/InkField'; import { List } from '../../fields/List'; import { listSpec } from '../../fields/Schema'; @@ -509,7 +508,7 @@ export class InkStrokeProperties { const inkStroke = inkView?.ComponentView as InkingStroke; const polylinePoints = this.sampleBezier(inkStroke?.inkScaledData().inkData ?? [])?.map(pt => [pt.x, pt.y]); if (polylinePoints) { - inkDoc[DocData].stroke = new InkField( + inkDoc.$stroke = new InkField( fitCurve.default(polylinePoints, tolerance) .reduce((cpts, bez) => ({n: cpts.push(...bez.map(cpt => ({X:cpt[0], Y:cpt[1]}))), cpts}).cpts, diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index ef8d0c197..e70f9e5ed 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -11,7 +11,6 @@ import '@dash/components/src/global/globalCssVariables.scss'; import { ClientUtils, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents } from '../../ClientUtils'; import { emptyFunction } from '../../Utils'; import { Doc, DocListCast, GetDocFromUrl, Opt, returnEmptyDoclist } from '../../fields/Doc'; -import { DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { DocCast, StrCast, toList } from '../../fields/Types'; import { DocServer } from '../DocServer'; @@ -849,7 +848,7 @@ export class MainView extends ObservableReactComponent { @action selectMenu = (button: Doc) => { - const title = StrCast(button[DocData].title); + const title = StrCast(button.$title); const willOpen = !this._leftMenuFlyoutWidth || this._panelContent !== title; this.closeFlyout(); if (willOpen) { diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index 3f4200dce..e4811a902 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -97,7 +97,6 @@ export class MarqueeAnnotator extends ObservableReactComponent' + this.props.Document.title, }); - const textRegionAnnoProto = textRegionAnno[DocData]; let minX = Number.MAX_VALUE; let maxX = -Number.MAX_VALUE; let minY = Number.MAX_VALUE; @@ -118,15 +117,15 @@ export class MarqueeAnnotator extends ObservableReactComponent(annoRects); - textRegionAnnoProto.opacity = 0; - textRegionAnnoProto.layout_unrendered = true; + textRegionAnno.$text_inlineAnnotations = new List(annoRects); + textRegionAnno.$opacity = 0; + textRegionAnno.$layout_unrendered = true; savedAnnoMap.clear(); return textRegionAnno; }; @@ -226,9 +225,8 @@ export class MarqueeAnnotator extends ObservableReactComponent { if (!dragEx.aborted && dragEx.linkDocument) { - const linkDocData = dragEx.linkDocument[DocData]; - linkDocData.link_relationship = 'cropped image'; - linkDocData.title = 'crop: ' + this.props.Document.title; + dragEx.linkDocument.$link_relationship = 'cropped image'; + dragEx.linkDocument.$title = 'crop: ' + this.props.Document.title; } }, }); diff --git a/src/client/views/PinFuncs.ts b/src/client/views/PinFuncs.ts index ab02c2d07..1ab8575a8 100644 --- a/src/client/views/PinFuncs.ts +++ b/src/client/views/PinFuncs.ts @@ -1,5 +1,4 @@ import { Doc, DocListCast, Field } from '../../fields/Doc'; -import { DocData } from '../../fields/DocSymbols'; import { Copy, Id } from '../../fields/FieldSymbols'; import { List } from '../../fields/List'; import { ObjectField } from '../../fields/ObjectField'; @@ -78,7 +77,7 @@ export function PinDocView(pinDocIn: Doc, pinProps: PinProps, targetDoc: Doc) { } if (pinProps.pinData.dataannos) { const fieldKey = Doc.LayoutFieldKey(targetDoc); - pinDoc.config_annotations = new List(DocListCast(targetDoc[DocData][fieldKey + '_annotations']).filter(doc => !doc.layout_unrendered)); + pinDoc.config_annotations = new List(DocListCast(targetDoc['$' + fieldKey + '_annotations']).filter(doc => !doc.layout_unrendered)); } if (pinProps.pinData.inkable) { pinDoc.config_fillColor = targetDoc.fillColor; diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 606fb17ed..2b4fe478e 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/no-unused-class-component-methods */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Dropdown, DropdownType, IListItemProps, Toggle, ToggleType, Type } from '@dash/components'; import { action, computed, observable } from 'mobx'; @@ -14,7 +13,6 @@ import { RxWidth } from 'react-icons/rx'; import { TbEditCircle, TbEditCircleOff, TbHandOff, TbHandStop, TbHighlight, TbHighlightOff } from 'react-icons/tb'; import { TfiBarChart } from 'react-icons/tfi'; import { Doc, Opt } from '../../fields/Doc'; -import { DocData } from '../../fields/DocSymbols'; import { ScriptField } from '../../fields/ScriptField'; import { BoolCast, ScriptCast, StrCast } from '../../fields/Types'; import { ImageField } from '../../fields/URLField'; @@ -134,8 +132,8 @@ export class PropertiesButtons extends React.Component { () => , (dv, doc) => { const on = !!doc.onPaint; - doc[DocData].onPaint = on ? undefined : ScriptField.MakeScript(`toggleDetail(documentView, "textPainted")`, { documentView: 'any' }); - doc[DocData].layout_textPainted = on ? undefined : ``; + doc.$onPaint = on ? undefined : ScriptField.MakeScript(`toggleDetail(documentView, "textPainted")`, { documentView: 'any' }); + doc.$layout_textPainted = on ? undefined : ``; } ); } diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 11adf7435..c72f958fc 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -282,7 +282,7 @@ export class PropertiesView extends ObservableReactComponent(tags) : undefined; + doc.$tags = tags.length ? new List(tags) : undefined; } return true; } @@ -498,7 +498,7 @@ export class PropertiesView extends ObservableReactComponent { let userOnDoc = true; @@ -777,7 +777,7 @@ export class PropertiesView extends ObservableReactComponent doc.layout_isSvg); + return this.containsInkDoc ? DocListCast(this.selectedDoc.$data) : DocumentView.SelectedSchemaDoc() ? [DocumentView.SelectedSchemaDoc()!] : DocumentView.SelectedDocs().filter(doc => doc.layout_isSvg); } @computed get shapeXps() { return NumCast(this.selectedDoc?.x); } // prettier-ignore set shapeXps(value) { this.selectedDoc && (this.selectedDoc.x = Math.round(value * 100) / 100); } // prettier-ignore @@ -839,10 +839,10 @@ export class PropertiesView extends ObservableReactComponent { - doc[DocData].stroke_width = Math.round(value * 100) / 100; + doc.$stroke_width = Math.round(value * 100) / 100; }); } @@ -881,20 +881,20 @@ export class PropertiesView extends ObservableReactComponent { const inkStroke = DocumentView.getDocumentView(doc)?.ComponentView as InkingStroke; const { inkData } = inkStroke.inkScaledData(); if (InkingStroke.IsClosed(inkData)) { - doc[DocData].fillColor = value || undefined; + doc.$fillColor = value || undefined; } }); } - @computed get colorStk() { return StrCast(this.selectedStrokes.lastElement()?.[DocData].color); } // prettier-ignore + @computed get colorStk() { return StrCast(this.selectedStrokes.lastElement()?.$olor); } // prettier-ignore set colorStk(value) { this.selectedStrokes.forEach(doc => { - doc[DocData].color = value || undefined; + doc.$color = value || undefined; }); } @computed get borderColor() { @@ -902,7 +902,7 @@ export class PropertiesView extends ObservableReactComponent void) { return ( @@ -1034,41 +1034,41 @@ export class PropertiesView extends ObservableReactComponent { - doc[DocData].stroke_dash = value ? this._lastDash : undefined; + doc.$stroke_dash = value ? this._lastDash : undefined; }); } @computed get widthStk() { return this.getField('stroke_width') || '1'; } // prettier-ignore set widthStk(value) { this.selectedStrokes.forEach(doc => { - doc[DocData].stroke_width = Number(value); + doc.$stroke_width = Number(value); }); } @computed get markScal() { return Number(this.getField('stroke_markerScale') || '1'); } // prettier-ignore set markScal(value) { this.selectedStrokes.forEach(doc => { - doc[DocData].stroke_markerScale = Number(value); + doc.$stroke_markerScale = Number(value); }); } @computed get refStrength() { return Number(this.getField('drawing_refStrength') || '50'); } // prettier-ignore set refStrength(value) { - this.selectedDoc[DocData].drawing_refStrength = Number(value); + this.selectedDoc.$drawing_refStrength = Number(value); } @computed get smoothAmt() { return Number(this.getField('stroke_smoothAmount') || '5'); } // prettier-ignore set smoothAmt(value) { this.selectedStrokes.forEach(doc => { - doc[DocData].stroke_smoothAmount = Number(value); + doc.$stroke_smoothAmount = Number(value); }); } @computed get markHead() { return this.getField('stroke_startMarker') || ''; } // prettier-ignore set markHead(value) { this.selectedStrokes.forEach(doc => { - doc[DocData].stroke_startMarker = value; + doc.$stroke_startMarker = value; }); } @computed get markTail() { return this.getField('stroke_endMarker') || ''; } // prettier-ignore set markTail(value) { this.selectedStrokes.forEach(doc => { - doc[DocData].stroke_endMarker = value; + doc.$stroke_endMarker = value; }); } @@ -1356,7 +1356,7 @@ export class PropertiesView extends ObservableReactComponent { - const childDocs: Doc[] = DocListCast(selectedDoc[DocData].data); + const childDocs: Doc[] = DocListCast(selectedDoc.$data); for (let i = 0; i < childDocs.length; i++) { if (DocumentView.getDocumentView(childDocs[i])?.layoutDoc?.layout_isSvg) { return true; @@ -1454,7 +1454,7 @@ export class PropertiesView extends ObservableReactComponent { if (this.selectedLink) { - this.selectedLink[DocData].link_description = value; + this.selectedLink.$link_description = value; } }); diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx index d05b0a6b6..52c0227d8 100644 --- a/src/client/views/ScriptBox.tsx +++ b/src/client/views/ScriptBox.tsx @@ -3,7 +3,6 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { emptyFunction } from '../../Utils'; import { Doc, Opt } from '../../fields/Doc'; -import { DocData } from '../../fields/DocSymbols'; import { ScriptField } from '../../fields/ScriptField'; import { ScriptCast } from '../../fields/Types'; import { DragManager } from '../util/DragManager'; @@ -101,7 +100,6 @@ export class ScriptBox extends React.Component { ); } // let l = docList(this.source[0].data).length; if (l) { let ind = this.target[0].index !== undefined ? (this.target[0].index+1) % l : 0; this.target[0].index = ind; this.target[0].proto = getProto(docList(this.source[0].data)[ind]);} - // eslint-disable-next-line react/sort-comp public static EditButtonScript(title: string, doc: Doc, fieldKey: string, clientX: number, clientY: number, contextParams?: { [name: string]: string }, defaultScript?: ScriptField) { let overlayDisposer: () => void = emptyFunction; const script = ScriptCast(doc[fieldKey]) || defaultScript; @@ -119,7 +117,7 @@ export class ScriptBox extends React.Component { onCancel={overlayDisposer} onSave={(text, onError) => { if (!text) { - doc[DocData][fieldKey] = undefined; + doc['$' + fieldKey] = undefined; } else { const compScript = CompileScript(text, { params: { this: Doc.name, ...contextParams }, @@ -142,7 +140,7 @@ export class ScriptBox extends React.Component { div.innerHTML = 'button'; params.length && DragManager.StartButtonDrag([div], text, doc.title + '-instance', {}, params, () => {}, clientX, clientY); - doc[DocData][fieldKey] = new ScriptField(compScript); + doc['$' + fieldKey] = new ScriptField(compScript); overlayDisposer(); } }} diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index e51bc18ef..a45b37f43 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -503,9 +503,8 @@ export class CollectionDockingView extends CollectionSubView() { }); const dashboardDoc = Docs.Create.DockDocument(newtabs, json, { title: incrementTitleCopy(StrCast(doc.title)) }); - dashboardDoc.pane_count = 1; - dashboardDoc.myOverlayDocs = new List(); - dashboardDoc.myPublishedDocs = new List(); + dashboardDoc.$myOverlayDocs = new List(); + dashboardDoc.$myPublishedDocs = new List(); DashboardView.SetupDashboardTrails(); DashboardView.SetupDashboardCalendars(); // Zaul TODO: needed? @@ -555,13 +554,13 @@ export class CollectionDockingView extends CollectionSubView() { stack.header?.element.on('mousedown', (e: MouseEvent) => { const dashboard = Doc.ActiveDashboard; if (dashboard && e.target === stack.header?.element[0] && e.button === 2) { - dashboard.pane_count = NumCast(dashboard.pane_count) + 1; + dashboard.$myPaneCount = NumCast(dashboard.$myPaneCount) + 1; const docToAdd = Docs.Create.FreeformDocument([], { _width: this._props.PanelWidth(), _height: this._props.PanelHeight(), _freeform_backgroundGrid: true, _layout_fitWidth: true, - title: `Untitled Tab ${NumCast(dashboard.pane_count)}`, + title: `Untitled Tab ${NumCast(dashboard.$myPaneCount)}`, }); Doc.AddDocToList(Doc.MyHeaderBar, 'data', docToAdd, undefined, undefined, true); inheritParentAcls(this.Document, docToAdd, false); @@ -572,13 +571,13 @@ export class CollectionDockingView extends CollectionSubView() { const addNewDoc = undoable(() => { const dashboard = Doc.ActiveDashboard; if (dashboard) { - dashboard.pane_count = NumCast(dashboard.pane_count) + 1; + dashboard.$myPaneCount = NumCast(dashboard.$myPaneCount) + 1; const docToAdd = Docs.Create.FreeformDocument([], { _width: this._props.PanelWidth(), _height: this._props.PanelHeight(), _layout_fitWidth: true, _freeform_backgroundGrid: true, - title: `Untitled Tab ${NumCast(dashboard.pane_count)}`, + title: `Untitled Tab ${NumCast(dashboard.$myPaneCount)}`, }); Doc.AddDocToList(Doc.MyHeaderBar, 'data', docToAdd, undefined, undefined, true); inheritParentAcls(this.dataDoc, docToAdd, false); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index cac276535..fdaf13733 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -88,7 +88,7 @@ export interface DocumentViewProps extends FieldViewSharedProps { @observer export class DocumentViewInternal extends DocComponent() { // this makes mobx trace() statements more descriptive - public get displayName() { return 'DocumentViewInternal(' + this.Document.title + ')'; } // prettier-ignore + public get displayName() { return 'DocumentViewInternal(' + this.Document.$title + ')'; } // prettier-ignore public static SelectAfterContextMenu = true; // whether a document should be selected after it's contextmenu is triggered. /** @@ -143,10 +143,10 @@ export class DocumentViewInternal extends DocComponent 0)) stopPropagate = false; preventDefault = false; } - this._singleClickFunc = undoable(clickFunc ?? sendToBack ?? selectFunc, 'click: ' + this.Document.title); + this._singleClickFunc = undoable(clickFunc ?? sendToBack ?? selectFunc, 'click: ' + this.Document.$title); const waitForDblClick = this._props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick; if ((clickFunc && waitForDblClick !== 'never') || waitForDblClick === 'always') { this._doubleClickTimeout && clearTimeout(this._doubleClickTimeout); @@ -519,7 +519,7 @@ export class DocumentViewInternal extends DocComponent { - if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && this._props.select(false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. + if (this.Document.$type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && this._props.select(false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. setTimeout(() => simulateMouseClick(document.elementFromPoint(e.clientX, e.clientY), e.clientX, e.clientY, e.screenX, e.screenY)); }; if (navigator.userAgent.includes('Macintosh')) { @@ -545,7 +545,7 @@ export class DocumentViewInternal extends DocComponent (item.method ? item.method() : item.script?.script.run({ this: this.Document, documentView: this, scriptContext: this._props.scriptContext })), icon: item.icon as IconProp }) ); - if (!this.Document.isFolder) { + if (!this.Document.$isFolder) { const templateDoc = Cast(this.Document[StrCast(this.Document.layout_fieldKey)], Doc, null); const appearance = cm.findByDescription('Appearance...'); const appearanceItems = appearance?.subitems ?? []; @@ -635,7 +635,7 @@ export class DocumentViewInternal extends DocComponent= 1 ? 0 : 1 / (1 + x * (viewXfScale - 1)); - const y = NumCast(this.Document.width) / viewXfScale / 200; + const y = NumCast(this.Document._width) / viewXfScale / 200; const yscale = y >= 1 ? 0 : 1 / (1 + y * viewXfScale - 1); return Math.max(xscale, yscale, 1 / viewXfScale); } @@ -735,7 +735,7 @@ export class DocumentViewInternal extends DocComponent
- {this._componentView?.isUnstyledView?.() || this.Document.type === DocumentType.CONFIG || !renderDoc ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} + {this._componentView?.isUnstyledView?.() || this.Document.$type === DocumentType.CONFIG || !renderDoc ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} {jsx}
); @@ -1210,7 +1210,7 @@ export class DocumentView extends DocComponent() { } @computed private get nativeScaling() { if (this.shouldNotScale) return 1; - const minTextScale = this.Document.type === DocumentType.RTF ? 0.1 : 0; + const minTextScale = this.Document.$type === DocumentType.RTF ? 0.1 : 0; const ai = this._showAIEditor && this.nativeWidth === this.layoutDoc.width ? 95 : 0; const effNW = Math.max(this.effectiveNativeWidth - ai, 1); const effNH = Math.max(this.effectiveNativeHeight - ai, 1); @@ -1325,7 +1325,7 @@ export class DocumentView extends DocComponent() { public startDragging = (x: number, y: number, dropAction: dropActionType | undefined, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource); public showContextMenu = (pageX: number, pageY: number) => this._docViewInternal?.onContextMenu(undefined, pageX, pageY); - public toggleNativeDimensions = () => this._docViewInternal && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.NativeDimScaling() ?? 1, this._props.PanelWidth(), this._props.PanelHeight()); + public toggleNativeDimensions = () => this._docViewInternal && this.Document.$type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.NativeDimScaling() ?? 1, this._props.PanelWidth(), this._props.PanelHeight()); public iconify(finished?: () => void, animateTime?: number) { this.ComponentView?.updateIcon?.(); diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 40c687b7e..9795febbe 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -54,16 +54,12 @@ export class KeyValueBox extends ViewBoxBaseComponent() { @observable private rows: KeyValuePair[] = []; @observable _splitPercentage = 50; - get fieldDocToLayout() { - return DocCast(this.Document); - } - @action onEnterKey = (e: React.KeyboardEvent): void => { if (e.key === 'Enter') { e.stopPropagation(); - if (this._keyInput.current?.value && this._valInput.current?.value && this.fieldDocToLayout) { - if (KeyValueBox.SetField(this.fieldDocToLayout, this._keyInput.current.value, this._valInput.current.value)) { + if (this._keyInput.current?.value && this._valInput.current?.value && this._props.Document) { + if (KeyValueBox.SetField(this._props.Document, this._keyInput.current.value, this._valInput.current.value)) { this._keyInput.current.value = ''; this._valInput.current.value = ''; document.body.focus(); @@ -114,7 +110,7 @@ export class KeyValueBox extends ViewBoxBaseComponent() { if (key) target[key] = script.originalScript; return false; } - field === undefined && (field = res.result instanceof Array ? new List(res.result) : (typeof res.result === 'function' ? res.result.name : res.result as FieldType)); + field === undefined && (field = res.result instanceof Array ? new List(res.result) : typeof res.result === 'function' ? res.result.name : (res.result as FieldType)); } } if (!key) return false; @@ -141,7 +137,7 @@ export class KeyValueBox extends ViewBoxBaseComponent() { rowHeight = () => 30; @computed get createTable() { - const doc = this.fieldDocToLayout; + const doc = this._props.Document; if (!doc) { return ( @@ -149,25 +145,35 @@ export class KeyValueBox extends ViewBoxBaseComponent() { ); } - const realDoc = doc; const ids: { [key: string]: string } = {}; const protos = Doc.GetAllPrototypes(doc); protos.forEach(proto => { Object.keys(proto).forEach(key => { - if (!(key in ids) && realDoc[key] !== ComputedField.undefined) { + if (!(key in ids) && doc[key] !== ComputedField.undefined) { ids[key] = key; } }); }); + const layoutProtos = Doc.GetAllPrototypes(this.layoutDoc); + layoutProtos.forEach(proto => { + Object.keys(proto) + .map(key => '_' + key) + .forEach(key => { + if (!(key.replace(/^_/, '') in ids) && doc[key] !== ComputedField.undefined) { + ids[key] = key; + } + }); + }); + const rows: JSX.Element[] = []; let i = 0; const keys = Object.keys(ids).slice(); // for (const key of [...keys.filter(id => id !== 'layout' && !id.includes('_')).sort(), ...keys.filter(id => id === 'layout' || id.includes('_')).sort()]) { const sortedKeys = keys.sort((a: string, b: string) => { - const a_ = a.split('_')[0]; - const b_ = b.split('_')[0]; + const a_ = a.replace(/^_/, '').split('_')[0]; + const b_ = b.replace(/^_/, '').split('_')[0]; if (a_ < b_) return -1; if (a_ > b_) return 1; if (a === a_) return -1; @@ -177,7 +183,7 @@ export class KeyValueBox extends ViewBoxBaseComponent() { sortedKeys.forEach(key => { rows.push( () { openItems.push({ description: 'Default Perspective', event: () => { - this._props.addDocTab(this.Document, OpenWhere.close); - this._props.addDocTab(this.fieldDocToLayout, OpenWhere.addRight); + this._props.addDocTab(this._props.Document, OpenWhere.close); + this._props.addDocTab(this._props.Document, OpenWhere.addRight); }, icon: 'image', }); diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 85aff04c3..93f5231cb 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -61,17 +61,18 @@ export class KeyValuePair extends ObservableReactComponent { render() { // let fieldKey = Object.keys(props.Document).indexOf(props.fieldKey) !== -1 ? props.fieldKey : "(" + props.fieldKey + ")"; - let protoCount = 0; - let { doc } = this._props; + const layoutField = this._props.keyName.startsWith('_'); + let doc = layoutField ? Doc.Layout(this._props.doc) : this._props.doc; + let protoCount = doc !== this._props.doc && !layoutField ? 1 : 0; while (doc) { - if (Object.keys(doc).includes(this._props.keyName)) { + if (Object.keys(doc).includes(this._props.keyName.replace(/^_/, ''))) { break; } protoCount++; doc = DocCast(doc.proto); } - const parenCount = Math.max(0, protoCount - 1); - const keyStyle = protoCount === 0 ? 'black' : 'blue'; + const parenCount = Math.max(0, protoCount); + const keyStyle = protoCount === 0 && doc === this._props.doc ? 'black' : 'blue'; const hover = { transition: '0.3s ease opacity', opacity: this.isPointerOver || this.isChecked ? 1 : 0 }; @@ -99,10 +100,9 @@ export class KeyValuePair extends ObservableReactComponent { pair[0].replace(/^_/, '') === this._props.keyName)?.[1].description ?? ''}> -
- {'('.repeat(parenCount)} - {this._props.keyName} - {')'.repeat(parenCount)} +
+ {(layoutField ? '_' : '$').repeat(parenCount)} + {(keyStyle === 'blue' && !layoutField && !parenCount ? '$' : '') + this._props.keyName}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index b84575389..9078648e9 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -245,9 +245,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent void = emptyFunction; - const targetData = target[DocData]; - targetData.mediaState = mediaState.Recording; - DictationManager.recordAudioAnnotation(targetData, Doc.LayoutFieldKey(target), stop => { stopFunc = stop }); // prettier-ignore + target.$mediaState = mediaState.Recording; + DictationManager.recordAudioAnnotation(target[DocData], Doc.LayoutFieldKey(target), stop => { stopFunc = stop }); // prettier-ignore const reactionDisposer = reaction( () => target.mediaState, @@ -1067,7 +1066,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent::$/, (state, match, start, end) => { const creator = (doc: Doc) => { - const textDoc = this.Document[DocData]; - const numInlines = NumCast(textDoc.inlineTextCount); - textDoc.inlineTextCount = numInlines + 1; + const numInlines = NumCast(this.Document.$inlineTextCount); + this.Document.$inlineTextCount = numInlines + 1; const node = state.doc.resolve(start).nodeAfter; const newNode = schema.nodes.dashComment.create({ docId: doc[Id], reflow: false }); const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 35, title: 'dashDoc', docId: doc[Id], float: 'right' }); @@ -109,16 +108,15 @@ export class RichTextRules { }), // Create annotation to a field on the text document new InputRule(/>>$/, (state, match, start, end) => { - const textDoc = this.Document[DocData]; - const numInlines = NumCast(textDoc.inlineTextCount); - textDoc.inlineTextCount = numInlines + 1; - const inlineFieldKey = 'inline' + numInlines; // which field on the text document this annotation will write to - const inlineLayoutKey = 'layout_' + inlineFieldKey; // the field holding the layout string that will render the inline annotation + const numInlines = NumCast(this.Document.$inlineTextCount); + this.Document.$inlineTextCount = numInlines + 1; + const inlineFieldKey = '$inline' + numInlines; // which field on the text document this annotation will write to + const inlineLayoutKey = '$layout_' + inlineFieldKey; // the field holding the layout string that will render the inline annotation const textDocInline = Docs.Create.TextDocument('', { _layout_fieldKey: inlineLayoutKey, _width: 75, _height: 35, - annotationOn: textDoc, + annotationOn: this.Document[DocData], _layout_fitWidth: true, _layout_autoHeight: true, text_fontSize: '9px', @@ -128,9 +126,9 @@ export class RichTextRules { textDocInline.title_custom = true; // And make sure that it's 'custom' so that editing text doesn't change the title of the containing doc textDocInline.isTemplateForField = inlineFieldKey; // this is needed in case the containing text doc is converted to a template at some point textDocInline.isDataDoc = true; - textDocInline.proto = textDoc; // make the annotation inherit from the outer text doc so that it can resolve any nested field references, e.g., [[field]] - textDoc[inlineLayoutKey] = FormattedTextBox.LayoutString(inlineFieldKey); // create a layout string for the layout key that will render the annotation text - textDoc[inlineFieldKey] = ''; // set a default value for the annotation + textDocInline.proto = this.Document[DocData]; // make the annotation inherit from the outer text doc so that it can resolve any nested field references, e.g., [[field]] + this.Document[inlineLayoutKey] = FormattedTextBox.LayoutString(inlineFieldKey); // create a layout string for the layout key that will render the annotation text + this.Document[inlineFieldKey] = ''; // set a default value for the annotation const node = state.doc.resolve(start).nodeAfter; const newNode = schema.nodes.dashComment.create({ docId: textDocInline[Id], reflow: true }); const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 35, title: 'dashDoc', docId: textDocInline[Id], float: 'right' }); @@ -334,18 +332,14 @@ export class RichTextRules { if (value?.includes(',') && !value.startsWith('((')) { const values = value.split(','); const strs = values.some(v => !v.match(/^[-]?[0-9.]$/)); - this.Document[DocData][fieldKey] = strs ? new List(values) : new List(values.map(v => Number(v))); + this.Document['$' + fieldKey] = strs ? new List(values) : new List(values.map(v => Number(v))); } else if (value) { Doc.SetField( this.Document, fieldKey, assign + value, Doc.IsDataProto(this.Document) ? true : undefined, - assign.includes(':=') - ? undefined - : (gptval: FieldResult) => { - (dataDoc ? this.Document[DocData] : this.Document)[fieldKey] = gptval as string; - } + assign.includes(':=') ? undefined : (gptval: FieldResult) => (this.Document[(dataDoc ? '$' : '_') + fieldKey] = gptval as string) ); if (fieldKey === this.TextBox.fieldKey) return this.TextBox.EditorView!.state.tr; } @@ -399,11 +393,11 @@ export class RichTextRules { new InputRule(/#(@?[a-zA-Z_-]+[a-zA-Z_\-0-9]*)\s$/, (state, match, start, end) => { const tag = match[1]; if (!tag) return state.tr; - // this.Document[DocData]['#' + tag] = '#' + tag; - const tags = StrListCast(this.Document[DocData].tags); + // this.Document[['$#' + tag] = '#' + tag; + const tags = StrListCast(this.Document.$tags); if (!tags.includes(tag)) { tags.push(tag); - this.Document[DocData].tags = new List(tags); + this.Document.$tags = new List(tags); this.Document._layout_showTags = true; } const fieldView = state.schema.nodes.dashField.create({ fieldKey: tag.startsWith('@') ? tag.replace(/^@/, '') : '#' + tag }); diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index f818c6e20..ec97e067a 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -596,11 +596,11 @@ export class PresBox extends ViewBoxBaseComponent() { } if (pinDataTypes?.inkable || (!pinDataTypes && (activeItem.config_fillColor !== undefined || activeItem.color !== undefined))) { if (bestTarget.fillColor !== activeItem.config_fillColor) { - bestTarget[DocData].fillColor = StrCast(activeItem.config_fillColor, StrCast(bestTarget.fillColor)); + bestTarget.$fillColor = StrCast(activeItem.config_fillColor, StrCast(bestTarget.fillColor)); changed = true; } if (bestTarget.color !== activeItem.config_color) { - bestTarget[DocData].color = StrCast(activeItem.config_color, StrCast(bestTarget.color)); + bestTarget.$color = StrCast(activeItem.config_color, StrCast(bestTarget.color)); changed = true; } if (bestTarget.width !== activeItem.width) { @@ -669,7 +669,7 @@ export class PresBox extends ViewBoxBaseComponent() { return doc; }); const newList = new List([...oldItems, ...hiddenItems, ...newItems]); - bestTarget[DocData][fkey + '_annotations'] = newList; + bestTarget['$' + fkey + '_annotations'] = newList; } if (pinDataTypes?.poslayoutview || (!pinDataTypes && activeItem.config_pinLayoutData !== undefined)) { changed = true; @@ -690,8 +690,8 @@ export class PresBox extends ViewBoxBaseComponent() { data.fill && (doc._fillColor = data.fill); doc._width = data.w; doc._height = data.h; - data.data && (doc[DocData].data = field); - data.text && (doc[DocData].text = tfield); + data.data && (doc.$data = field); + data.text && (doc.$text = tfield); Doc.AddDocToList(bestTarget[DocData], layoutField, doc); } }); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index dc7524bcd..2142adac8 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -431,7 +431,7 @@ export class PDFViewer extends ObservableReactComponent { }; addDrawingAnnotation = (drawing: Doc) => { - // drawing[DocData].x = this._props.pdfBox.ScreenToLocalBoxXf().TranslateX + // drawing.x = this._props.pdfBox.ScreenToLocalBoxXf().TranslateX // const scaleX = this._mainCont.current.offsetWidth / boundingRect.width; drawing.y = NumCast(drawing.y) + NumCast(this._props.Document.layout_scrollTop); this._props.addDocument?.(drawing); diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index 6f70e96ab..841546a04 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -66,7 +66,7 @@ export class FaceRecognitionHandler { * returns a list of all face collection Docs on the current dashboard * @returns face collection Doc list */ - public static UniqueFaces = () => DocListCast(Doc.ActiveDashboard?.[DocData].myUniqueFaces); + public static UniqueFaces = () => DocListCast(Doc.ActiveDashboard?.$myUniqueFaces); /** * Find a unique face from its name @@ -87,22 +87,22 @@ export class FaceRecognitionHandler { * @param faceDoc unique face Doc * @returns label string */ - public static UniqueFaceLabel = (faceDoc: Doc) => StrCast(faceDoc[DocData].face); + public static UniqueFaceLabel = (faceDoc: Doc) => StrCast(faceDoc.$face); - public static SetUniqueFaceLabel = (faceDoc: Doc, value: string) => (faceDoc[DocData].face = value); + public static SetUniqueFaceLabel = (faceDoc: Doc, value: string) => (faceDoc.$face = value); /** * Returns all the face descriptors associated with a unique face Doc * @param faceDoc unique face Doc * @returns face descriptors */ - public static UniqueFaceDescriptors = (faceDoc: Doc) => DocListCast(faceDoc[DocData].face_annos).map(face => face.faceDescriptor as List); + public static UniqueFaceDescriptors = (faceDoc: Doc) => DocListCast(faceDoc.$face_annos).map(face => face.faceDescriptor as List); /** * Returns a list of all face image Docs associated with a unique face Doc * @param faceDoc unique face Doc * @returns image Docs */ - public static UniqueFaceImages = (faceDoc: Doc) => DocListCast(faceDoc[DocData].face_annos).map(face => DocCast(face.annotationOn, face)); + public static UniqueFaceImages = (faceDoc: Doc) => DocListCast(faceDoc.$face_annos).map(face => DocCast(face.annotationOn, face)); /** * Adds a face image to a unique face Doc, adds the unique face Doc to the images list of reognized faces, @@ -145,8 +145,8 @@ export class FaceRecognitionHandler { * @returns a unique face Doc */ private createUniqueFaceDoc = (dashboard: Doc) => { - const faceDocNum = NumCast(dashboard[DocData].myUniqueFaces_count) + 1; - dashboard[DocData].myUniqueFaces_count = faceDocNum; // TODO: improve to a better name + const faceDocNum = NumCast(dashboard.$myUniqueFaces_count) + 1; + dashboard.$myUniqueFaces_count = faceDocNum; // TODO: improve to a better name const uniqueFaceDoc = Docs.Create.UniqeFaceDocument({ title: ComputedField.MakeFunction('this.face', undefined, undefined, 'this.face = value') as unknown as string, @@ -160,9 +160,8 @@ export class FaceRecognitionHandler { _width: 400, _height: 100, }); - const uface = uniqueFaceDoc[DocData]; - uface.face = `Face${faceDocNum}`; - uface.face_annos = new List(); + uniqueFaceDoc.$face = `Face${faceDocNum}`; + uniqueFaceDoc.$face_annos = new List(); Doc.SetContainer(uniqueFaceDoc, Doc.MyFaceCollection); Doc.ActiveDashboard && Doc.AddDocToList(Doc.ActiveDashboard[DocData], 'myUniqueFaces', uniqueFaceDoc); @@ -241,7 +240,7 @@ export class FaceRecognitionHandler { annos.push(faceAnno); }); - imgDoc[DocData].data_annotations = new List(annos); + imgDoc.$data_annotations = new List(annos); imgDoc._layout_showTags = annos.length > 0; return imgDocFaceDescriptions; }) diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index af98355d1..8b7e77fba 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -465,7 +465,6 @@ export class SearchBox extends ViewBoxBaseComponent() { } }); - // eslint-disable-next-line react/jsx-props-no-spreading const recommendationsJSX: JSX.Element[] = []; // this._recommendations.map(props => ); return ( diff --git a/src/client/views/smartdraw/DrawingFillHandler.tsx b/src/client/views/smartdraw/DrawingFillHandler.tsx index c672bc718..f1d5f2cfe 100644 --- a/src/client/views/smartdraw/DrawingFillHandler.tsx +++ b/src/client/views/smartdraw/DrawingFillHandler.tsx @@ -1,6 +1,5 @@ import { imageUrlToBase64 } from '../../../ClientUtils'; import { Doc, StrListCast } from '../../../fields/Doc'; -import { DocData } from '../../../fields/DocSymbols'; import { List } from '../../../fields/List'; import { DocCast, ImageCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; @@ -15,8 +14,7 @@ import { AspectRatioLimits, FireflyDimensionsMap, FireflyImageDimensions, Firefl const DashDropboxId = '2m86iveqdr9vzsa'; export class DrawingFillHandler { static drawingToImage = async (drawing: Doc, strength: number, user_prompt: string, styleDoc?: Doc) => { - const docData = drawing[DocData]; - const tags = StrListCast(docData.tags).map(tag => tag.slice(1)); + const tags = StrListCast(drawing.$tags).map(tag => tag.slice(1)); const styles = tags.filter(tag => FireflyStylePresets.has(tag)); const styleDocs = !Doc.Links(drawing).length ? styleDoc && !tags.length @@ -47,7 +45,7 @@ export class DrawingFillHandler { Networking.PostToServer('/queryFireflyImageFromStructure', { prompt: `${newPrompt}`, width: dims.width, height: dims.height, structureUrl, strength, presets: styles, styleUrl }) .then(res => { const genratedDocs = DocCast(drawing.ai_firefly_generatedDocs) ?? Docs.Create.MasonryDocument([], { _width: 400, _height: 400 }); - drawing[DocData].ai_firefly_generatedDocs = genratedDocs; + drawing.$ai_firefly_generatedDocs = genratedDocs; (res as Upload.ImageInformation[]).map(info => Doc.AddDocToList( genratedDocs, diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index fc89dcbe7..f5bd4f44c 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -320,10 +320,11 @@ export class Doc extends RefField { UpdatingFromServer, Width, '__LAYOUT__', + '__DATA__', ]; }, getOwnPropertyDescriptor: (target, prop) => { - if (prop.toString() === '__LAYOUT__' || !(prop in target[FieldKeys])) { + if (prop.toString() === '__DATA__' || prop.toString() === '__LAYOUT__' || !(prop in target[FieldKeys])) { return Reflect.getOwnPropertyDescriptor(target, prop); } return { @@ -400,6 +401,9 @@ export class Doc extends RefField { public [ToString] = () => `Doc(${GetEffectiveAcl(this[SelfProxy]) === AclPrivate ? '-inaccessible-' : this[SelfProxy].title})`; public get [DocLayout]() { return this[SelfProxy].__LAYOUT__; } // prettier-ignore public get [DocData](): Doc { + return this[SelfProxy].__DATA__; + } + @computed get __DATA__(): Doc { const self = this[SelfProxy]; return self.resolvedDataDoc && !self.isTemplateForField ? self : Doc.GetProto(Cast(Doc.Layout(self).resolvedDataDoc, Doc, null) || self); } @@ -414,7 +418,7 @@ export class Doc extends RefField { } else { return Cast(layoutField, Doc, null); } - return Cast(self[renderFieldKey + '_layout[' + templateLayoutDoc[Id] + ']'], Doc, null) || templateLayoutDoc; + return Cast(self['layout_' + templateLayoutDoc.title + '(' + renderFieldKey + ')'], Doc, null) || templateLayoutDoc; } return undefined; } @@ -865,7 +869,7 @@ export namespace Doc { // If it doesn't find the expanded layout, then it makes a delegate of the template layout and // saves it on the data doc indexed by the template layout's id. // - const expandedLayoutFieldKey = templateField + '_layout[' + templateLayoutDoc[Id] + ']'; + const expandedLayoutFieldKey = 'layout_' + templateLayoutDoc.title + '(' + templateField + ')'; let expandedTemplateLayout = targetDoc?.[expandedLayoutFieldKey]; if (templateLayoutDoc.resolvedDataDoc instanceof Promise) { @@ -1152,7 +1156,9 @@ export namespace Doc { // the document containing the view layout information - will be the Document itself unless the Document has // a layout field or 'layout' is given. export function Layout(doc: Doc, layout?: Doc): Doc { - const overrideLayout = layout && Cast(doc[`${StrCast(layout.isTemplateForField, 'data')}_layout[` + layout[Id] + ']'], Doc, null); + const templateField = layout && StrCast(layout.isTemplateForField, Doc.LayoutFieldKey(layout)); // the field that the template renders + const overrideLayout = layout && Cast(doc[layout.title + '(' + templateField + ')'], Doc, null); + // [`${StrCast(layout.isTemplateForField, 'data')}_layout[` + layout[Id] + ']'], Doc, null); return overrideLayout || doc[DocLayout] || doc; } export function SetLayout(doc: Doc, layout: Doc | string) { diff --git a/src/fields/util.ts b/src/fields/util.ts index 33764aca5..abbe543e8 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -314,6 +314,13 @@ export function setter(target: ListImpl | Doc, inProp: string | symbo // if you're trying to change an acl but don't have Admin access / you're trying to change it to something that isn't an acceptable acl, you can't if (typeof prop === 'string' && prop.startsWith('acl_') && (effectiveAcl !== AclAdmin || ![...Object.values(SharingPermissions), undefined].includes(value as SharingPermissions))) return true; + if (typeof prop === 'string' && prop !== '__id' && prop !== '__fieldTuples' && prop.startsWith('$')) { + prop = prop.substring(1); + if (target.__DATA__ instanceof Doc) { + target.__DATA__[prop] = value as FieldResult; + return true; + } + } if (typeof prop === 'string' && prop !== '__id' && prop !== '__fieldTuples' && prop.startsWith('_')) { if (!prop.startsWith('__')) prop = prop.substring(1); if (target.__LAYOUT__ instanceof Doc) { @@ -351,6 +358,7 @@ export function getter(target: Doc | ListImpl, prop: string | symbol, case DocAcl : return target[DocAcl]; case $mobx: return target.__fieldTuples[prop]; case DocLayout: return target.__LAYOUT__; + case DocData: return target.__DATA__; case Height: case Width: if (GetEffectiveAcl(target) === AclPrivate) return returnZero; // eslint-disable-next-line no-fallthrough default : @@ -362,6 +370,8 @@ export function getter(target: Doc | ListImpl, prop: string | symbol, const layoutProp = prop.startsWith('_') ? prop.substring(1) : undefined; if (layoutProp && target.__LAYOUT__) return (target.__LAYOUT__ as Doc)[layoutProp]; + const dataProp = prop.startsWith('$') ? prop.substring(1) : undefined; + if (dataProp && target.__DATA__) return (target.__DATA__ as Doc)[dataProp]; return getFieldImpl(target, layoutProp ?? prop, proxy); } -- cgit v1.2.3-70-g09d2 From eef391dba5ee9f1588274f8719eb4047fe844e22 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 10 Apr 2025 23:08:13 -0400 Subject: changed naming of makeDelegates to not add a number at the end. switched dataNote to MetaNote and cleaned up initialization of it. fixed sidebar/stacking view to not grab wheel evebnts when not active. fixed dashfieldview to vcenter labels. fixed height and scrolling of templae menu. simplified formattedtextbox menu --- src/client/documents/DocUtils.ts | 2 +- src/client/documents/Documents.ts | 5 +- src/client/util/CurrentUserUtils.ts | 83 +++++++++++----------- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/SidebarAnnos.tsx | 3 +- src/client/views/TemplateMenu.scss | 4 ++ .../views/collections/CollectionStackingView.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 70 +++++++++--------- .../views/nodes/formattedText/DashFieldView.scss | 1 + .../views/nodes/formattedText/FormattedTextBox.tsx | 61 ---------------- .../views/nodes/formattedText/RichTextRules.ts | 2 +- src/fields/Doc.ts | 6 +- 13 files changed, 96 insertions(+), 147 deletions(-) (limited to 'src/client/views/nodes/formattedText/RichTextRules.ts') diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts index f5eee84aa..0d15a91e9 100644 --- a/src/client/documents/DocUtils.ts +++ b/src/client/documents/DocUtils.ts @@ -899,7 +899,7 @@ export namespace DocUtils { const ndoc = Doc.MakeDelegateWithProto(dragFactory); if (ndoc && dragFactory.dragFactory_count !== undefined) { dragFactory.dragFactory_count = NumCast(dragFactory.dragFactory_count) + 1; - Doc.GetProto(ndoc).title = ndoc.title + ' ' + NumCast(dragFactory.dragFactory_count).toString(); + Doc.GetProto(ndoc).title = ndoc.title; } return ndoc; } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 0e3c614fe..d93a432d4 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -221,7 +221,6 @@ export class DocumentOptions { color?: STRt = new StrInfo('foreground color data doc', false); hidden?: BOOLt = new BoolInfo('whether the document is not rendered by its collection', false); backgroundColor?: STRt = new StrInfo('background color for data doc', false); - _override_backgroundColor?: BOOLt = new BoolInfo("whether the layout template overrides the data doc's background color"); opacity?: NUMt = new NumInfo('document opacity', false); viewTransitionTime?: NUMt = new NumInfo('transition duration for view parameters', false); dontRegisterView?: BOOLt = new BoolInfo('are views of this document registered so that they can be found when following links, etc', false); @@ -284,7 +283,7 @@ export class DocumentOptions { _layout_curPage?: NUMt = new NumInfo('current page of a PDF or other? paginated document', false); _layout_currentTimecode?: NUMt = new NumInfo('the current timecode of a time-based document (e.g., current time of a video) value is in seconds', false); _layout_fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)'); - _layout_fieldKey?: STRt = new StrInfo('the field key containing the current layout definition', false); + layout_fieldKey?: STRt = new StrInfo('the field key containing the current layout definition', false); _layout_enableAltContentUI?: BOOLt = new BoolInfo('whether to show alternate content button'); _layout_flashcardType?: STRt = new StrInfo('flashcard style to render in ComparisonBox. currently just "flashcard".'); _layout_showTitle?: string; // field name to display in header (:hover is an optional suffix) @@ -678,7 +677,7 @@ export namespace Docs { // whatever options pertain to this specific prototype const options: DocumentOptions = { isSystem: true, - _layout_fieldKey: 'layout', + layout_fieldKey: 'layout', title, type, isBaseProto: true, diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 4c492cae0..1c0f11c91 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -144,14 +144,16 @@ export class CurrentUserUtils { static setupNoteTemplates(doc: Doc, field="template_notes") { const tempNotes = DocCast(doc[field]); const reqdTempOpts:DocumentOptions[] = [ - { title: "Postit", _override_backgroundColor: true, backgroundColor: "yellow", icon: "sticky-note", _layout_showTitle: "title", layout_borderRounding: "5px"}, - { title: "Idea", _override_backgroundColor: true, backgroundColor: "pink", icon: "lightbulb" , _layout_showTitle: "title"}, - { title: "Topic", _override_backgroundColor: true, backgroundColor: "lightblue", icon: "book-open" , _layout_showTitle: "title"}]; + { title: "Postit", backgroundColor: "yellow", icon: "sticky-note", _layout_showTitle: "title", layout_borderRounding: "5px"}, + { title: "Idea", backgroundColor: "pink", icon: "lightbulb" , _layout_showTitle: "title"}, + { title: "Topic", backgroundColor: "lightblue", icon: "book-open" , _layout_showTitle: "title"}]; + + const reqdNoteList = [...reqdTempOpts.map(opts => { const reqdOpts = {...opts, isSystem:true, width:200, layout_autoHeight: true, layout_fitWidth: true}; const noteTemp = tempNotes ? DocListCast(tempNotes.data).find(fdoc => fdoc.title === opts.title): undefined; return DocUtils.AssignOpts(noteTemp, reqdOpts) ?? MakeTemplate(Docs.Create.TextDocument("",reqdOpts)); - }), ... DocListCast(tempNotes?.data).filter(note => !reqdTempOpts.find(reqd => reqd.title === note.title))]; + }), DocCast(doc.emptyMetaNote), ... DocListCast(tempNotes?.data).filter(note => !reqdTempOpts.find(reqd => reqd.title === note.title))]; const reqdOpts:DocumentOptions = { title: "Note Layouts", _height: 75, isSystem: true }; return DocUtils.AssignOpts(tempNotes, reqdOpts, reqdNoteList) ?? (doc[field] = Docs.Create.TreeDocument(reqdNoteList, reqdOpts)); @@ -247,7 +249,6 @@ export class CurrentUserUtils { title: string, toolTip: string, icon: string, ignoreClick?: boolean, dragFactory?: Doc, backgroundColor?: string, openFactoryAsDelegate?:boolean, openFactoryLocation?:string, clickFactory?: Doc, scripts?: { onClick?: string, onDragStart?: string}, funcs?: {onDragStart?:string, hidden?: string}, }[] { - const standardOps = (key:string) => ({ title : "Untitled "+ key, _layout_fitWidth: false, isSystem: true, "dragFactory_count": 0, cloneFieldFilter: new List(["isSystem"]) }); const json = { doc: { type: "doc", @@ -272,17 +273,17 @@ export class CurrentUserUtils { // " " + // " " + // ""; - const headerBtnHgt = 10; - const headerTemplate = (opts:DocumentOptions) => - MakeTemplate(Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { ...opts, title: "Header Template", + const metadataBtnHght = 10; + const metaNoteTemplate = (opts:DocumentOptions) => + MakeTemplate(Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { ...opts, title: "MetaNote", layout:` - + - Metadata + Metadata ` - }, "header")); + }, "metaNote")); const slideView = (opts:DocumentOptions) => MakeTemplate(Docs.Create.MultirowDocument( [ @@ -405,9 +406,9 @@ pie title Minerals in my tap water {key: "Script", creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }}, {key: "DataViz", creator: opts => Docs.Create.DataVizDocument("", opts), opts: { _width: 300, _height: 300, }}, // AARAV ADD // - {key: "DailyJournal",creator:opts => Docs.Create.DailyJournalDocument("", opts),opts:{ _width: 300, _height: 300}}, + {key: "DailyJournal",creator:opts => Docs.Create.DailyJournalDocument("", opts),opts: { _width: 300, _height: 300}}, {key: "Chat", creator: Docs.Create.ChatDocument, opts: { _width: 500, _height: 500, _layout_fitWidth: true, }}, - {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 120, _header_pointerEvents: "all", _header_height: 50, _header_fontSize: 9,_layout_autoHeightMargins: 50, _layout_autoHeight: true, treeView_HideUnrendered: true}}, + {key: "MetaNote", creator: metaNoteTemplate, opts: { _width: 300, _height: 120, _header_pointerEvents: "all", _header_height: 50, _header_fontSize: 9,_layout_autoHeightMargins: 50, _layout_autoHeight: true, treeView_HideUnrendered: true}}, {key: "ViewSlide", creator: slideView, opts: { _width: 400, _height: 300, _xMargin: 3, _yMargin: 3,}}, {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, _layout_dontCenter:'xy', dropAction: dropActionType.embed, treeView_HideTitle: true, _layout_fitWidth:true, layout_boxShadow: "0 0" }}, {key: "Tab", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }}, @@ -420,40 +421,42 @@ pie title Minerals in my tap water {key: "Plotly", creator: plotlyView, opts: { _width: 300, _height: 300, }}, ]; + const standardOps = (key:string) => ({ title : "Untitled "+ key, _layout_fitWidth: false, isSystem: true, "dragFactory_count": 0, cloneFieldFilter: new List(["isSystem"]) }); emptyThings.forEach( thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, thing.scripts, thing.funcs)); - + DocCast(Doc.UserDoc().emptyMetaNote).title = "MetaNote"; // hack: metanotes are used a template, so 'untitled metaNote' is an awkward name + return [ - { toolTip: "Tap or drag to create a note", title: "Note", icon: "sticky-note", dragFactory: doc.emptyNote as Doc, clickFactory: DocCast(doc.emptyNote)}, - { toolTip: "Tap or drag to create a flashcard", title: "Flashcard", icon: "id-card", dragFactory: doc.emptyFlashcard as Doc, clickFactory: DocCast(doc.emptyFlashcard)}, - { toolTip: "Tap or drag to create an equation", title: "Math", icon: "calculator", dragFactory: doc.emptyEquation as Doc, clickFactory: DocCast(doc.emptyEquation)}, - { toolTip: "Tap or drag to create a mermaid node", title: "Mermaids", icon: "rocket", dragFactory: doc.emptyMermaids as Doc, clickFactory: DocCast(doc.emptyMermaids)}, - { toolTip: "Tap or drag to create a plotly node", title: "Plotly", icon: "rocket", dragFactory: doc.emptyPlotly as Doc, clickFactory: DocCast(doc.emptyMermaids)}, - { toolTip: "Tap or drag to create a note board", title: "Notes", icon: "book", dragFactory: doc.emptyNoteboard as Doc, clickFactory: DocCast(doc.emptyNoteboard)}, - { toolTip: "Tap or drag to create an image", title: "Image", icon: "image", dragFactory: doc.emptyImage as Doc, clickFactory: DocCast(doc.emptyImage)}, - { toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab)}, - { toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, clickFactory: DocCast(doc.emptyWebpage)}, - { toolTip: "Tap or drag to create a comparison box", title: "Compare", icon: "columns", dragFactory: doc.emptyComparison as Doc, clickFactory: DocCast(doc.emptyComparison)}, - { toolTip: "Tap or drag to create a diagram", title: "Diagram", icon: "tree", dragFactory: doc.emptyDiagram as Doc, clickFactory: DocCast(doc.emptyDiagram)}, - { toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, clickFactory: DocCast(doc.emptyAudio), openFactoryLocation: OpenWhere.overlay}, - { toolTip: "Tap or drag to create a map", title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc, clickFactory: DocCast(doc.emptyMap)}, - { toolTip: "Tap or drag to create a chat assistant", title: "Assistant Chat", icon: "book",dragFactory: doc.emptyChat as Doc, clickFactory: DocCast(doc.emptyChat)}, - { toolTip: "Tap or drag to create a screen grabber", title: "Grab", icon: "photo-video", dragFactory: doc.emptyScreengrab as Doc, clickFactory: DocCast(doc.emptyScreengrab), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, - { toolTip: "Tap or drag to create a WebCam recorder", title: "WebCam", icon: "photo-video", dragFactory: doc.emptyWebCam as Doc, clickFactory: DocCast(doc.emptyWebCam), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, - { toolTip: "Tap or drag to create a button", title: "Button", icon: "circle", dragFactory: doc.emptyButton as Doc, clickFactory: DocCast(doc.emptyButton)}, - { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, clickFactory: DocCast(doc.emptyScript), funcs: { hidden: "IsNoviceMode()"}}, - { toolTip: "Tap or drag to create a data viz node", title: "DataViz", icon: "chart-bar", dragFactory: doc.emptyDataViz as Doc, clickFactory: DocCast(doc.emptyDataViz)}, - { toolTip: "Tap or drag to create a journal entry", title: "Journal", icon: "book", dragFactory: doc.emptyDailyJournal as Doc,clickFactory:DocCast(doc.emptyDataJournal), }, - { toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon: "person-chalkboard", dragFactory: doc.emptySlide as Doc, clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay,funcs: { hidden: "IsNoviceMode()"}}, - { toolTip: "Tap or drag to create a view slide", title: "View Slide", icon: "address-card", dragFactory: doc.emptyViewSlide as Doc, clickFactory: DocCast(doc.emptyViewSlide), openFactoryLocation: OpenWhere.overlay,funcs: { hidden: "IsNoviceMode()"}}, - { toolTip: "Tap or drag to create a data note", title: "DataNote", icon: "window-maximize", dragFactory: doc.emptyHeader as Doc, clickFactory: DocCast(doc.emptyHeader), openFactoryAsDelegate: true, funcs: { hidden: "IsNoviceMode()"} }, - { toolTip: "Toggle a Calculator REPL", title: "replviewer", icon: "calculator", clickFactory: '' as unknown as Doc, openFactoryLocation: OpenWhere.overlay}, // hack: clickFactory is not a Doc but will get interpreted as a custom UI by the openDoc() onClick script + { toolTip: "Tap or drag to create a note", title: "Note", icon: "sticky-note", dragFactory: doc.emptyNote as Doc, clickFactory: DocCast(doc.emptyNote)}, + { toolTip: "Tap or drag to create a flashcard", title: "Flashcard", icon: "id-card", dragFactory: doc.emptyFlashcard as Doc, clickFactory: DocCast(doc.emptyFlashcard)}, + { toolTip: "Tap or drag to create an equation", title: "Math", icon: "calculator", dragFactory: doc.emptyEquation as Doc, clickFactory: DocCast(doc.emptyEquation)}, + { toolTip: "Tap or drag to create a mermaid node", title: "Mermaids", icon: "rocket", dragFactory: doc.emptyMermaids as Doc, clickFactory: DocCast(doc.emptyMermaids)}, + { toolTip: "Tap or drag to create a plotly node", title: "Plotly", icon: "rocket", dragFactory: doc.emptyPlotly as Doc, clickFactory: DocCast(doc.emptyMermaids)}, + { toolTip: "Tap or drag to create a note board", title: "Notes", icon: "book", dragFactory: doc.emptyNoteboard as Doc, clickFactory: DocCast(doc.emptyNoteboard)}, + { toolTip: "Tap or drag to create an image", title: "Image", icon: "image", dragFactory: doc.emptyImage as Doc, clickFactory: DocCast(doc.emptyImage)}, + { toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab)}, + { toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, clickFactory: DocCast(doc.emptyWebpage)}, + { toolTip: "Tap or drag to create a comparison box", title: "Compare", icon: "columns", dragFactory: doc.emptyComparison as Doc, clickFactory: DocCast(doc.emptyComparison)}, + { toolTip: "Tap or drag to create a diagram", title: "Diagram", icon: "tree", dragFactory: doc.emptyDiagram as Doc, clickFactory: DocCast(doc.emptyDiagram)}, + { toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, clickFactory: DocCast(doc.emptyAudio), openFactoryLocation: OpenWhere.overlay}, + { toolTip: "Tap or drag to create a map", title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc, clickFactory: DocCast(doc.emptyMap)}, + { toolTip: "Tap or drag to create a chat assistant", title: "Chat Assist", icon: "book", dragFactory: doc.emptyChat as Doc, clickFactory: DocCast(doc.emptyChat)}, + { toolTip: "Tap or drag to create a screen grabber", title: "Grab", icon: "photo-video", dragFactory: doc.emptyScreengrab as Doc, clickFactory: DocCast(doc.emptyScreengrab), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, + { toolTip: "Tap or drag to create a WebCam recorder", title: "WebCam", icon: "photo-video", dragFactory: doc.emptyWebCam as Doc, clickFactory: DocCast(doc.emptyWebCam), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, + { toolTip: "Tap or drag to create a button", title: "Button", icon: "circle", dragFactory: doc.emptyButton as Doc, clickFactory: DocCast(doc.emptyButton)}, + { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, clickFactory: DocCast(doc.emptyScript), funcs: { hidden: "IsNoviceMode()"}}, + { toolTip: "Tap or drag to create a data viz node", title: "DataViz", icon: "chart-bar", dragFactory: doc.emptyDataViz as Doc, clickFactory: DocCast(doc.emptyDataViz)}, + { toolTip: "Tap or drag to create a journal entry", title: "Journal", icon: "book", dragFactory:doc.emptyDailyJournal as Doc,clickFactory: DocCast(doc.emptyDataJournal), }, + { toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon:"person-chalkboard",dragFactory: doc.emptySlide as Doc, clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, + { toolTip: "Tap or drag to create a view slide", title: "View Slide", icon: "address-card", dragFactory: doc.emptyViewSlide as Doc, clickFactory: DocCast(doc.emptyViewSlide), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, + { toolTip: "Tap or drag to create a data note", title: "MetaNote", icon: "window-maximize", dragFactory: doc.emptyMetaNote as Doc, clickFactory: DocCast(doc.emptyMetaNote), openFactoryAsDelegate: true, funcs: { hidden: "IsNoviceMode()"} }, + { toolTip: "Toggle a Calculator REPL", title: "replviewer", icon: "calculator", clickFactory: '' as unknown as Doc, openFactoryLocation: OpenWhere.overlay}, // hack: clickFactory is not a Doc but will get interpreted as a custom UI by the openDoc() onClick script ].map(tuple => ( { openFactoryLocation: OpenWhere.addRight, scripts: { onClick: 'openDoc(copyDragFactory(this.clickFactory,this.openFactoryAsDelegate), this.openFactoryLocation)', onDragStart: '{ return copyDragFactory(this.dragFactory,this.openFactoryAsDelegate); }'}, funcs: tuple.funcs, - ...tuple, })) + ...tuple, })); } /// Initalizes the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 9a57a5e6c..6f2f051cd 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -512,7 +512,7 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (
{this.pinButton}
{this.recordButton}
{this.calendarButton}
-
{this.aiEditorButton}
+ {this.view0?.HasAIEditor ?
{this.aiEditorButton}
: null}
{this.keywordButton}
{!Doc.UserDoc().documentLinksButton_fullMenu ? null :
{this.shareButton}
}
{this.menuButton}
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index b7e6318b1..573c28ccf 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -1,7 +1,7 @@ import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { ClientUtils, returnAll, returnFalse, returnOne, returnZero } from '../../ClientUtils'; +import { ClientUtils, returnFalse, returnOne, returnZero } from '../../ClientUtils'; import { emptyFunction } from '../../Utils'; import { Doc, DocListCast, Field, FieldResult, FieldType, StrListCast } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; @@ -253,7 +253,6 @@ export class SidebarAnnos extends ObservableReactComponent diff --git a/src/client/views/TemplateMenu.scss b/src/client/views/TemplateMenu.scss index 8879fc20d..049945517 100644 --- a/src/client/views/TemplateMenu.scss +++ b/src/client/views/TemplateMenu.scss @@ -40,12 +40,16 @@ height: 100%; width: 100%; max-height: 250px; + overflow: auto; .templateToggle, .chromeToggle { text-align: left; color: black; } + .collectionTreeView { + height: fit-content !important; + } input { margin-right: 10px; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 4f60acb18..112510265 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -720,7 +720,7 @@ export class CollectionStackingView extends CollectionSubView e.stopPropagation(); + onPassiveWheel = (e: WheelEvent) => this._props.isContentActive() && e.stopPropagation(); render() { TraceMobx(); const editableViewProps = { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 962fbdcd7..3497a62cb 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -467,7 +467,7 @@ export class CollectionTreeView extends CollectionSubView +
{!(this.Document instanceof Doc) || !this.treeChildren ? null : this.Document.treeView_HasOverlay ? ( DocumentView.SetLightboxDoc(this.Document), icon: 'external-link-alt' }); } appearanceItems.push({ description: 'Pin', event: () => this._props.pinToPres(this.Document, {}), icon: 'map-pin' }); - appearanceItems.push({ description: 'AI view', event: () => this._docView?.toggleAIEditor(), icon: 'map-pin' }); + this._componentView?.componentAIView?.() && appearanceItems.push({ description: 'AI view', event: () => this._docView?.toggleAIEditor(), icon: 'map-pin' }); !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template ', event: () => this._props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' }); !appearance && appearanceItems.length && cm.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'compass' }); @@ -660,7 +660,7 @@ export class DocumentViewInternal extends DocComponent (this.disableClickScriptFunc ? undefined : this.onClickHdlr); setHeight = (height: number) => { !this._props.suppressSetHeight && (this.layoutDoc._height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), height + 2 * NumCast(this.Document.borderWidth))); } // prettier-ignore setContentView = action((view: ViewBoxInterface) => { this._componentView = view; }); // prettier-ignore @@ -712,32 +712,34 @@ export class DocumentViewInternal extends DocComponent (this.aiContentsHeight() * (this._props.NativeWidth?.() || 1)) / (this._props.NativeHeight?.() || 1); aiContentsHeight = () => Math.max(10, this._props.PanelHeight() - this._aiWinHeight * this.uiBtnScaling); - aiEditor = () => ( - <> -
this.historyRef(this._oldAiWheel, (this._oldAiWheel = r))} - style={{ - transform: `scale(${this.uiBtnScaling})`, - height: this.aiContentsHeight() / this.uiBtnScaling, - width: ((this._props.PanelWidth() - this.aiContentsWidth()) * 0.95) / this.uiBtnScaling, - }}> - {this._componentView?.componentAIViewHistory?.() ?? null} -
-
this.historyRef(this._oldHistoryWheel, (this._oldHistoryWheel = r))}> -
- {this._componentView?.componentAIView?.() ?? null} - {this._props.DocumentView?.() ? : null} -
- - ); + @computed get aiEditor() { + return ( + <> +
this.historyRef(this._oldAiWheel, (this._oldAiWheel = r))} + style={{ + transform: `scale(${this.uiBtnScaling})`, + height: this.aiContentsHeight() / this.uiBtnScaling, + width: ((this._props.PanelWidth() - this.aiContentsWidth()) * 0.95) / this.uiBtnScaling, + }}> + {this._componentView?.componentAIViewHistory?.() ?? null} +
+
this.historyRef(this._oldHistoryWheel, (this._oldHistoryWheel = r))}> +
+ {this._componentView?.componentAIView?.() ?? null} + {this._props.DocumentView?.() ? : null} +
+ + ); + } @computed get tagsOverlay() { return (
(this.widgetDecorations ? this.widgetOverlay : null); + viewingAiEditor = () => (this._props.showAIEditor && this._componentView?.componentAIView?.() !== undefined ? this.aiEditor : null); @computed get viewBoxContents() { TraceMobx(); const isInk = this.layoutDoc._layout_isSvg && !this._props.LayoutTemplateString; @@ -770,8 +773,8 @@ export class DocumentViewInternal extends DocComponent
- {this._props.showAIEditor ? this.aiEditor() : this.tagsOverlayFunc()} + {this.viewingAiEditor() ?? this.tagsOverlayFunc()} {this.widgetOverlayFunc()} ); @@ -1256,6 +1259,7 @@ export class DocumentView extends DocComponent() { public get allLinks() { return this._docViewInternal?._allLinks ?? []; } // prettier-ignore public get TagBtnHeight() { return this._docViewInternal?.TagsBtnHeight; } // prettier-ignore public get UIBtnScaling() { return this._docViewInternal?.uiBtnScaling; } // prettier-ignore + public get HasAIEditor() { return !!this._docViewInternal?._componentView?.componentAIView?.(); } // prettier-ignore get LayoutFieldKey() { return Doc.LayoutFieldKey(this.Document, this._props.LayoutTemplateString); diff --git a/src/client/views/nodes/formattedText/DashFieldView.scss b/src/client/views/nodes/formattedText/DashFieldView.scss index 6db8abc7f..3734ad9cc 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.scss +++ b/src/client/views/nodes/formattedText/DashFieldView.scss @@ -26,6 +26,7 @@ display: inline-block; font-weight: normal; background: rgba(0, 0, 0, 0.1); + align-content: center; cursor: default; } .dashFieldView-fieldSpan { diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index bef999e6d..fbe4fd294 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1,5 +1,4 @@ /* eslint-disable no-use-before-define */ -import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { Property } from 'csstype'; @@ -21,7 +20,6 @@ import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, ForceServerWrite, U import { Id, ToString } from '../../../../fields/FieldSymbols'; import { InkTool } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; -import { PrefetchProxy } from '../../../../fields/Proxy'; import { RichTextField } from '../../../../fields/RichTextField'; import { ComputedField } from '../../../../fields/ScriptField'; import { BoolCast, Cast, DateCast, DocCast, FieldValue, NumCast, RTFCast, ScriptCast, StrCast } from '../../../../fields/Types'; @@ -35,7 +33,6 @@ import { DocUtils } from '../../../documents/DocUtils'; import { DictationManager } from '../../../util/DictationManager'; import { DragManager } from '../../../util/DragManager'; import { dropActionType } from '../../../util/DropActionTypes'; -import { MakeTemplate } from '../../../util/DropConverter'; import { LinkManager } from '../../../util/LinkManager'; import { RTFMarkup } from '../../../util/RTFMarkup'; import { SnappingManager } from '../../../util/SnappingManager'; @@ -855,42 +852,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - Doc.setNativeView(this.Document); - this.layoutDoc.layout_autoHeightMargins = undefined; - }, 'set plain view'), - icon: 'eye', - }); - changeItems.push({ - description: 'metadata', - event: undoable(() => { - this.dataDoc.layout_meta = Cast(Doc.UserDoc().emptyHeader, Doc, null)?.layout; - this.Document.layout_fieldKey = 'layout_meta'; - setTimeout(() => { - this.layoutDoc._header_height = this.layoutDoc._layout_autoHeightMargins = 50; - }, 50); - }, 'set metadata view'), - icon: 'eye', - }); - const noteTypesDoc = Cast(Doc.UserDoc().template_notes, Doc, null); - DocListCast(noteTypesDoc?.data).forEach(note => { - const icon: IconProp = StrCast(note.icon) as IconProp; - changeItems.push({ - description: StrCast(note.title), - event: undoable( - () => { - this.layoutDoc.layout_autoHeightMargins = undefined; - Doc.setNativeView(this.Document); - DocUtils.makeCustomViewClicked(this.Document, Docs.Create.TreeDocument, StrCast(note.title), note); - }, - `set ${StrCast(note.title)} view}` - ), - icon: icon, - }); - }); const highlighting: ContextMenuProps[] = []; const noviceHighlighting = ['Audio Tags', 'My Text', 'Text from Others', 'Bold Text']; const expertHighlighting = [...noviceHighlighting, 'Important Items', 'Ignore Items', 'Disagree Items', 'By Recent Minute', 'By Recent Hour']; @@ -952,20 +913,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - if (!this.layoutDoc.isTemplateDoc) { - MakeTemplate(this.Document); - } - Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.Document); - Doc.AddDocToList(Cast(Doc.UserDoc().template_notes, Doc, null), 'data', this.Document); - }, - icon: 'eye', - }); !appearance && appearanceItems.length && cm.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'eye' }); const options = cm.findByDescription('Options...'); @@ -988,14 +935,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - this.layoutDoc._layout_autoHeight = !this.layoutDoc._layout_autoHeight; - }, - icon: this.Document._layout_autoHeight ? 'lock' : 'unlock', - }); optionItems.push({ description: this.Document.savedAsSticker ? 'Sticker Saved!' : 'Save to Stickers', event: action(undoable(async () => await StickerPalette.addToPalette(this.Document), 'save to palette')), diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index 77c00537b..04315e886 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -113,7 +113,7 @@ export class RichTextRules { const inlineFieldKey = '$inline' + numInlines; // which field on the text document this annotation will write to const inlineLayoutKey = '$layout_' + inlineFieldKey; // the field holding the layout string that will render the inline annotation const textDocInline = Docs.Create.TextDocument('', { - _layout_fieldKey: inlineLayoutKey, + layout_fieldKey: inlineLayoutKey, _width: 75, _height: 35, annotationOn: this.Document[DocData], diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index e48337651..2db8d3b85 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -239,7 +239,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 MyStickers() { return DocCast(Doc.UserDoc().myStickers); } // 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 @@ -1062,14 +1062,14 @@ export namespace Doc { return ndoc; } - let _applyCount: number = 0; export function ApplyTemplate(templateDoc: Doc) { if (templateDoc) { const proto = new Doc(); + const applyCount = NumCast(templateDoc.dragFactory_count); proto.author = ClientUtils.CurrentUserEmail(); const target = Doc.MakeDelegate(proto); const targetKey = StrCast(templateDoc.layout_fieldKey, 'layout'); - const applied = ApplyTemplateTo(templateDoc, target, targetKey, templateDoc.title + '(...' + _applyCount++ + ')'); + const applied = ApplyTemplateTo(templateDoc, target, targetKey, templateDoc.title + '(...' + applyCount + ')'); target.layout_fieldKey = targetKey; //this and line above applied && (Doc.GetProto(applied).type = templateDoc.type); return applied; -- cgit v1.2.3-70-g09d2 From 1525fe600142d955fa24e939322f45cbca9d1cba Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 11 Apr 2025 12:53:15 -0400 Subject: fixed ViewGuid generation to never start with a number (enables text boxes to have css specific to a single Doc). cleaned up '%' style rules for text boxes. cleaned up custom style sheets in text boxes to only be created when needed and to improve highlighting bold text with context. --- src/ClientUtils.ts | 5 +- src/client/util/CaptureManager.tsx | 2 +- src/client/util/SettingsManager.tsx | 2 +- .../views/collections/CollectionDockingView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 119 ++++++++++----------- .../views/nodes/formattedText/RichTextRules.ts | 33 ++---- src/client/views/pdf/PDFViewer.tsx | 2 +- 9 files changed, 75 insertions(+), 94 deletions(-) (limited to 'src/client/views/nodes/formattedText/RichTextRules.ts') diff --git a/src/ClientUtils.ts b/src/ClientUtils.ts index e1f490c1a..03ff13924 100644 --- a/src/ClientUtils.ts +++ b/src/ClientUtils.ts @@ -476,7 +476,10 @@ export function smoothScrollHorizontal(duration: number, element: HTMLElement | export function addStyleSheet() { const style = document.createElement('style'); const sheets = document.head.appendChild(style); - return sheets.sheet; + return sheets; +} +export function removeStyleSheet(sheet?: HTMLStyleElement) { + sheet && document.head.removeChild(sheet); } export function addStyleSheetRule(sheet: CSSStyleSheet | null, selector: string, css: string | { [key: string]: string }, selectorPrefix = '.') { const propText = diff --git a/src/client/util/CaptureManager.tsx b/src/client/util/CaptureManager.tsx index 47f31612f..80af78898 100644 --- a/src/client/util/CaptureManager.tsx +++ b/src/client/util/CaptureManager.tsx @@ -13,7 +13,7 @@ import './CaptureManager.scss'; export class CaptureManager extends React.Component { // eslint-disable-next-line no-use-before-define public static Instance: CaptureManager; - static _settingsStyle = addStyleSheet(); + static _settingsStyle = addStyleSheet().sheet; @observable _document: Opt = undefined; @observable isOpen: boolean = false; // whether the CaptureManager is to be displayed or not. diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index 89e3686b2..88f1f3260 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -30,7 +30,7 @@ export enum ColorScheme { export class SettingsManager extends React.Component { // eslint-disable-next-line no-use-before-define public static Instance: SettingsManager; - static _settingsStyle = addStyleSheet(); + static _settingsStyle = addStyleSheet().sheet; @observable private _passwordResultText = ''; @observable private _playgroundMode = false; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 12a131deb..094e61db9 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -60,7 +60,7 @@ export class CollectionDockingView extends CollectionSubView() { public get HasFullScreen() { return this._goldenLayout._maximisedItem !== null; } - static _highlightStyleSheet = addStyleSheet(); + static _highlightStyleSheet = addStyleSheet().sheet; constructor(props: SubCollectionViewProps) { super(props); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index cbd92c159..d88d8c44d 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1161,7 +1161,7 @@ export class DocumentView extends DocComponent() { public static UniquifyId(inLightbox: boolean | undefined, id: string) { return (inLightbox ? 'lightbox-' : '') + id; } - public ViewGuid = DocumentView.UniquifyId(DocumentView.LightboxContains(this), Utils.GenerateGuid()); // a unique id associated with the main
. used by LinkBox's Xanchor to find the arrowhead locations. + public ViewGuid = DocumentView.UniquifyId(DocumentView.LightboxContains(this), 'D' + Utils.GenerateGuid()); // a unique id associated with the main
. used by LinkBox's Xanchor to find the arrowhead locations. public DocUniqueId = DocumentView.UniquifyId(DocumentView.LightboxContains(this), this.Document[Id]); constructor(props: DocumentViewProps) { diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 4b3f96bcf..bad4f5b13 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -54,7 +54,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() { } public static openSidebarWidth = 250; public static sidebarResizerWidth = 5; - static webStyleSheet = addStyleSheet(); + static webStyleSheet = addStyleSheet().sheet; private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt) => void); private _mainCont: React.RefObject = React.createRef(); private _outerRef: React.RefObject = React.createRef(); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index fbe4fd294..cfb6dfa12 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -13,7 +13,7 @@ import { EditorState, NodeSelection, Plugin, Selection, TextSelection, Transacti import { EditorView, NodeViewConstructor } from 'prosemirror-view'; import * as React from 'react'; import { BsMarkdownFill } from 'react-icons/bs'; -import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, ClientUtils, DivWidth, returnFalse, returnZero, setupMoveUpEvents, simMouseEvent, smoothScroll, StopEvent } from '../../../../ClientUtils'; +import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, ClientUtils, DivWidth, removeStyleSheet, returnFalse, returnZero, setupMoveUpEvents, simMouseEvent, smoothScroll, StopEvent } from '../../../../ClientUtils'; import { DateField } from '../../../../fields/DateField'; import { CreateLinkToActiveAudio, Doc, DocListCast, Field, FieldType, Opt, StrListCast } from '../../../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, ForceServerWrite, UpdatingFromServer } from '../../../../fields/DocSymbols'; @@ -101,12 +101,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { [key: string]: NodeViewConstructor }; - private static _globalHighlightsCache: string = ''; - private static _globalHighlights = new ObservableSet(['Audio Tags', 'Text from Others', 'Todo Items', 'Important Items', 'Disagree Items', 'Ignore Items']); - private static _highlightStyleSheet = addStyleSheet(); - private static _bulletStyleSheet = addStyleSheet(); - private static _userStyleSheet = addStyleSheet(); + private _curHighlights = new ObservableSet(['Audio Tags']); + private static _highlightStyleSheet = addStyleSheet().sheet; + private static _bulletStyleSheet = addStyleSheet().sheet; + private _userStyleSheetElement: HTMLStyleElement | undefined; + private _enteringStyle = false; private _oldWheel: HTMLDivElement | null = null; private _selectionHTML: string | undefined; private _sidebarRef = React.createRef(); @@ -696,45 +696,33 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - if (Array.from(highlights).join('') === FormattedTextBox._globalHighlightsCache) return; - setTimeout(() => { - FormattedTextBox._globalHighlightsCache = Array.from(highlights).join(''); - }); - clearStyleSheetRules(FormattedTextBox._userStyleSheet); - if (!highlights.includes('Audio Tags')) { - addStyleSheetRule(FormattedTextBox._userStyleSheet, 'audiotag', { display: 'none' }, ''); - } - if (highlights.includes('Text from Others')) { - addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-remote', { background: 'yellow' }); - } - if (highlights.includes('My Text')) { - addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-' + ClientUtils.CurrentUserEmail().replace(/\./g, '').replace(/@/g, ''), { background: 'moccasin' }); - } - if (highlights.includes('Todo Items')) { - addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-todo', { outline: 'black solid 1px' }); - } - if (highlights.includes('Important Items')) { - addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-important', { 'font-size': 'larger' }); - } - if (highlights.includes('Bold Text')) { - addStyleSheetRule(FormattedTextBox._userStyleSheet, '.formattedTextBox-inner .ProseMirror strong > span', { 'font-size': 'large' }, ''); - addStyleSheetRule(FormattedTextBox._userStyleSheet, '.formattedTextBox-inner .ProseMirror :not(strong > span)', { 'font-size': '0px' }, ''); - } - if (highlights.includes('Disagree Items')) { - addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-disagree', { 'text-decoration': 'line-through' }); - } - if (highlights.includes('Ignore Items')) { - addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-ignore', { 'font-size': '1' }); - } + const userStyleSheet = () => { + if (!this._userStyleSheetElement) { + this._userStyleSheetElement = addStyleSheet(); + } + return this._userStyleSheetElement.sheet; + }; + const viewId = this.DocumentView?.().ViewGuid ?? 1; + const userId = ClientUtils.CurrentUserEmail().replace(/\./g, '').replace('@', ''); // must match marks_rts -> user_mark's uid + highlights.filter(f => f !== 'Audio Tags').length && clearStyleSheetRules(userStyleSheet()); + if (!highlights.includes('Audio Tags')) addStyleSheetRule(userStyleSheet(), `#${viewId} .audiotag`, { display: 'none' }, ''); // prettier-ignore + if (highlights.includes('Text from Others')) addStyleSheetRule(userStyleSheet(), `#${viewId} .UM-remote`, { background: 'yellow' }, ''); // prettier-ignore + if (highlights.includes('My Text')) addStyleSheetRule(userStyleSheet(), `#${viewId} .UM-${userId}`, { background: 'moccasin' }, ''); // prettier-ignore + if (highlights.includes('Todo Items')) addStyleSheetRule(userStyleSheet(), `#${viewId} .UT-todo`, { outline: 'black solid 1px' }, ''); // prettier-ignore + if (highlights.includes('Important Items')) addStyleSheetRule(userStyleSheet(), `#${viewId} .UT-important`, { 'font-size': 'larger' }, ''); // prettier-ignore + if (highlights.includes('Disagree Items')) addStyleSheetRule(userStyleSheet(), `#${viewId} .UT-disagree`, { 'text-decoration': 'line-through' }, ''); // prettier-ignore + if (highlights.includes('Ignore Items')) addStyleSheetRule(userStyleSheet(), `#${viewId} .UT-ignore`, { 'font-size': '1' }, ''); // prettier-ignore + if (highlights.includes('Bold Text')) { addStyleSheetRule(userStyleSheet(), `#${viewId} .formattedTextBox-inner .ProseMirror p:not(:has(strong))`, { 'font-size': '0px' }, ''); + addStyleSheetRule(userStyleSheet(), `#${viewId} .formattedTextBox-inner .ProseMirror p:not(:has(strong)) ::after`, { content: '...', 'font-size': '5px' }, '')} // prettier-ignore if (highlights.includes('By Recent Minute')) { - addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-' + ClientUtils.CurrentUserEmail().replace('.', '').replace('@', ''), { opacity: '0.1' }); + addStyleSheetRule(userStyleSheet(), `#${viewId} .UM-${userId}`, { opacity: '0.1' }, ''); const min = Math.round(Date.now() / 1000 / 60); - numberRange(10).map(i => addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-min-' + (min - i), { opacity: ((10 - i - 1) / 10).toString() })); + numberRange(10).map(i => addStyleSheetRule(userStyleSheet(), `#${viewId} .UM-min-` + (min - i), { opacity: ((10 - i - 1) / 10).toString() }, '')); } if (highlights.includes('By Recent Hour')) { - addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-' + ClientUtils.CurrentUserEmail().replace('.', '').replace('@', ''), { opacity: '0.1' }); + addStyleSheetRule(userStyleSheet(), `#${viewId} .UM-${userId}`, { opacity: '0.1' }, ''); const hr = Math.round(Date.now() / 1000 / 60 / 60); - numberRange(10).map(i => addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-hr-' + (hr - i), { opacity: ((10 - i - 1) / 10).toString() })); + numberRange(10).map(i => addStyleSheetRule(userStyleSheet(), `#${viewId} .UM-hr-` + (hr - i), { opacity: ((10 - i - 1) / 10).toString() }, '')); } this.layoutDoc[DocCss] = this.layoutDoc[DocCss] + 1; // css changes happen outside of react/mobx. so we need to set a flag that will notify anyone interested in layout changes triggered by css changes (eg., CollectionLinkView) }; @@ -857,16 +845,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent highlighting.push({ - description: (!FormattedTextBox._globalHighlights.has(option) ? 'Highlight ' : 'Unhighlight ') + option, + description: (!this._curHighlights.has(option) ? 'Highlight ' : 'Unhighlight ') + option, event: action(() => { e.stopPropagation(); - if (!FormattedTextBox._globalHighlights.has(option)) { - FormattedTextBox._globalHighlights.add(option); + if (!this._curHighlights.has(option)) { + this._curHighlights.add(option); } else { - FormattedTextBox._globalHighlights.delete(option); + this._curHighlights.delete(option); } }), - icon: !FormattedTextBox._globalHighlights.has(option) ? 'highlighter' : 'remove-format', + icon: !this._curHighlights.has(option) ? 'highlighter' : 'remove-format', }) ); const appearance = cm.findByDescription('Appearance...'); @@ -1191,15 +1179,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent ({ autoHeight: this.layout_autoHeight, fontSize: this.fontSize, css: this.Document[DocCss], xMargin: this.Document.xMargin, yMargin: this.Document.yMargin }), autoHeight => setTimeout(() => autoHeight && this.tryUpdateScrollHeight()) ); - this._disposers.highlights = reaction( - () => Array.from(FormattedTextBox._globalHighlights).slice(), - highlights => this.updateHighlights(highlights), - { fireImmediately: true } - ); - this._disposers.width = reaction( - () => this._props.PanelWidth(), - () => this.tryUpdateScrollHeight() - ); + this._disposers.highlights = reaction(() => Array.from(this._curHighlights).slice(), this.updateHighlights, { fireImmediately: true }); + this._disposers.width = reaction(this._props.PanelWidth, this.tryUpdateScrollHeight); this._disposers.scrollHeight = reaction( () => ({ scrollHeight: this.scrollHeight, layoutAutoHeight: this.layout_autoHeight, width: NumCast(this.layoutDoc._width) }), ({ width, scrollHeight, layoutAutoHeight }) => width && layoutAutoHeight && this.resetNativeHeight(scrollHeight), @@ -1211,7 +1192,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { const newHeight = this.contentScaling * (marginsHeight + Math.max(sidebarHeight, textHeight)); if ( - (!Array.from(FormattedTextBox._globalHighlights).includes('Bold Text') || this._props.isSelected()) && // + (!Array.from(this._curHighlights).includes('Bold Text') || this._props.isSelected()) && // layoutAutoHeight && newHeight && (newHeight !== this.layoutDoc.height || border < NumCast(this.layoutDoc.height)) && @@ -1220,7 +1201,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent Doc.Links(this.dataDoc), // if a link is deleted, then remove all hyperlinks that reference it from the text's marks @@ -1275,7 +1256,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent disposer?.()); this.endUndoTypingBatch(); FormattedTextBox.LiveTextUndo?.end(); @@ -1766,13 +1748,30 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - if (!match[0].startsWith('%') && !this.EnteringStyle) return null; + // set the First-line indent node type for the selection's paragraph + new InputRule(/%d$/, (state, match, start, end) => { const pos = state.doc.resolve(start); for (let depth = pos.depth; depth >= 0; depth--) { const node = pos.node(depth); @@ -158,9 +155,8 @@ export class RichTextRules { return null; }), - // set the Hanging indent node type for the current selection's paragraph (assumes % was used to initiate an EnteringStyle mode) - new InputRule(/(%h|h)$/, (state, match, start, end) => { - if (!match[0].startsWith('%') && !this.EnteringStyle) return null; + // set the Hanging indent node type for the current selection's paragraph + new InputRule(/%h$/, (state, match, start, end) => { const pos = state.doc.resolve(start); for (let depth = pos.depth; depth >= 0; depth--) { const node = pos.node(depth); @@ -173,9 +169,8 @@ export class RichTextRules { return null; }), - // set the Quoted indent node type for the current selection's paragraph (assumes % was used to initiate an EnteringStyle mode) - new InputRule(/(%q|q)$/, (state, match, start, end) => { - if (!match[0].startsWith('%') && !this.EnteringStyle) return null; + // set the Quoted indent node type for the current selection's paragraph + new InputRule(/%q$/, (state, match, start, end) => { const pos = state.doc.resolve(start); if (state.selection instanceof NodeSelection && state.selection.node.type === schema.nodes.ordered_list) { const { node } = state.selection; @@ -410,22 +405,6 @@ export class RichTextRules { // # heading textblockTypeInputRule(/^(#{1,6})\s$/, schema.nodes.heading, match => ({ level: match[1].length })), - // set the Todo user-tag on the current selection (assumes % was used to initiate an EnteringStyle mode) - new InputRule(/[ti!x]$/, (state, match, start, end) => { - if (state.selection.to === state.selection.from || !this.EnteringStyle) return null; - - const tag = match[0] === 't' ? 'todo' : match[0] === 'i' ? 'ignore' : match[0] === 'x' ? 'disagree' : match[0] === '!' ? 'important' : '??'; - const node = state.doc.resolve(start).nodeAfter; - - if (node?.marks.findIndex(m => m.type === schema.marks.user_tag) !== -1) return state.tr.removeMark(start, end, schema.marks.user_tag); - return node - ? state.tr - .removeMark(start, end, schema.marks.user_mark) - .addMark(start, end, schema.marks.user_mark.create({ userid: ClientUtils.CurrentUserEmail(), modified: Math.floor(Date.now() / 1000) })) - .addMark(start, end, schema.marks.user_tag.create({ userid: ClientUtils.CurrentUserEmail(), tag: tag, modified: Math.round(Date.now() / 1000 / 60) })) - : state.tr; - }), - new InputRule(/%\(/, (state, match, start, end) => { const node = state.doc.resolve(start).nodeAfter; const sm = state.storedMarks?.slice() || []; diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 9aa0e8e8b..21d987587 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -55,7 +55,7 @@ interface IViewerProps extends FieldViewProps { */ @observer export class PDFViewer extends ObservableReactComponent { - static _annotationStyle = addStyleSheet(); + static _annotationStyle = addStyleSheet().sheet; constructor(props: IViewerProps) { super(props); -- cgit v1.2.3-70-g09d2 From d818ef151ca65008e5c6bb5e92b709decb3026d8 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 14 Apr 2025 18:35:49 -0400 Subject: fixed how templates are expanded to avoid template sub-component conflicts by changing how field keys are named. fixed various Cast functions to be more typesafe by including undefined as part of return type. overhaul of Doc.MakeClone, MakeCopy, FindRefernces - makeClone is no longer async. fixed inlined docs in text docs. --- src/client/documents/DocUtils.ts | 41 +- src/client/documents/DocumentTypes.ts | 2 +- src/client/documents/Documents.ts | 8 +- src/client/util/CurrentUserUtils.ts | 37 +- src/client/util/DictationManager.ts | 2 +- src/client/util/DocumentManager.ts | 2 +- src/client/util/DragManager.ts | 40 +- src/client/util/DropConverter.ts | 6 +- src/client/util/Import & Export/ImageUtils.ts | 2 +- src/client/util/LinkFollower.ts | 32 +- src/client/util/LinkManager.ts | 43 +- src/client/util/SearchUtil.ts | 6 +- src/client/util/SettingsManager.tsx | 2 +- src/client/views/DocComponent.tsx | 8 +- src/client/views/DocumentButtonBar.tsx | 8 +- src/client/views/FilterPanel.tsx | 4 +- src/client/views/GlobalKeyHandler.ts | 6 +- src/client/views/InkStrokeProperties.ts | 2 +- src/client/views/InkTranscription.tsx | 6 +- src/client/views/LightboxView.tsx | 4 +- src/client/views/Main.tsx | 4 +- src/client/views/MainView.tsx | 42 +- src/client/views/PinFuncs.ts | 8 +- src/client/views/PropertiesButtons.tsx | 2 +- src/client/views/PropertiesView.tsx | 8 +- src/client/views/StyleProvider.tsx | 12 +- src/client/views/StyleProviderQuiz.tsx | 2 +- src/client/views/TagsView.tsx | 6 +- src/client/views/animationtimeline/Timeline.tsx | 2 +- .../views/collections/CollectionCarouselView.tsx | 3 +- .../views/collections/CollectionDockingView.tsx | 16 +- .../views/collections/CollectionNoteTakingView.tsx | 11 +- .../views/collections/CollectionStackingView.tsx | 12 +- .../CollectionStackingViewFieldColumn.tsx | 4 +- src/client/views/collections/CollectionSubView.tsx | 37 +- src/client/views/collections/TabDocView.tsx | 14 +- src/client/views/collections/TreeView.tsx | 20 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 31 +- .../collectionFreeForm/FaceCollectionBox.tsx | 2 +- .../collectionFreeForm/ImageLabelBox.tsx | 4 +- .../collections/collectionFreeForm/MarqueeView.tsx | 6 +- .../collectionLinear/CollectionLinearView.tsx | 4 +- .../collectionSchema/CollectionSchemaView.tsx | 4 +- .../collectionSchema/SchemaTableCell.tsx | 2 +- src/client/views/global/globalScripts.ts | 37 +- src/client/views/newlightbox/NewLightboxView.tsx | 2 +- src/client/views/nodes/AudioBox.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 4 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 2 +- src/client/views/nodes/DocumentContentsView.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 100 ++-- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/IconTagBox.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 24 +- src/client/views/nodes/KeyValueBox.tsx | 8 +- src/client/views/nodes/KeyValuePair.tsx | 4 +- src/client/views/nodes/PDFBox.tsx | 2 +- .../views/nodes/RecordingBox/RecordingBox.tsx | 2 +- src/client/views/nodes/ScreenshotBox.tsx | 2 +- src/client/views/nodes/ScriptingBox.tsx | 13 +- src/client/views/nodes/WebBox.tsx | 18 +- .../nodes/chatbot/chatboxcomponents/ChatBox.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 55 +- .../views/nodes/formattedText/RichTextMenu.tsx | 6 +- .../views/nodes/formattedText/RichTextRules.ts | 19 +- src/client/views/nodes/trails/PresBox.tsx | 187 +++--- src/client/views/nodes/trails/PresElementBox.scss | 308 ---------- src/client/views/nodes/trails/PresElementBox.tsx | 628 --------------------- src/client/views/nodes/trails/PresSlideBox.scss | 308 ++++++++++ src/client/views/nodes/trails/PresSlideBox.tsx | 628 +++++++++++++++++++++ src/client/views/nodes/trails/index.ts | 2 +- src/client/views/pdf/GPTPopup/GPTPopup.tsx | 2 +- src/client/views/search/FaceRecognitionHandler.tsx | 4 +- src/client/views/search/SearchBox.tsx | 2 +- src/client/views/smartdraw/StickerPalette.tsx | 13 +- src/debug/Repl.tsx | 6 +- src/fields/Doc.ts | 486 ++++++++-------- src/fields/List.ts | 6 +- src/fields/Proxy.ts | 64 +-- src/fields/Schema.ts | 21 +- src/fields/ScriptField.ts | 12 +- src/fields/Types.ts | 91 +-- src/fields/util.ts | 10 +- 83 files changed, 1799 insertions(+), 1806 deletions(-) delete mode 100644 src/client/views/nodes/trails/PresElementBox.scss delete mode 100644 src/client/views/nodes/trails/PresElementBox.tsx create mode 100644 src/client/views/nodes/trails/PresSlideBox.scss create mode 100644 src/client/views/nodes/trails/PresSlideBox.tsx (limited to 'src/client/views/nodes/formattedText/RichTextRules.ts') diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts index 5a8230847..7845c80aa 100644 --- a/src/client/documents/DocUtils.ts +++ b/src/client/documents/DocUtils.ts @@ -55,13 +55,13 @@ export namespace DocUtils { const matchLink = (val: string, anchor: Doc) => { const linkedToExp = (val ?? '').split('='); if (linkedToExp.length === 1) return Field.toScriptString(anchor) === val; - return Field.toScriptString(DocCast(anchor[linkedToExp[0]])) === linkedToExp[1]; + return DocCast(anchor[linkedToExp[0]]) && 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 as string, DocCast(link.link_anchor_1)) || - matchLink(value as string, DocCast(link.link_anchor_2)) )); + (allLinks.some(link => (DocCast(link.link_anchor_1) && matchLink(value as string, DocCast(link.link_anchor_1)!)) || + (DocCast(link.link_anchor_2) && matchLink(value as string, DocCast(link.link_anchor_2)!)) )); } if (typeof value === 'string') { value = value.replace(`,${ClientUtils.noRecursionHack}`, ''); @@ -266,7 +266,7 @@ export namespace DocUtils { Object.keys(funcs) .filter(key => !key.endsWith('-setter')) .forEach(key => { - const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); + const cfield = ComputedField.DisableCompute(() => FieldValue(doc[key])); const func = funcs[key]; if (ScriptCast(cfield)?.script.originalScript !== func) { const setFunc = Cast(funcs[key + '-setter'], 'string', null); @@ -375,12 +375,13 @@ export namespace DocUtils { const documentList: ContextMenuProps[] = foo .filter(btnDoc => !btnDoc.hidden) - .map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)) + .map(btnDoc => DocCast(btnDoc?.dragFactory)) .filter(doc => doc && doc !== Doc.UserDoc().emptyTrail && doc.title) + .map(doc => doc!) .map(dragDoc => ({ description: ':' + StrCast(dragDoc.title).replace('Untitled ', ''), event: undoable(() => { - const newDoc = (Doc.isTemplateDoc(dragDoc) ? DocUtils.delegateDragFactory : DocUtils.copyDragFactory)(dragDoc); + const newDoc = (dragDoc.isTemplateDoc ? DocUtils.delegateDragFactory : DocUtils.copyDragFactory)(dragDoc); if (newDoc) { newDoc._author = ClientUtils.CurrentUserEmail(); newDoc.x = x; @@ -437,6 +438,7 @@ export namespace DocUtils { .filter(btnDoc => !btnDoc.hidden) .map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)) .filter(doc => doc && doc !== Doc.UserDoc().emptyTrail && doc !== Doc.UserDoc().emptyNote && doc.title) + .map(doc => doc!) .map(dragDoc => ({ description: ':' + StrCast(dragDoc.title).replace('Untitled ', ''), event: undoable(() => { @@ -494,11 +496,11 @@ export namespace DocUtils { .map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc) .filter(d => d.isTemplateDoc); // bcz: this is hacky -- want to have different templates be applied depending on the "type" of a document. but type is not reliable and there could be other types of template searches so this should be generalized - // first try to find a template that matches the specific document type (_). otherwise, fallback to a general match on + // first try to find a template that matches the specific document type (). otherwise, fallback to a general match on !docLayoutTemplate && allTemplates.forEach(tempDoc => { const templateType = StrCast(doc[templateName + '_fieldKey'] || doc.type); - StrCast(tempDoc.title) === templateName + '_' + templateType && (docLayoutTemplate = tempDoc); + StrCast(tempDoc.title) === templateName + (templateType[0].toUpperCase() + templateType.slice(1)) && (docLayoutTemplate = tempDoc); }); !docLayoutTemplate && allTemplates.forEach(tempDoc => { @@ -522,18 +524,13 @@ export namespace DocUtils { Doc.ApplyTemplateTo(docLayoutTemplate, doc, customName, undefined); } } else { - let fieldTemplate: Opt; - if (doc.data instanceof RichTextField || typeof doc.data === 'string') { - fieldTemplate = Docs.Create.TextDocument('', options); - } else if (doc.data instanceof PdfField) { - fieldTemplate = Docs.Create.PdfDocument('http://www.msn.com', options); - } else if (doc.data instanceof VideoField) { - fieldTemplate = Docs.Create.VideoDocument('http://www.cs.brown.edu', options); - } else if (doc.data instanceof AudioField) { - fieldTemplate = Docs.Create.AudioDocument('http://www.cs.brown.edu', options); - } else if (doc.data instanceof ImageField) { - fieldTemplate = Docs.Create.ImageDocument('http://www.cs.brown.edu', options); - } + const fieldTemplate = (() => { + if (doc.data instanceof RichTextField || typeof doc.data === 'string') return Docs.Create.TextDocument('', options); + if (doc.data instanceof PdfField) return Docs.Create.PdfDocument('http://www.msn.com', options); + if (doc.data instanceof VideoField) return Docs.Create.VideoDocument('http://www.cs.brown.edu', options); + if (doc.data instanceof AudioField) return Docs.Create.AudioDocument('http://www.cs.brown.edu', options); + if (doc.data instanceof ImageField) return Docs.Create.ImageDocument('http://www.cs.brown.edu', options); + })(); const docTemplate = creator?.(fieldTemplate ? [fieldTemplate] : [], { title: customName + '(' + doc.title + ')', isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) }); fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, docTemplate ? Doc.GetProto(docTemplate) : docTemplate); docTemplate && Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined); @@ -904,8 +901,8 @@ export namespace DocUtils { return ndoc; } - export async function Zip(doc: Doc, zipFilename = 'dashExport.zip') { - const { clone, map, linkMap } = await Doc.MakeClone(doc); + export function Zip(doc: Doc, zipFilename = 'dashExport.zip') { + const { clone, map, linkMap } = Doc.MakeClone(doc); const proms = new Set(); function replacer(key: string, value: { url: string; [key: string]: unknown }) { if (key && ['branchOf', 'cloneOf', 'cursors'].includes(key)) return undefined; diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index dd0985182..5c6559836 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -36,7 +36,7 @@ export enum DocumentType { // special purpose wrappers that either take no data or are compositions of lower level types LINK = 'link', PRES = 'presentation', - PRESELEMENT = 'preselement', + PRESSLIDE = 'presslide', COMPARISON = 'comparison', PUSHPIN = 'pushpin', MAPROUTE = 'maproute', diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index d93a432d4..bf9cc5bd4 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -217,7 +217,7 @@ export class DocumentOptions { author?: string; // STRt = new StrInfo('creator of document'); // bcz: don't change this. Otherwise, the userDoc's field Infos will have a FieldInfo assigned to its author field which will render it unreadable author_date?: DATEt = new DateInfo('date the document was created', true); annotationOn?: DOCt = new DocInfo('document annotated by this document', false); - rootDocument?: DOCt = new DocInfo('document that supplies the information needed for a rendering template (eg, pres slide for PresElement)'); + rootDocument?: DOCt = new DocInfo('document that stores the data for compound template documents.'); color?: STRt = new StrInfo('foreground color data doc', false); hidden?: BOOLt = new BoolInfo('whether the document is not rendered by its collection', false); backgroundColor?: STRt = new StrInfo('background color for data doc', false); @@ -1139,8 +1139,8 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.FONTICON), undefined, { ...(options || {}) }); } - export function PresElementBoxDocument() { - return Prototypes.get(DocumentType.PRESELEMENT); + export function PresSlideDocument() { + return Prototypes.get(DocumentType.PRESSLIDE); } export function DataVizDocument(url: string, options?: DocumentOptions, overwriteDoc?: Doc) { @@ -1148,7 +1148,7 @@ export namespace Docs { } export function AnnoPaletteDocument(options?: DocumentOptions) { - return InstanceFromProto(Prototypes.get(DocumentType.ANNOPALETTE), new List([Doc.MyStickers]), { ...(options || {}) }); + return InstanceFromProto(Prototypes.get(DocumentType.ANNOPALETTE), new List([...(Doc.MyStickers ? [Doc.MyStickers] : [])]), { ...(options || {}) }); } export function DockDocument(documents: Array, config: string, options: DocumentOptions, id?: string) { diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 35dc5f1c7..1887c1716 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -148,12 +148,12 @@ export class CurrentUserUtils { { title: "Idea", backgroundColor: "pink", icon: "lightbulb" , _layout_showTitle: "title"}, { title: "Topic", backgroundColor: "lightblue", icon: "book-open" , _layout_showTitle: "title"}]; - + const metanote = DocCast(doc.emptyMetaNote); const reqdNoteList = [...reqdTempOpts.map(opts => { const reqdOpts = {...opts, isSystem:true, width:200, layout_autoHeight: true, layout_fitWidth: true}; const noteTemp = tempNotes ? DocListCast(tempNotes.data).find(fdoc => fdoc.title === opts.title): undefined; return DocUtils.AssignOpts(noteTemp, reqdOpts) ?? MakeTemplate(Docs.Create.TextDocument("",reqdOpts)); - }), DocCast(doc.emptyMetaNote), ... DocListCast(tempNotes?.data).filter(note => !reqdTempOpts.find(reqd => reqd.title === note.title))]; + }), ...(metanote ? [metanote]:[]), ... DocListCast(tempNotes?.data).filter(note => !reqdTempOpts.find(reqd => reqd.title === note.title))]; const reqdOpts:DocumentOptions = { title: "Note Layouts", _height: 75, isSystem: true }; return DocUtils.AssignOpts(tempNotes, reqdOpts, reqdNoteList) ?? (doc[field] = Docs.Create.TreeDocument(reqdNoteList, reqdOpts)); @@ -211,7 +211,7 @@ export class CurrentUserUtils { const fontBox = (opts:DocumentOptions, fieldKey:string) => Docs.Create.FontIconDocument({ layout:FontIconBox.LayoutString(fieldKey), _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, ...opts }); const makeIconTemplate = (name: DocumentType | string | undefined, templateField: string, opts:DocumentOptions) => { - const title = "icon" + (name ? "_" + name : ""); + const title = "icon" + (name ? name[0].toUpperCase()+name.slice(1) : ""); const curIcon = DocCast(templateIconsDoc[title]); const creator = (() => { switch (opts.iconTemplate) { case DocumentType.IMG : return imageBox; @@ -424,7 +424,10 @@ pie title Minerals in my tap water const standardOps = (key:string) => ({ title : "Untitled "+ key, _layout_fitWidth: false, isSystem: true, "dragFactory_count": 0, cloneFieldFilter: new List(["isSystem"]) }); emptyThings.forEach( thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, thing.scripts, thing.funcs)); - DocCast(Doc.UserDoc().emptyMetaNote).title = "MetaNote"; // hack: metanotes are used a template, so 'untitled metaNote' is an awkward name + const metanote = DocCast(Doc.UserDoc().emptyMetaNote); + if (metanote) { + metanote.title = "MetaNote"; // hack: metanotes are used a template, so 'untitled metaNote' is an awkward name + } return [ { toolTip: "Tap or drag to create a note", title: "Note", icon: "sticky-note", dragFactory: doc.emptyNote as Doc, clickFactory: DocCast(doc.emptyNote)}, @@ -490,7 +493,7 @@ pie title Minerals in my tap water { title: "Tools", toolTip: "Tools", target: this.setupToolsBtnPanel(doc, "myTools"), icon: "wrench", }, { title: "Imports", toolTip: "Imports ⌘I", target: this.setupImportSidebar(doc, "myImports"), icon: "upload", }, { title: "Closed", toolTip: "Recently Closed", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), icon: "archive", hidden: true }, // this doc is hidden from the Sidebar, but it's still being used in MyFilesystem which ignores the hidden field - { title: "Shared", toolTip: "Shared Docs", target: Doc.MySharedDocs, icon: "users", funcs: {badgeValue: badgeValue}}, + { title: "Shared", toolTip: "Shared Docs", target: Doc.MySharedDocs??Doc.UserDoc(), icon: "users", funcs: {badgeValue: badgeValue}}, { title: "Trails", toolTip: "Trails ⌘R", target: Doc.UserDoc(), icon: "pres-trail", funcs: {target: getActiveDashTrails}}, { title: "Image Grouper", toolTip: "Image Grouper", target: this.setupImageGrouper(doc, "myImageGrouper"), icon: "folder-open", hidden: false }, { title: "Faces", toolTip: "Unique Faces", target: this.setupFaceCollection(doc, "myFaceCollection"), icon: "face-smile", hidden: false }, @@ -551,7 +554,6 @@ pie title Minerals in my tap water const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc, allTools?.length ? allTools[0]:undefined); const userTools = allTools && allTools?.length > 1 ? allTools[1]:undefined; const userBtns = CurrentUserUtils.setupUserDocumentCreatorButtons(doc, userTools); - // doc.myUserBtns = new PrefetchProxy(userBtns); const reqdToolOps:DocumentOptions = { title: "My Tools", isSystem: true, ignoreClick: true, layout_boxShadow: "0 0", layout_explainer: "This is a palette of documents that can be created.", _layout_dontCenter: "y", @@ -975,7 +977,10 @@ pie title Minerals in my tap water }; DocUtils.AssignDocField(doc, "mySharedDocs", opts => Docs.Create.TreeDocument([], opts, sharingDocumentId + "layout", sharingDocumentId), sharedDocOpts, undefined, sharedScripts); - if (!Doc.GetProto(DocCast(doc.mySharedDocs)).data_dashboards) Doc.GetProto(DocCast(doc.mySharedDocs)).data_dashboards = new List(); + const sharedDocs = DocCast(doc.mySharedDocs); + if (sharedDocs) { + if (!Doc.GetProto(sharedDocs).data_dashboards) Doc.GetProto(sharedDocs).data_dashboards = new List(); + } } /// Import option on the left side button panel @@ -1000,9 +1005,9 @@ pie title Minerals in my tap water static updateUserDocument(docIn: Doc, sharingDocumentId: string, linkDatabaseId: string) { const doc = docIn; DocUtils.AssignDocField(doc, "globalGroupDatabase", () => Docs.Prototypes.MainGroupDocument(), {}); - reaction(() => DateCast(DocCast(doc.globalGroupDatabase).data_modificationDate), + reaction(() => DateCast(DocCast(doc.globalGroupDatabase)?.data_modificationDate), async () => { - const groups = await DocListCastAsync(DocCast(doc.globalGroupDatabase).data); + const groups = await DocListCastAsync(DocCast(doc.globalGroupDatabase)?.data); const mygroups = groups?.filter(group => JSON.parse(StrCast(group.members)).includes(ClientUtils.CurrentUserEmail())) || []; SetCachedGroups(["Guest", ...(mygroups?.map(g => StrCast(g.title))??[])]); }, { fireImmediately: true }); @@ -1058,11 +1063,13 @@ pie title Minerals in my tap water SelectionManager.DeselectAll(); // this forces SelectionManager implementation to copy over to DocumentView's API. This also triggers the LinkManager to be created - Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyDashboards); - Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MySharedDocs); - Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyRecentlyClosed); + if (Doc.MyFilesystem) { + Doc.MyDashboards && Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyDashboards); + Doc.MyDashboards && Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyDashboards); + Doc.MyRecentlyClosed && Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyRecentlyClosed); + } - Doc.GetProto(DocCast(Doc.UserDoc().emptyWebpage)).data = new WebField("https://www.wikipedia.org"); + DocCast(Doc.UserDoc().emptyWebpage) && (Doc.GetProto(DocCast(Doc.UserDoc().emptyWebpage)!).data = new WebField("https://www.wikipedia.org")); DocServer.CacheNeedsUpdate() && setTimeout(UPDATE_SERVER_CACHE, 2500); setInterval(UPDATE_SERVER_CACHE, 120000); @@ -1142,7 +1149,7 @@ pie title Minerals in my tap water const file = input.files?.[0]; if (file?.type === 'application/zip' || file?.type === 'application/x-zip-compressed') { const doc = await Doc.importDocument(file); - const list = Cast(Doc.MyImports.data, listSpec(Doc), null); + const list = Cast(Doc.MyImports?.data, listSpec(Doc), null); doc instanceof Doc && list?.splice(0, 0, doc); } else if (input.files && input.files.length !== 0) { const disposer = OverlayView.ShowSpinner(); @@ -1150,7 +1157,7 @@ pie title Minerals in my tap water if (results.length !== input.files?.length) { alert("Error uploading files - possibly due to unsupported file types"); } - const list = Cast(Doc.MyImports.data, listSpec(Doc), null); + const list = Cast(Doc.MyImports?.data, listSpec(Doc), null); list?.splice(0, 0, ...results); disposer(); } else { diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index 2eef3da0e..dcef4a4fe 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -364,7 +364,7 @@ export namespace DictationManager { case 'nested collection':return Docs.Create.FreeformDocument([], {}); } // prettier-ignore })(); - created && Doc.AddDocToList(target.dataDoc, Doc.LayoutFieldKey(target.Document), created); + created && Doc.AddDocToList(target.dataDoc, Doc.LayoutDataKey(target.Document), created); } } }, diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 5ce005811..ad57c2a62 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -183,7 +183,7 @@ export class DocumentManager { static _howl: Howl; static playAudioAnno(doc: Doc) { - const anno = Cast(doc[Doc.LayoutFieldKey(doc) + '_audioAnnotations'], listSpec(AudioField), null)?.lastElement(); + const anno = Cast(doc[Doc.LayoutDataKey(doc) + '_audioAnnotations'], listSpec(AudioField), null)?.lastElement(); if (anno) { this._howl?.stop(); if (anno instanceof AudioField) { diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index e2e4c0fe4..a66e6998b 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -234,29 +234,27 @@ export namespace DragManager { dropDoc instanceof Doc && CreateLinkToActiveAudio(() => dropDoc); return dropDoc; }; - const finishDrag = async (e: DragCompleteEvent) => { + const finishDrag = (e: DragCompleteEvent) => { const { docDragData } = e; setTimeout(() => dragData.dragEnding?.()); onDropCompleted?.(e); // glr: optional additional function to be called - in this case with presentation trails if (docDragData && !docDragData.droppedDocuments.length) { docDragData.dropAction = dragData.userDropAction || dragData.dropAction; - docDragData.droppedDocuments = ( - await Promise.all( - dragData.draggedDocuments.map(async d => - !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart) - ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result as Doc) - : docDragData.dropAction === dropActionType.embed - ? Doc.BestEmbedding(d) - : docDragData.dropAction === dropActionType.add - ? d - : docDragData.dropAction === dropActionType.proto - ? d[DocData] - : docDragData.dropAction === dropActionType.copy - ? (await Doc.MakeClone(d)).clone - : d - ) + docDragData.droppedDocuments = dragData.draggedDocuments + .map(d => + !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart) + ? addAudioTag(ScriptCast(d.onDragStart)!.script.run({ this: d }).result as Doc) + : docDragData.dropAction === dropActionType.embed + ? Doc.BestEmbedding(d) + : docDragData.dropAction === dropActionType.add + ? d + : docDragData.dropAction === dropActionType.proto + ? d[DocData] + : docDragData.dropAction === dropActionType.copy + ? Doc.MakeClone(d).clone + : d ) - ).filter(d => d); + .filter(d => d); ![dropActionType.same, dropActionType.proto].includes(StrCast(docDragData.dropAction) as dropActionType) && docDragData.droppedDocuments // .filter(drop => !drop.dragOnlyWithinContainer || ['embed', 'copy'].includes(docDragData.dropAction as any)) @@ -364,7 +362,7 @@ export namespace DragManager { }; } - async function dispatchDrag(target: Element, e: PointerEvent, complete: DragCompleteEvent, pos: { x: number; y: number }, finishDrag?: (e: DragCompleteEvent) => void, options?: DragOptions, endDrag?: () => void) { + function dispatchDrag(target: Element, e: PointerEvent, complete: DragCompleteEvent, pos: { x: number; y: number }, finishDrag?: (e: DragCompleteEvent) => void, options?: DragOptions, endDrag?: () => void) { const dropArgs = { cancelable: true, // allows preventDefault() to be called to cancel the drop bubbles: true, @@ -380,7 +378,7 @@ export namespace DragManager { }; target.dispatchEvent(new CustomEvent('dashPreDrop', dropArgs)); UndoManager.StartTempBatch(); // run drag/drop in temp batch in case drop is not allowed (so we can undo any intermediate changes) - await finishDrag?.(complete); + finishDrag?.(complete); UndoManager.EndTempBatch(target.dispatchEvent(new CustomEvent('dashOnDrop', dropArgs))); // event return val is true unless the event preventDefault() is called options?.dragComplete?.(complete); endDrag?.(); @@ -566,11 +564,11 @@ export namespace DragManager { const targClassName = e.target instanceof HTMLElement && typeof e.target.className === 'string' ? e.target.className : ''; if (['lm_tab', 'lm_title_wrap', 'lm_tabs', 'lm_header'].includes(targClassName) && docDragData.draggedDocuments.length === 1) { if (!startWindowDragTimer) { - startWindowDragTimer = setTimeout(async () => { + startWindowDragTimer = setTimeout(() => { startWindowDragTimer = undefined; docDragData.dropAction = docDragData.userDropAction || dropActionType.same; AbortDrag(); - await finishDrag?.(new DragCompleteEvent(true, docDragData)); + finishDrag?.(new DragCompleteEvent(true, docDragData)); DragManager.StartWindowDrag?.(e, docDragData.droppedDocuments, aborted => { if (!aborted && (docDragData?.dropAction === dropActionType.move || docDragData?.dropAction === dropActionType.same)) { docDragData.removeDocument?.(docDragData?.draggedDocuments[0]); diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index 7d3f63448..b6b111930 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -3,7 +3,7 @@ import { DocData, DocLayout } from '../../fields/DocSymbols'; import { ObjectField } from '../../fields/ObjectField'; import { RichTextField } from '../../fields/RichTextField'; import { ComputedField, ScriptField } from '../../fields/ScriptField'; -import { StrCast } from '../../fields/Types'; +import { DocCast, StrCast } from '../../fields/Types'; import { ImageField } from '../../fields/URLField'; import { Docs, DocumentOptions } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; @@ -23,7 +23,7 @@ import { ScriptingGlobals } from './ScriptingGlobals'; */ function makeTemplate(doc: Doc, first: boolean = true): boolean { const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc; - if (layoutDoc.layout instanceof Doc) { + if (DocCast(layoutDoc.layout)) { return true; // its already a template } const layout = StrCast(layoutDoc.layout).match(/fieldKey={'[^']*'}/)?.[0]; @@ -68,7 +68,7 @@ export function MakeTemplate(doc: Doc) { * Makes a draggable button or image that will create a template doc Instance */ export function makeUserTemplateButtonOrImage(doc: Doc, image?: string) { - const layoutDoc = doc; // doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc; + const layoutDoc = doc; if (layoutDoc.type !== DocumentType.FONTICON) { !layoutDoc.isTemplateDoc && makeTemplate(layoutDoc); } diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts index 9c32ca25a..eae3460b3 100644 --- a/src/client/util/Import & Export/ImageUtils.ts +++ b/src/client/util/Import & Export/ImageUtils.ts @@ -15,7 +15,7 @@ export namespace ImageUtils { export const AssignImgInfo = (document: Doc, data?: Upload.InspectionResults) => { if (data) { data.nativeWidth && (document._height = (NumCast(document._width) * data.nativeHeight) / data.nativeWidth); - const field = '$' + Doc.LayoutFieldKey(document); + const field = '$' + Doc.LayoutDataKey(document); document[`${field}_nativeWidth`] = data.nativeWidth; document[`${field}_nativeHeight`] = data.nativeHeight; document[`${field}_path`] = data.source; diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 0e67dcfaa..6081c3fae 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -43,13 +43,13 @@ export class LinkFollower { }; public static traverseLink(link: Opt, sourceDoc: Doc, finished?: () => void, traverseBacklink?: boolean) { - const getView = (doc: Doc) => DocumentView.getFirstDocumentView(DocCast(doc.layout_unrendered ? doc.annotationOn : doc)); - const isAnchor = (source: Doc, anchor: Doc) => Doc.AreProtosEqual(anchor, source) || Doc.AreProtosEqual(anchor.annotationOn as Doc, source); + const getView = (doc: Doc) => DocumentView.getFirstDocumentView(DocCast(doc.layout_unrendered ? doc.annotationOn : doc)!); + const isAnchor = (source?: Doc, anchor?: Doc) => Doc.AreProtosEqual(anchor, source) || Doc.AreProtosEqual(DocCast(anchor?.annotationOn), source); const linkDocs = link ? [link] : Doc.Links(sourceDoc); - const fwdLinks = linkDocs.filter(l => isAnchor(sourceDoc, l.link_anchor_1 as Doc)); // link docs where 'sourceDoc' is link_anchor_1 - const backLinks = linkDocs.filter(l => isAnchor(sourceDoc, l.link_anchor_2 as Doc)); // link docs where 'sourceDoc' is link_anchor_2 - const fwdLinkWithoutTargetView = fwdLinks.find(l => !getView(DocCast(l.link_anchor_2))); - const backLinkWithoutTargetView = backLinks.find(l => !getView(DocCast(l.link_anchor_1))); + const fwdLinks = linkDocs.filter(l => isAnchor(sourceDoc, DocCast(l.link_anchor_1))); // link docs where 'sourceDoc' is link_anchor_1 + const backLinks = linkDocs.filter(l => isAnchor(sourceDoc, DocCast(l.link_anchor_2))); // link docs where 'sourceDoc' is link_anchor_2 + const fwdLinkWithoutTargetView = fwdLinks.find(l => !DocCast(l.link_anchor_2) || !getView(DocCast(l.link_anchor_2)!)); + const backLinkWithoutTargetView = backLinks.find(l => !DocCast(l.link_anchor_1) || !getView(DocCast(l.link_anchor_1)!)); const linkWithoutTargetDoc = traverseBacklink === undefined ? (fwdLinkWithoutTargetView ?? backLinkWithoutTargetView) : traverseBacklink ? backLinkWithoutTargetView : fwdLinkWithoutTargetView; const linkDocList = linkWithoutTargetDoc && !sourceDoc.followAllLinks ? [linkWithoutTargetDoc] : traverseBacklink === undefined ? fwdLinks.concat(backLinks) : traverseBacklink ? backLinks : fwdLinks; const followLinks = sourceDoc.followLinkToggle || sourceDoc.followAllLinks ? linkDocList : linkDocList.slice(0, 1); @@ -60,17 +60,17 @@ export class LinkFollower { return false; } followLinks.forEach(async linkDoc => { - const target = ( + const target = DocCast( sourceDoc === linkDoc.link_anchor_1 ? linkDoc.link_anchor_2 : sourceDoc === linkDoc.link_anchor_2 ? linkDoc.link_anchor_1 - : Doc.AreProtosEqual(sourceDoc, linkDoc.link_anchor_1 as Doc) || Doc.AreProtosEqual((linkDoc.link_anchor_1 as Doc).annotationOn as Doc, sourceDoc) + : Doc.AreProtosEqual(sourceDoc, DocCast(linkDoc.link_anchor_1)) || Doc.AreProtosEqual(DocCast(DocCast(linkDoc.link_anchor_1)?.annotationOn), sourceDoc) ? linkDoc.link_anchor_2 : linkDoc.link_anchor_1 - ) as Doc; - const srcAnchor: Doc = Doc.getOppositeAnchor(linkDoc, target) ?? sourceDoc; + ); if (target) { + const srcAnchor = Doc.getOppositeAnchor(linkDoc, target) ?? sourceDoc; const doFollow = (canToggle?: boolean) => { const toggleTarget = canToggle && BoolCast(sourceDoc.followLinkToggle); const options: FocusViewOptions = { @@ -102,14 +102,16 @@ export class LinkFollower { if (srcAnchor.followLinkLocation === OpenWhere.inParent) { const sourceDocParent = DocCast(sourceDoc.embedContainer); if (target.embedContainer instanceof Doc && target.embedContainer !== sourceDocParent) { - Doc.RemoveDocFromList(target.embedContainer, Doc.LayoutFieldKey(target.embedContainer), target); + Doc.RemoveDocFromList(target.embedContainer, Doc.LayoutDataKey(target.embedContainer), target); movedTarget = true; } - if (!DocListCast(sourceDocParent[Doc.LayoutFieldKey(sourceDocParent)]).includes(target)) { - Doc.AddDocToList(sourceDocParent, Doc.LayoutFieldKey(sourceDocParent), target); - movedTarget = true; + if (sourceDocParent) { + if (!DocListCast(sourceDocParent[Doc.LayoutDataKey(sourceDocParent)]).includes(target)) { + Doc.AddDocToList(sourceDocParent, Doc.LayoutDataKey(sourceDocParent), target); + movedTarget = true; + } + Doc.SetContainer(target, sourceDocParent); } - Doc.SetContainer(target, sourceDocParent); } const moveTo = [NumCast(sourceDoc.x) + NumCast(sourceDoc.followLinkXoffset), NumCast(sourceDoc.y) + NumCast(sourceDoc.followLinkYoffset)]; if (srcAnchor.followLinkXoffset !== undefined && moveTo[0] !== target.x) { diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 3f98ab3c4..344e2e4c0 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -136,7 +136,7 @@ export class LinkManager { true ); FieldLoader.ServerLoadStatus.message = 'links'; - this.addLinkDB(Doc.LinkDBDoc()); + Doc.LinkDBDoc() && this.addLinkDB(Doc.LinkDBDoc()!); } public createlink_relationshipLists = () => { @@ -148,16 +148,21 @@ export class LinkManager { public addLink(linkDoc: Doc, checkExists = false) { Doc.AddDocToList(Doc.UserDoc(), 'links', linkDoc); - if (!checkExists || !DocListCast(Doc.LinkDBDoc().data).includes(linkDoc)) { - Doc.AddDocToList(Doc.LinkDBDoc(), 'data', linkDoc); - // eslint-disable-next-line no-use-before-define - setTimeout(UPDATE_SERVER_CACHE, 100); + if (Doc.LinkDBDoc()) { + if (!checkExists || !DocListCast(Doc.LinkDBDoc()!.data).includes(linkDoc)) { + Doc.AddDocToList(Doc.LinkDBDoc()!, 'data', linkDoc); + // eslint-disable-next-line no-use-before-define + setTimeout(UPDATE_SERVER_CACHE, 100); + } } } public deleteLink(linkDoc: Doc) { - const ret = Doc.RemoveDocFromList(Doc.LinkDBDoc(), 'data', linkDoc); - linkDoc.$link_anchor_1 = linkDoc.$link_anchor_2 = undefined; - return ret; + if (Doc.LinkDBDoc()) { + const ret = Doc.RemoveDocFromList(Doc.LinkDBDoc()!, 'data', linkDoc); + linkDoc.$link_anchor_1 = linkDoc.$link_anchor_2 = undefined; + return ret; + } + return false; } public deleteAllLinksOnAnchor(anchor: Doc) { LinkManager.Instance.relatedLinker(anchor).forEach(LinkManager.Instance.deleteLink); @@ -178,8 +183,8 @@ export class LinkManager { } const dirLinks = Array.from(anchor[DocData][DirectLinks]).filter(l => Doc.GetProto(anchor) === anchor[DocData] || ['1', '2'].includes(LinkManager.anchorIndex(l, anchor) as '0' | '1' | '2')); - const anchorRoot = DocCast(anchor.rootDocument, anchor); // template Doc fields store annotations on the topmost root of a template (not on themselves since the template layout items are only for layout) - const annos = DocListCast(anchorRoot[Doc.LayoutFieldKey(anchor) + '_annotations']); + const anchorRoot = DocCast(anchor.rootDocument, anchor)!; // template Doc fields store annotations on the topmost root of a template (not on themselves since the template layout items are only for layout) + const annos = DocListCast(anchorRoot[Doc.LayoutDataKey(anchor) + '_annotations']); return Array.from( annos.reduce((set, anno) => { if (!processed.includes(anno)) { @@ -242,11 +247,13 @@ export function UPDATE_SERVER_CACHE() { .filter(doc => doc instanceof Doc) .map(doc => doc as Doc); const references = new Set(prototypes); + DocCast(Doc.UserDoc().myLinkDatabase) && references.add(DocCast(Doc.UserDoc().myLinkDatabase)!); // prevent crawling through link database here -- see below Doc.FindReferences(Doc.UserDoc(), references, undefined); - DocListCast(DocCast(Doc.UserDoc().myLinkDatabase).data).forEach(link => { - if (!references.has(DocCast(link.link_anchor_1)) && !references.has(DocCast(link.link_anchor_2))) { - Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myLinkDatabase), 'data', link); - Doc.AddDocToList(Doc.MyRecentlyClosed, undefined, link); + + DocListCast(DocCast(Doc.UserDoc().myLinkDatabase)?.data).forEach(link => { + if (DocCast(link.link_anchor_1) && !references.has(DocCast(link.link_anchor_1)!) && DocCast(link.link_anchor_2) && !references.has(DocCast(link.link_anchor_2)!)) { + DocCast(Doc.UserDoc().myLinkDatabase) && Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myLinkDatabase)!, 'data', link); + Doc.MyRecentlyClosed && Doc.AddDocToList(Doc.MyRecentlyClosed, undefined, link); } }); LinkManager.Instance.userLinkDBs.forEach(linkDb => Doc.FindReferences(linkDb, references, undefined)); @@ -257,10 +264,10 @@ export function UPDATE_SERVER_CACHE() { cacheDocumentIds = newCacheUpdate; // print out cached docs - //Doc.MyDockedBtns.linearView_IsOpen && console.log('Set cached docs = '); - // const isFiltered = filtered.filter(doc => !Doc.IsSystem(doc)); - // const strings = isFiltered.map(doc => StrCast(doc.title) + ' ' + (Doc.IsDataProto(doc) ? '(data)' : '(embedding)')); - //Doc.MyDockedBtns.linearView_IsOpen && strings.sort().forEach((str, i) => console.log(i.toString() + ' ' + str)); + Doc.MyDockedBtns?.linearView_IsOpen && console.log('Set cached docs = '); + const isFiltered = filtered.filter(doc => !Doc.IsSystem(doc)); + const strings = isFiltered.map(doc => StrCast(doc.title) + ' ' + (Doc.IsDataProto(doc) ? '(data)' : '(embedding)')); + Doc.MyDockedBtns?.linearView_IsOpen && strings.sort().forEach((str, i) => console.log(i.toString() + ' ' + str)); rp.post(ClientUtils.prepend('/setCacheDocumentIds'), { body: { diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index 733eae5f4..e4adcaa7e 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -9,7 +9,7 @@ export namespace SearchUtil { export type HighlightingResult = { [id: string]: { [key: string]: string[] } }; export function SearchCollection(collectionDoc: Opt, queryIn: string, matchKeyNames: boolean, onlyKeys?: string[]) { - const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING]; + const blockedTypes = [DocumentType.PRESSLIDE, DocumentType.CONFIG, DocumentType.KVP, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING]; const blockedKeys = matchKeyNames ? [] : Object.entries(DocOptions) @@ -21,7 +21,7 @@ export namespace SearchUtil { const results = new ObservableMap(); if (collectionDoc) { - const docs = DocListCast(collectionDoc[Doc.LayoutFieldKey(collectionDoc)]); + const docs = DocListCast(collectionDoc[Doc.LayoutDataKey(collectionDoc)]); // eslint-disable-next-line @typescript-eslint/ban-types const docIDs: String[] = []; SearchUtil.foreachRecursiveDoc(docs, (depth: number, doc: Doc) => { @@ -77,7 +77,7 @@ export namespace SearchUtil { // eslint-disable-next-line no-loop-func docs.filter(d => d && !visited.includes(d)).forEach(d => { visited.push(d); - const fieldKey = Doc.LayoutFieldKey(d); + const fieldKey = Doc.LayoutDataKey(d); const annos = !Field.toString(Doc.LayoutField(d) as FieldType).includes('CollectionView'); const data = d[annos ? fieldKey + '_annotations' : fieldKey]; data && newarray.push(...DocListCast(data)); diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index 88f1f3260..9e79fd870 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -578,7 +578,7 @@ export class SettingsManager extends React.Component {
{ClientUtils.CurrentUserEmail()}
-