From d0fccd1050f5d6ccc24c1e4d2b7d1c0ed94fb2a7 Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 23 Mar 2025 10:27:28 -0400 Subject: updated more [DocData] to .$ things --- src/client/views/global/globalScripts.ts | 49 +++++++++++++------------------- 1 file changed, 20 insertions(+), 29 deletions(-) (limited to 'src/client/views/global') diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index 835c28daa..79d0ee88f 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -1,15 +1,12 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { Colors } from '@dash/components'; import { runInAction } from 'mobx'; -import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc'; -import { DocData } from '../../../fields/DocSymbols'; +import { Doc, Opt, StrListCast } from '../../../fields/Doc'; import { InkEraserTool, InkInkTool, InkProperty, InkTool } from '../../../fields/InkField'; -import { List } from '../../../fields/List'; import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; import { Gestures } from '../../../pen-gestures/GestureTypes'; -import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; -import { Docs } from '../../documents/Documents'; +import { DocumentType } from '../../documents/DocumentTypes'; import { LinkManager } from '../../util/LinkManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SnappingManager } from '../../util/SnappingManager'; @@ -17,30 +14,30 @@ import { UndoManager, undoable } from '../../util/UndoManager'; import { GestureOverlay } from '../GestureOverlay'; import { InkTranscription } from '../InkTranscription'; import { PropertiesView } from '../PropertiesView'; +import { docSortings } from '../collections/CollectionSubView'; import { CollectionFreeFormView } from '../collections/collectionFreeForm'; import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; import { ActiveEraserWidth, - ActiveInkFillColor, - ActiveInkColor, ActiveHideTextLabels, + ActiveInkColor, + ActiveInkFillColor, ActiveInkWidth, ActiveIsInkMask, DocumentView, - SetActiveInkFillColor, SetActiveInkColor, - SetactiveHideTextLabels, + SetActiveInkFillColor, SetActiveInkWidth, SetActiveIsInkMask, SetEraserWidth, + SetactiveHideTextLabels, } from '../nodes/DocumentView'; import { ImageBox } from '../nodes/ImageBox'; +import { OpenWhere } from '../nodes/OpenWhere'; import { VideoBox } from '../nodes/VideoBox'; import { WebBox } from '../nodes/WebBox'; import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup'; -import { OpenWhere } from '../nodes/OpenWhere'; -import { docSortings } from '../collections/CollectionSubView'; // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function IsNoneSelected() { @@ -101,10 +98,7 @@ ScriptingGlobals.add(function setBorderColor(color?: string, checkResult?: boole return (selected.lastElement() ?? Doc.UserDoc()).borderColor ?? defaultBorder(); } if (!selected.length) setDefaultBorder(color ?? 'transparent'); - else - selected.forEach(doc => { - doc[DocData].borderColor = color; - }); + else selected.forEach(doc => (doc.$borderColor = color)); } return ''; }); @@ -114,7 +108,7 @@ ScriptingGlobals.add(function setBorderColor(color?: string, checkResult?: boole ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: boolean) { const selectedViews = DocumentView.Selected(); const selectedDoc = selectedViews.lastElement()?.Document; - const defaultFill = selectedDoc?._layout_isSvg ? () => StrCast(selectedDoc[DocData].fillColor) : !Doc.ActiveTool || Doc.ActiveTool === InkTool.None ? () => StrCast(Doc.UserDoc().textBackgroundColor, 'transparent') : () => ActiveInkFillColor(); + const defaultFill = selectedDoc?._layout_isSvg ? () => StrCast(selectedDoc.$fillColor) : !Doc.ActiveTool || Doc.ActiveTool === InkTool.None ? () => StrCast(Doc.UserDoc().textBackgroundColor, 'transparent') : () => ActiveInkFillColor(); const setDefaultFill = !Doc.ActiveTool || Doc.ActiveTool === InkTool.None ? (c: string) => { Doc.UserDoc().textBackgroundColor = c; }: SetActiveInkFillColor; // prettier-ignore if (Doc.ActiveTool !== InkTool.None && !selectedViews.lastElement()?.Document._layout_isSvg) { if (checkResult) return defaultFill(); @@ -149,10 +143,7 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b return selected.lastElement()?._backgroundColor ?? defaultFill(); } if (!selected.length) setDefaultFill(color ?? 'transparent'); - else - selected.forEach(doc => { - doc[DocData][doc._layout_isSvg ? 'fillColor' : 'backgroundColor'] = color; - }); + else selected.forEach(doc => (doc[doc._layout_isSvg ? '$fillColor' : '$backgroundColor'] = color)); } return ''; }); @@ -170,7 +161,7 @@ ScriptingGlobals.add(function setHeaderColor(color?: string, checkResult?: boole } if (DocumentView.Selected().length) { DocumentView.SelectedDocs().forEach(doc => { - doc[DocData].layout_headingColor = color === 'transparent' ? undefined : color; + doc.$layout_headingColor = color === 'transparent' ? undefined : color; doc.layout_showTitle = color === 'transparent' ? undefined : StrCast(doc.layout_showTitle, 'title'); }); } else { @@ -470,23 +461,23 @@ ScriptingGlobals.add(function setInkProperty(option: InkProperty, value: string // prettier-ignore const map: Map number|boolean|string|undefined; setInk: (doc: Doc) => void; setMode: () => void }> = new Map([ [InkProperty.Mask, { - checkResult: () => ((selected?._layout_isSvg ? BoolCast(selected[DocData].stroke_isInkMask) : ActiveIsInkMask())), - setInk: (doc: Doc) => { doc[DocData].stroke_isInkMask = !doc.stroke_isInkMask; }, + checkResult: () => ((selected?._layout_isSvg ? BoolCast(selected.$stroke_isInkMask) : ActiveIsInkMask())), + setInk: (doc: Doc) => { doc.$stroke_isInkMask = !doc.stroke_isInkMask; }, setMode: () => SetActiveIsInkMask(value ? true : false) }], [InkProperty.Labels, { - checkResult: () => ((selected?._layout_isSvg ? BoolCast(selected[DocData].stroke_showLabel) : !ActiveHideTextLabels())), - setInk: (doc: Doc) => { doc[DocData].stroke_showLabel = value; }, + checkResult: () => ((selected?._layout_isSvg ? BoolCast(selected.$stroke_showLabel) : !ActiveHideTextLabels())), + setInk: (doc: Doc) => { doc.$stroke_showLabel = value; }, setMode: () => SetactiveHideTextLabels(value? false : true), }], [ InkProperty.StrokeWidth, { - checkResult: () => (selected?._layout_isSvg ? NumCast(selected[DocData].stroke_width, 1) : ActiveInkWidth()), - setInk: (doc: Doc) => { doc[DocData].stroke_width = NumCast(value); }, + checkResult: () => (selected?._layout_isSvg ? NumCast(selected.$stroke_width, 1) : ActiveInkWidth()), + setInk: (doc: Doc) => { doc.$stroke_width = NumCast(value); }, setMode: () => SetActiveInkWidth(value.toString()), }], [InkProperty.StrokeColor, { - checkResult: () => (selected?._layout_isSvg? StrCast(selected[DocData].color) : ActiveInkColor()), - setInk: (doc: Doc) => { doc[DocData].color = String(value); }, + checkResult: () => (selected?._layout_isSvg? StrCast(selected.$color) : ActiveInkColor()), + setInk: (doc: Doc) => { doc.$color = String(value); }, setMode: () => SetActiveInkColor(StrCast(value)) }], [ InkProperty.EraserWidth, { -- cgit v1.2.3-70-g09d2 From 6c8effb77029db96bccab92152a6b68a0aefc132 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 1 Apr 2025 13:30:06 -0400 Subject: fixed text views to write/read font_ from data doc. --- src/client/views/global/globalScripts.ts | 4 +-- .../views/nodes/formattedText/FormattedTextBox.tsx | 38 +++++++++++----------- 2 files changed, 21 insertions(+), 21 deletions(-) (limited to 'src/client/views/global') diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index 79d0ee88f..04b2873d1 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -367,8 +367,8 @@ ScriptingGlobals.add(function toggleCharStyle(charStyle: attrname, checkResult?: toggle: () => editorView?.state && RichTextMenu.Instance?.changeListType(list) }]); // prettier-ignore const attrs:attrfuncs[] = [ - ['dictation', { checkResult: () => !!textView?._recordingDictation, - toggle: () => textView && runInAction(() => { textView._recordingDictation = !textView._recordingDictation;} ) }], + ['dictation', { checkResult: () => !!textView?.recordingDictation, + toggle: () => textView && runInAction(() => { textView.recordingDictation = !textView.recordingDictation;} ) }], ['fitBox', { checkResult: () => RichTextMenu.Instance?.fitBox ?? false, toggle: () => RichTextMenu.Instance?.toggleFitBox()}], ['elide', { checkResult: () => false, diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 6955e5401..f7e6d8e1e 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -141,20 +141,20 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - if (this.EditorView && this._recordingDictation) { + if (this.EditorView && this.recordingDictation) { this.stopDictation(/* true */); this._break = true; const { state } = this.EditorView; const { to } = state.selection; const updated = TextSelection.create(state.doc, to, to); this.EditorView.dispatch(state.tr.setSelection(updated).insert(to, state.schema.nodes.paragraph.create({}))); - if (this._recordingDictation) { + if (this.recordingDictation) { this.recordDictation(); } } @@ -1333,14 +1333,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent this._recordingDictation, + () => this.recordingDictation, () => { this.stopDictation(/* true */); - this._recordingDictation && this.recordDictation(); + this.recordingDictation && this.recordDictation(); }, { fireImmediately: true } ); - if (this._recordingDictation) setTimeout(this.recordDictation); + if (this.recordingDictation) setTimeout(this.recordDictation); } this._disposers.scroll = reaction( () => NumCast(this.layoutDoc._layout_scrollTop), @@ -1560,8 +1560,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent disposer?.()); this.endUndoTypingBatch(); @@ -1596,7 +1596,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent @@ -1919,7 +1919,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - this._recordingDictation = !this._recordingDictation; + this.recordingDictation = !this.recordingDictation; }) ) }> -- cgit v1.2.3-70-g09d2 From 031a607100700f818f96b7fbf478f1b75292be9b Mon Sep 17 00:00:00 2001 From: bobzel Date: Sat, 5 Apr 2025 00:01:53 -0400 Subject: fixed sizing of text box annotations sidebar button. cleaned up TagsView to not overlap button bar below doc decorations or bottom resize handle --- src/client/views/AntimodeMenu.tsx | 2 + src/client/views/DocumentDecorations.scss | 3 +- src/client/views/DocumentDecorations.tsx | 34 +++++------ src/client/views/SidebarAnnos.scss | 10 ++++ src/client/views/SidebarAnnos.tsx | 7 +-- src/client/views/TagsView.scss | 3 +- src/client/views/TagsView.tsx | 21 +++++-- .../views/global/globalCssVariables.module.scss | 2 +- src/client/views/nodes/DocumentView.scss | 4 +- src/client/views/nodes/DocumentView.tsx | 3 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 65 ++++++++++++++-------- 11 files changed, 98 insertions(+), 56 deletions(-) (limited to 'src/client/views/global') diff --git a/src/client/views/AntimodeMenu.tsx b/src/client/views/AntimodeMenu.tsx index 99dee6410..b5e56cad5 100644 --- a/src/client/views/AntimodeMenu.tsx +++ b/src/client/views/AntimodeMenu.tsx @@ -4,6 +4,7 @@ import { SnappingManager } from '../util/SnappingManager'; import './AntimodeMenu.scss'; import { ObservableReactComponent } from './ObservableReactComponent'; +// eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface AntimodeMenuProps {} /** @@ -162,6 +163,7 @@ export abstract class AntimodeMenu extends Observab transitionDuration: this._transitionDuration, transitionDelay: this._transitionDelay, position: this.Pinned ? 'unset' : undefined, + border: `${SnappingManager.userColor} solid 1px`, }}> {buttons} diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 732c2645e..28cebe23c 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -41,6 +41,7 @@ $resizeHandler: 8px; .documentDecorations-tagsView { position: absolute; height: 100%; + width: 100%; pointer-events: all; border-radius: 50%; color: black; @@ -327,7 +328,7 @@ $resizeHandler: 8px; .documentDecorations-rightResizer { pointer-events: auto; background: global.$medium-gray-dim; - //opacity: 0.2; + opacity: 0.2; &:hover { opacity: 1; } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 875eb45e0..452dd60ee 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -49,7 +49,7 @@ export class DocumentDecorations extends ObservableReactComponent(); - private _resizeBorderWidth = 16; + private _resizeBorderWidth = 8; private _linkBoxHeight = 20 + 3; // link button height + margin private _titleHeight = 20; private _resizeUndo?: UndoManager.Batch; @@ -98,11 +98,11 @@ export class DocumentDecorations extends ObservableReactComponent
- {(seldocview.TagPanelHeight ?? 0) > 30 ? null :
} + {seldocview.TagPanelHeight !== 0 || seldocview.TagPanelEditing ? null :
}
)} @@ -850,12 +850,12 @@ export class DocumentDecorations extends ObservableReactComponent )} - {hideDocumentButtonBar || this._showNothing ? null : ( + {seldocview.TagPanelEditing || hideDocumentButtonBar || this._showNothing ? null : (
1 ? 0 : `${seldocview.showTags ? 4 + seldocview.TagPanelHeight : 4}px`, - transform: `translate(${-this._resizeBorderWidth / 2 + 10}px, ${this._resizeBorderWidth + bounds.b - bounds.y + this._titleHeight}px) `, + top: DocumentView.Selected().length > 1 || !seldocview.showTags ? 0 : `${seldocview.TagPanelHeight}px`, + transform: `translate(${-this._resizeBorderWidth + 10}px, ${(seldocview.TagPanelHeight === 0 ? 2 * this._resizeBorderWidth : this._resizeBorderWidth) + bounds.b - bounds.y + this._titleHeight}px) `, }}> DocumentView.Selected()} />
@@ -864,7 +864,7 @@ export class DocumentDecorations extends ObservableReactComponent {DocumentView.Selected().length > 1 ? : null}
diff --git a/src/client/views/SidebarAnnos.scss b/src/client/views/SidebarAnnos.scss index d7de2b641..abfd04f11 100644 --- a/src/client/views/SidebarAnnos.scss +++ b/src/client/views/SidebarAnnos.scss @@ -1,3 +1,13 @@ +.sidebarAnnos-container { + position: absolute; + width: 100%; + height: 100%; + right: 0; + .sidebarAnnos-stacking { + width: 100%; + position: relative; + } +} .sidebarAnnos-tagList { display: flex; flex-direction: row; diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 3c0611f03..b7e6318b1 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -213,14 +213,11 @@ export class SidebarAnnos extends ObservableReactComponent
e.stopPropagation()}> {this.allUsers.length > 1 ? this.allUsers.map(renderUsers) : null} @@ -228,7 +225,7 @@ export class SidebarAnnos extends ObservableReactComponent -
+
{ super(props); makeObservable(this); } - InsetDist = 25; // how far tag panel is moved up to overlap DocumentView. @observable _panelHeightDirty = 0; @observable _currentInput = ''; @@ -298,8 +297,8 @@ export class TagsView extends ObservableReactComponent { @computed get isEditing() { const selected = DocumentView.Selected().length === 1 && DocumentView.Selected().includes(this.View); - if (this._isEditing === undefined) return selected && !StrListCast(this.View.dataDoc.tags).length && !StrListCast(this.View.dataDoc[Doc.LayoutFieldKey(this.View.Document) + '_audioAnnotations_text']).length; - return this._isEditing && (this._props.Views.length > 1 || selected); + if (this._isEditing === undefined) return selected && this.View.TagPanelEditing; // && !StrListCast(this.View.dataDoc.tags).length && !StrListCast(this.View.dataDoc[Doc.LayoutFieldKey(this.View.Document) + '_audioAnnotations_text']).length; + return this._isEditing && (this._props.Views.length > 1 || (selected && this.View.TagPanelEditing)); } /** @@ -309,7 +308,10 @@ export class TagsView extends ObservableReactComponent { @action setToEditing = (editing = true) => { this._isEditing = editing; - editing && this._props.Views.length === 1 && this.View.select(false); + if (this._props.Views.length === 1) { + this.View.TagPanelEditing = editing; + editing && this.View.select(false); + } }; /** @@ -350,7 +352,16 @@ export class TagsView extends ObservableReactComponent { return this.View.ComponentView?.isUnstyledView?.() || (!this.View.showTags && this._props.Views.length === 1) ? null : (
r && new ResizeObserver(action(() => this._props.Views.length === 1 && (this.View.TagPanelHeight = Math.max(0, (r?.getBoundingClientRect().height ?? 0) - this.InsetDist)))).observe(r)} + ref={r => + r && + new ResizeObserver( + action(() => { + if (this._props.Views.length === 1) { + this.View.TagPanelHeight = Math.floor(r?.children[0].children[0].getBoundingClientRect().height ?? 0) - Math.floor(r?.children[0].children[0].children[0].getBoundingClientRect().height ?? 0); + } + }) + ).observe(r?.children[0]) + } style={{ display: SnappingManager.IsResizing === this.View.Document[Id] ? 'none' : undefined, backgroundColor: this.isEditing ? this._props.background : Colors.TRANSPARENT, diff --git a/src/client/views/global/globalCssVariables.module.scss b/src/client/views/global/globalCssVariables.module.scss index ad0c5c21d..82f6caa52 100644 --- a/src/client/views/global/globalCssVariables.module.scss +++ b/src/client/views/global/globalCssVariables.module.scss @@ -4,7 +4,7 @@ $white: #ffffff; $off-white: #fdfdfd; $light-gray: #dfdfdf; $medium-gray: #9f9f9f; -$medium-gray-dim: #9f9f9f30; +$medium-gray-dim: #9f9f9f; $dark-gray: #323232; $black: #000000; diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index dd5fd0d0c..f60f33608 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -273,7 +273,9 @@ .documentView-noAIWidgets { transform-origin: top left; - position: relative; + position: absolute; + bottom: 0; + pointer-events: none; } .documentView-editorView-history { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 37f888ddd..4cf60d356 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -748,7 +748,7 @@ export class DocumentViewInternal extends DocComponent {this._props.DocumentView?.() && !this._props.docViewPath().slice(-2)[0].ComponentView?.isUnstyledView?.() ? : null}
@@ -1163,6 +1163,7 @@ export class DocumentView extends DocComponent() { @observable private _selected = false; @observable public static CurrentlyPlaying: DocumentView[] = []; // audio or video media views that are currently playing @observable public TagPanelHeight = 0; + @observable public TagPanelEditing = false; @computed get showTags() { return this.Document._layout_showTags || this._props.showTags; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index f7e6d8e1e..d90be007f 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -154,11 +154,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { const defaultSidebar = 250; - const prevWidth = 1 - this.sidebarWidth() / DivWidth(this._ref.current!); + const dw = DivWidth(this._ref.current); + const prevWidth = 1 - this.sidebarWidth() / dw / this.nativeScaling(); if (preview) this._showSidebar = true; else { - this.layoutDoc[this.sidebarKey + '_freeform_scale_max'] = 1; - this.layoutDoc._layout_showSidebar = - (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? `${(defaultSidebar / (NumCast(this.layoutDoc._width) + defaultSidebar)) * 100}%` : '0%') !== '0%'; + this.layoutDoc._layout_sidebarWidthPercent = + this.sidebarWidthPercent === '0%' // + ? `${(defaultSidebar / (NumCast(this.layoutDoc._width) + defaultSidebar)) * 100}%` // + : '0%'; + this.layoutDoc._layout_showSidebar = this.sidebarWidthPercent !== '0%'; } - this.layoutDoc._width = !preview && this.SidebarShown ? NumCast(this.layoutDoc._width) + defaultSidebar : Math.max(20, NumCast(this.layoutDoc._width) * prevWidth); + this.layoutDoc._width = + !preview && this.SidebarShown // + ? NumCast(this.layoutDoc._width) + defaultSidebar + : Math.max(20, NumCast(this.layoutDoc._width) * prevWidth); }; sidebarDown = (e: React.PointerEvent) => { const batch = UndoManager.StartBatch('toggle sidebar'); @@ -769,7 +775,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { const localDelta = this.DocumentView?.().screenToViewTransform().transformDirection(delta[0], delta[1]) ?? delta; - const sidebarWidth = (NumCast(this.layoutDoc._width) * Number(this.layout_sidebarWidthPercent.replace('%', ''))) / 100; + const sidebarWidth = (NumCast(this.layoutDoc._width) * Number(this.sidebarWidthPercent.replace('%', ''))) / 100; const width = NumCast(this.layoutDoc._width) + localDelta[0]; this.layoutDoc._layout_sidebarWidthPercent = Math.max(0, (sidebarWidth + localDelta[0]) / width) * 100 + '%'; this.layoutDoc.width = width; @@ -1223,7 +1229,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent BoolCast(this.Document._freeform_fitContentsToBox); - sidebarContentScaling = () => (this._props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1); + nativeScaling = () => this._props.NativeDimScaling?.() || 1; sidebarAddDocument = (doc: Doc | Doc[], sidebarKey: string = this.sidebarKey) => { if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar(); return this.addDocument(doc, sidebarKey); @@ -1901,12 +1907,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { this.dataDoc[this.sidebarKey + '_height'] = height; }; - sidebarWidth = () => (Number(this.layout_sidebarWidthPercent.substring(0, this.layout_sidebarWidthPercent.length - 1)) / 100) * this._props.PanelWidth(); + sidebarWidth = () => (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this._props.PanelWidth(); sidebarScreenToLocal = () => this._props .ScreenToLocalTransform() - .translate(-(this._props.PanelWidth() - this.sidebarWidth()) / (this._props.NativeDimScaling?.() || 1), 0) - .scale(1 / NumCast(this.layoutDoc._freeform_scale, 1) / (this._props.NativeDimScaling?.() || 1)); + .translate(-(this._props.PanelWidth() - this.sidebarWidth()) / this.nativeScaling(), 0) + .scale(1 / this.nativeScaling()); @computed get audioHandle() { return !this.recordingDictation ? null : ( @@ -1927,6 +1933,20 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent ); } + private _sideBtnWidth = 35; + /** + * How much the content of the view is being scaled based on its nesting and its fit-to-width settings + */ + @computed get viewScaling() { return this.ScreenToLocalBoxXf().Scale ; } // prettier-ignore + /** + * The maximum size a UI widget can be scaled so that it won't be bigger in screen pixels than its normal 35 pixel size. + */ + @computed get maxWidgetSize() { return Math.min(this._sideBtnWidth, 0.2 * this._props.PanelWidth())*this.viewScaling; } // prettier-ignore + /** + * How much to reactively scale a UI element so that it is as big as it can be (up to its normal 35pixel size) without being too big for the Doc content + */ + @computed get uiBtnScaling() { return this.maxWidgetSize / this._sideBtnWidth; } // prettier-ignore + @computed get sidebarHandle() { TraceMobx(); const annotated = DocListCast(this.dataDoc[this.sidebarKey]).filter(d => d?.author).length; @@ -1941,7 +1961,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent
@@ -1986,7 +2006,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent +
{renderComponent(StrCast(this.layoutDoc[this.sidebarKey + '_type_collection']))}
); @@ -2061,7 +2081,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent const height = Number(styleFromLayout.height?.replace('px', '')); // prevent default if selected || child is active but this doc isn't scrollable @@ -2078,8 +2098,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent !this._props.isContentActive() && FormattedTextBoxComment.textBox === this && FormattedTextBoxComment.Hide); const scrSize = (which: number, view = this._props.docViewPath().slice(-which)[0]) => @@ -2107,7 +2127,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent
- {this.noSidebar || !this.SidebarShown || this.layout_sidebarWidthPercent === '0%' ? null : this.sidebarCollection} + {this.noSidebar || !this.SidebarShown || this.sidebarWidthPercent === '0%' ? null : this.sidebarCollection} {this.noSidebar || this.Document._layout_noSidebar || this.Document._createDocOnCR || this.layoutDoc._chromeHidden || this.Document.quiz ? null : this.sidebarHandle} {this.audioHandle} {this.layoutDoc._layout_enableAltContentUI && !this.layoutDoc._chromeHidden ? this.overlayAlternateIcon : null} -- cgit v1.2.3-70-g09d2 From 4f236271c39380f15409b8fb38b2f6e2bae8df9f Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 9 Apr 2025 11:44:56 -0400 Subject: cleaned up color setting for templates so that instances can override template default color. --- src/client/views/DocComponent.tsx | 19 +++++++++++++++++++ src/client/views/StyleProvider.tsx | 8 +++++--- src/client/views/global/globalScripts.ts | 7 ++++--- src/client/views/nodes/DocumentView.tsx | 8 ++++---- 4 files changed, 32 insertions(+), 10 deletions(-) (limited to 'src/client/views/global') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index d33f3b713..b8b70d9d2 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -49,6 +49,13 @@ export function DocComponent

() { get rootDoc() { return DocCast(this.Document.rootDocument, this.Document); } + + /** + * Whether the doc is a sub-componentn of a compound template doc. + */ + get isTemplate() { + return this.rootDoc !== this.layoutDoc; + } /** * This is the document being rendered by the React component. In the * case of a compound template, this will be the expanded template Doc @@ -109,6 +116,12 @@ export function ViewBoxBaseComponent

() { get rootDoc() { return DocCast(this.Document.rootDocument, this.Document); } + /** + * Whether the doc is a sub-componentn of a compound template doc. + */ + get isTemplate() { + return this.rootDoc !== this.layoutDoc; + } /** * This is the document being rendered by the React component. In the * case of a compound template, this will be the expanded template Doc @@ -183,6 +196,12 @@ export function ViewBoxAnnotatableComponent

() { @computed get rootDoc() { return DocCast(this.Document.rootDocument, this.Document); } + /** + * Whether the doc is a sub-componentn of a compound template doc. + */ + get isTemplate() { + return this.rootDoc !== this.layoutDoc; + } /** * This is the document being rendered. It may be a template so it may or may no inherit from the data doc. */ diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index ae94c206c..a1c6aa1a2 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -251,9 +251,11 @@ export function DefaultStyleProvider(doc: Opt, props: Opt = StrCast(doc?.[fieldKey+alternate], StrCast(doc?.['backgroundColor' +alternate], isCaption ? 'rgba(0,0,0,0.4)' : '')); - if (!docColor && doc?.[StrCast(doc?.layout_fieldKey)] instanceof Doc) docColor = StrCast(doc._backgroundColor,docColor); - if (docColor && doc?._override_backgroundColor) docColor = StrCast(doc._backgroundColor,docColor); + let docColor:Opt = StrCast(doc?._backgroundColor, // renderDoc === this.layoutDoc + StrCast(doc?.[fieldKey+alternate], // doc === this.Document + StrCast(doc?.['backgroundColor' +alternate], + isCaption ? 'rgba(0,0,0,0.4)' : ''))); + // prettier-ignore switch (layoutDoc?.type) { case DocumentType.PRESELEMENT: docColor = docColor || ""; break; diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index 04b2873d1..caacd0a11 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -38,6 +38,7 @@ import { VideoBox } from '../nodes/VideoBox'; import { WebBox } from '../nodes/WebBox'; import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup'; +import { DocData } from '../../../fields/DocSymbols'; // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function IsNoneSelected() { @@ -131,10 +132,10 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b obj[fieldKey] = color; CollectionFreeFormDocumentView.setStringValues(contentFrameNumber, dv.Document, obj); } else { - const dataKey = Doc.LayoutFieldKey(dv.Document); + const colorDoc = dv.isTemplate ? dv.layoutDoc : dv.dataDoc; // assigning to a template should not assign to the data doc + const dataKey = Doc.LayoutFieldKey(colorDoc); const alternate = (dv.layoutDoc[dataKey + '_usePath'] ? '_' + dv.layoutDoc[dataKey + '_usePath'] : '').replace(':hover', ''); - dv.layoutDoc[fieldKey + alternate] = undefined; - dv.dataDoc[fieldKey + alternate] = color; + colorDoc[fieldKey + alternate] = color; } }); } else { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 4cf60d356..436f35d4c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -103,14 +103,14 @@ export class DocumentViewInternal extends DocComponent; } // prettier-ignore @computed get showCaption() { return this.style(this.layoutDoc, StyleProp.ShowCaption) as string ?? ""; } // prettier-ignore @computed get headerMargin() { return this.style(this.layoutDoc, StyleProp.HeaderMargin) as number ?? 0; } // prettier-ignore @computed get titleHeight() { return this.style(this.layoutDoc, StyleProp.TitleHeight) as number ?? 0; } // prettier-ignore - @computed get docContents() { return this.style(this.Document, StyleProp.DocContents) as JSX.Element; } // prettier-ignore - @computed get highlighting() { return this.style(this.Document, StyleProp.Highlighting); } // prettier-ignore - @computed get borderPath() { return this.style(this.Document, StyleProp.BorderPath); } // prettier-ignore + @computed get docContents() { return this.style(this.Document, StyleProp.DocContents) as JSX.Element; } // prettier-ignore + @computed get highlighting() { return this.style(this.Document, StyleProp.Highlighting); } // prettier-ignore + @computed get borderPath() { return this.style(this.Document, StyleProp.BorderPath); } // prettier-ignore @computed get onClickHdlr() { return this._props.onClickScript?.() ?? ScriptCast(this.layoutDoc.onClick ?? this.Document.onClick); } // prettier-ignore @computed get onDoubleClickHdlr() { return this._props.onDoubleClickScript?.() ?? ScriptCast(this.layoutDoc.onDoubleClick ?? this.Document.onDoubleClick); } // prettier-ignore -- cgit v1.2.3-70-g09d2 From 2d382a1dd28aa5aae22669988475e5721435b738 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 9 Apr 2025 14:55:28 -0400 Subject: more color template fixes. --- src/client/views/DocComponent.tsx | 17 +++-------------- src/client/views/StyleProvider.tsx | 20 ++++++++++++-------- src/client/views/global/globalScripts.ts | 4 ++-- src/client/views/nodes/DocumentView.tsx | 2 +- 4 files changed, 18 insertions(+), 25 deletions(-) (limited to 'src/client/views/global') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index b8b70d9d2..45c80c6f7 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -19,6 +19,7 @@ import { FieldViewProps } from './nodes/FieldView'; * */ export interface DocComponentProps { Document: Doc; + TemplateDataDocument?: Doc; LayoutTemplate?: () => Opt; LayoutTemplateString?: string; } @@ -53,8 +54,8 @@ export function DocComponent

() { /** * Whether the doc is a sub-componentn of a compound template doc. */ - get isTemplate() { - return this.rootDoc !== this.layoutDoc; + get isTemplateForField() { + return this.rootDoc !== this.layoutDoc && this._props.TemplateDataDocument; } /** * This is the document being rendered by the React component. In the @@ -116,12 +117,6 @@ export function ViewBoxBaseComponent

() { get rootDoc() { return DocCast(this.Document.rootDocument, this.Document); } - /** - * Whether the doc is a sub-componentn of a compound template doc. - */ - get isTemplate() { - return this.rootDoc !== this.layoutDoc; - } /** * This is the document being rendered by the React component. In the * case of a compound template, this will be the expanded template Doc @@ -196,12 +191,6 @@ export function ViewBoxAnnotatableComponent

() { @computed get rootDoc() { return DocCast(this.Document.rootDocument, this.Document); } - /** - * Whether the doc is a sub-componentn of a compound template doc. - */ - get isTemplate() { - return this.rootDoc !== this.layoutDoc; - } /** * This is the document being rendered. It may be a template so it may or may no inherit from the data doc. */ diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index a1c6aa1a2..a3067907d 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -248,14 +248,18 @@ export function DefaultStyleProvider(doc: Opt, props: Opt = StrCast(doc?._backgroundColor, // renderDoc === this.layoutDoc - StrCast(doc?.[fieldKey+alternate], // doc === this.Document - StrCast(doc?.['backgroundColor' +alternate], - isCaption ? 'rgba(0,0,0,0.4)' : ''))); - + const dataKey = doc ? Doc.LayoutFieldKey(doc) : ''; + const usePath = StrCast(doc?.[dataKey + '_usePath']); + const alternate = usePath.includes(':hover') ? ( isHovering?.() ? '_' + usePath.replace(':hover','') : '') : usePath ? "_" +usePath:usePath; + let docColor:Opt = layoutDoc && + StrCast(alternate ? layoutDoc['backgroundColor' + alternate]:undefined, + doc.rootDocument + ? StrCast(layoutDoc.backgroundColor, StrCast(DocCast(doc.rootDocument).backgroundColor)) // for nested templates: use template's color, then root doc's color + : layoutDoc === doc + ? StrCast(doc.backgroundColor) + : StrCast(StrCast(Doc.GetT(layoutDoc, 'backgroundColor', 'string', true), StrCast(doc.backgroundColor, StrCast(layoutDoc.backgroundColor)) // otherwise, use expanded template coloor, then root doc's color, then template's inherited color + ))); + // prettier-ignore switch (layoutDoc?.type) { case DocumentType.PRESELEMENT: docColor = docColor || ""; break; diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index caacd0a11..32afb3d3d 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -120,7 +120,7 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b const fieldKey = selView.Document._layout_isSvg ? 'fillColor' : 'backgroundColor'; const layoutFrameNumber = Cast(selView.containerViewPath?.().lastElement()?.Document?._currentFrame, 'number'); // frame number that container is at which determines layout frame values const contentFrameNumber = Cast(selView.Document?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed - return CollectionFreeFormDocumentView.getStringValues(selView?.Document, contentFrameNumber)[fieldKey] || defaultFill(); + return (contentFrameNumber !== undefined ? CollectionFreeFormDocumentView.getStringValues(selView?.Document, contentFrameNumber)[fieldKey] : selView.backgroundColor()) || defaultFill(); } !selectedViews.length && setDefaultFill(color ?? 'transparent'); selectedViews.forEach(dv => { @@ -132,7 +132,7 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b obj[fieldKey] = color; CollectionFreeFormDocumentView.setStringValues(contentFrameNumber, dv.Document, obj); } else { - const colorDoc = dv.isTemplate ? dv.layoutDoc : dv.dataDoc; // assigning to a template should not assign to the data doc + const colorDoc = dv.isTemplateForField ? dv.layoutDoc : dv.dataDoc; // assigning to a template's compoment field should not assign to the data doc const dataKey = Doc.LayoutFieldKey(colorDoc); const alternate = (dv.layoutDoc[dataKey + '_usePath'] ? '_' + dv.layoutDoc[dataKey + '_usePath'] : '').replace(':hover', ''); colorDoc[fieldKey + alternate] = color; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 436f35d4c..b03dd3944 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -103,11 +103,11 @@ export class DocumentViewInternal extends DocComponent; } // prettier-ignore @computed get showCaption() { return this.style(this.layoutDoc, StyleProp.ShowCaption) as string ?? ""; } // prettier-ignore @computed get headerMargin() { return this.style(this.layoutDoc, StyleProp.HeaderMargin) as number ?? 0; } // prettier-ignore @computed get titleHeight() { return this.style(this.layoutDoc, StyleProp.TitleHeight) as number ?? 0; } // prettier-ignore + @computed get backgroundBoxColor(){ return this.style(this.Document, StyleProp.BackgroundColor + ':docView') as string; } // prettier-ignore @computed get docContents() { return this.style(this.Document, StyleProp.DocContents) as JSX.Element; } // prettier-ignore @computed get highlighting() { return this.style(this.Document, StyleProp.Highlighting); } // prettier-ignore @computed get borderPath() { return this.style(this.Document, StyleProp.BorderPath); } // prettier-ignore -- 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/global') 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()}
-