From 4b4d77f99bd55e6de0593c3acd1cf5798ae038bf Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 10 May 2024 14:05:01 -0400
Subject: added an always option for OpenWhere lightbox.  cleaned up/fixed
 making collections capable of being a lightbox.

---
 src/client/views/collections/TreeView.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 3a187171a..bc12d1c28 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -231,7 +231,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
         } else {
             // choose an appropriate embedding or make one. --- choose the first embedding that (1) user owns,  (2) has no context field ... otherwise make a new embedding
             const bestEmbedding = docView.Document.author === ClientUtils.CurrentUserEmail() && !Doc.IsDataProto(docView.Document) ? docView.Document : Doc.BestEmbedding(docView.Document);
-            this._props.addDocTab(bestEmbedding, OpenWhere.lightbox);
+            this._props.addDocTab(bestEmbedding, OpenWhere.lightboxAlways);
         }
     };
 
-- 
cgit v1.2.3-70-g09d2


From dc20525c09943fef332f8e7dac54aab3039e8df7 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 10 May 2024 16:34:37 -0400
Subject: fixed exception when text templates have no inherited data, and when
 text views are modified after the editor has been destroyed.  random code
 cleanup

---
 src/client/views/StyleProvider.tsx                 |  6 +-
 src/client/views/collections/TreeView.tsx          |  2 +-
 src/client/views/nodes/DocumentView.tsx            | 64 ++++++++++------------
 .../views/nodes/formattedText/FormattedTextBox.tsx |  7 ++-
 4 files changed, 36 insertions(+), 43 deletions(-)

(limited to 'src/client/views/collections/TreeView.tsx')

diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 0b8201903..3842f930a 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -80,8 +80,8 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
     const isNonTransparentLevel = isNonTransparent ? Number(property.replace(/.*:nonTransparent([0-9]+).*/, '$1')) : 0; // property.includes(':nonTransparent');
     const isAnnotated = property.includes(':annotated');
     const layoutDoc = doc ? Doc.Layout(doc) : doc;
-    const isOpen = property.includes(':open');
-    const boxBackground = property.includes(':box');
+    const isOpen = property.includes(':treeOpen');
+    const boxBackground = property.includes(':docView'); // background color of docView's bounds can be different than the background of contents -- eg FontIconBox
     const {
         DocumentView: docView,
         fieldKey: fieldKeyProp,
@@ -115,7 +115,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
     // prettier-ignore
     switch (property.split(':')[0]) {
         case StyleProp.TreeViewIcon: {
-            const img = ImageCast(doc?.icon, ImageCast(doc?.data));
+            const img = ImageCast(doc?.icon ?? doc?.[doc ? Doc.LayoutFieldKey(doc) : ""]);
             if (img) {
                 const ext = extname(img.url.href);
                 const url = doc?.icon ? img.url.href : img.url.href.replace(ext, '_s' + ext);
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index bc12d1c28..b82421e6b 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -779,7 +779,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
 
     @computed get renderBullet() {
         TraceMobx();
-        const iconType = this.treeView._props.styleProvider?.(this.Document, this.treeView._props, StyleProp.TreeViewIcon + (this.treeViewOpen ? ':open' : !this.childDocs.length ? ':empty' : '')) || 'question';
+        const iconType = this.treeView._props.styleProvider?.(this.Document, this.treeView._props, StyleProp.TreeViewIcon + (this.treeViewOpen ? ':treeOpen' : !this.childDocs.length ? ':empty' : '')) || 'question';
         const color = SettingsManager.userColor;
         const checked = this.onCheckedClick ? this.Document.treeView_Checked ?? 'unchecked' : undefined;
         return (
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 14feca0b5..804d014a1 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -123,31 +123,23 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
 
     animateScaleTime = () => this._animateScaleTime ?? 100;
     style = (doc: Doc, sprop: StyleProp | string) => this._props.styleProvider?.(doc, this._props, sprop);
-    @computed get showTitle()          { return this.style(this.layoutDoc, StyleProp.ShowTitle) as Opt<string>; } // prettier-ignore
-    @computed get opacity()            { return this.style(this.layoutDoc, StyleProp.Opacity); } // prettier-ignore
-    @computed get boxShadow()          { return this.style(this.layoutDoc, StyleProp.BoxShadow); } // prettier-ignore
-    @computed get borderRounding()     { return this.style(this.layoutDoc, StyleProp.BorderRounding); } // prettier-ignore
-    @computed get widgetDecorations()  { return this.style(this.layoutDoc, StyleProp.Decorations); } // prettier-ignore
-    @computed get backgroundBoxColor() { return this.style(this.layoutDoc, StyleProp.BackgroundColor + ':box'); } // prettier-ignore
-    @computed get headerMargin()       { return this.style(this.layoutDoc, StyleProp.HeaderMargin) ?? 0; } // prettier-ignore
-    @computed get showCaption()        { return this.style(this.layoutDoc, StyleProp.ShowCaption) ?? 0;  } // prettier-ignore
-    @computed get titleHeight()        { return this.style(this.layoutDoc, StyleProp.TitleHeight) ?? 0;  } // prettier-ignore
-    @computed get docContents()        { return this.style(this.Document, StyleProp.DocContents); } // 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 onClickHandler() {
-        return this._props.onClickScript?.() ?? ScriptCast(this.Document.onClick, ScriptCast(this.layoutDoc.onClick));
-    }
-    @computed get onDoubleClickHandler() {
-        return this._props.onDoubleClickScript?.() ?? ScriptCast(this.layoutDoc.onDoubleClick, ScriptCast(this.Document.onDoubleClick));
-    }
-    @computed get onPointerDownHandler() {
-        return this._props.onPointerDownScript?.() ?? ScriptCast(this.layoutDoc.onPointerDown, ScriptCast(this.Document.onPointerDown));
-    }
-    @computed get onPointerUpHandler() {
-        return this._props.onPointerUpScript?.() ?? ScriptCast(this.layoutDoc.onPointerUp, ScriptCast(this.Document.onPointerUp));
-    }
+    @computed get opacity()           { return this.style(this.layoutDoc, StyleProp.Opacity); } // prettier-ignore
+    @computed get boxShadow()         { return this.style(this.layoutDoc, StyleProp.BoxShadow); } // prettier-ignore
+    @computed get borderRounding()    { return this.style(this.layoutDoc, StyleProp.BorderRounding); } // prettier-ignore
+    @computed get widgetDecorations() { return this.style(this.layoutDoc, StyleProp.Decorations); } // prettier-ignore
+    @computed get backgroundBoxColor(){ return this.style(this.layoutDoc, StyleProp.BackgroundColor + ':docView'); } // prettier-ignore
+    @computed get showTitle()         { return this.style(this.layoutDoc, StyleProp.ShowTitle) as Opt<string>; } // prettier-ignore
+    @computed get showCaption()       { return this.style(this.layoutDoc, StyleProp.ShowCaption) ?? 0;  } // prettier-ignore
+    @computed get headerMargin()      { return this.style(this.layoutDoc, StyleProp.HeaderMargin) ?? 0; } // prettier-ignore
+    @computed get titleHeight()       { return this.style(this.layoutDoc, StyleProp.TitleHeight) ?? 0;  } // prettier-ignore
+    @computed get docContents()       { return this.style(this.Document, StyleProp.DocContents); } // 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
+    @computed get onPointerDownHdlr() { return this._props.onPointerDownScript?.() ?? ScriptCast(this.layoutDoc.onPointerDown ?? this.Document.onPointerDown); } // prettier-ignore
+    @computed get onPointerUpHdlr()   { return this._props.onPointerUpScript?.()   ?? ScriptCast(this.layoutDoc.onPointerUp   ?? this.Document.onPointerUp); } // prettier-ignore
 
     @computed get disableClickScriptFunc() {
         const onScriptDisable = this._props.onClickScriptDisable ?? this._componentView?.onClickScriptDisable?.() ?? this.layoutDoc.onClickScriptDisable;
@@ -163,7 +155,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
         TraceMobx();
         return this._props.contentPointerEvents ??
             ((!this.disableClickScriptFunc && //
-                this.onClickHandler &&
+                this.onClickHdlr &&
                 !SnappingManager.ExploreMode &&
                 !this.layoutDoc.layout_isSvg &&
                 this.isContentActive() !== true) ||
@@ -315,8 +307,8 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
             };
             if (this._doubleTap) {
                 const defaultDblclick = this._props.defaultDoubleClick?.() || this.Document.defaultDoubleClick;
-                if (this.onDoubleClickHandler?.script) {
-                    UndoManager.RunInBatch(() => this.onDoubleClickHandler.script.run(scriptProps, console.log).result?.select && this._props.select(false), 'on double click: ' + this.Document.title);
+                if (this.onDoubleClickHdlr?.script) {
+                    UndoManager.RunInBatch(() => this.onDoubleClickHdlr.script.run(scriptProps, console.log).result?.select && this._props.select(false), 'on double click: ' + this.Document.title);
                 } else if (!Doc.IsSystem(this.Document) && defaultDblclick !== 'ignore') {
                     UndoManager.RunInBatch(() => this._props.addDocTab(this.Document, OpenWhere.lightboxAlways), 'double tap');
                     DocumentView.DeselectAll();
@@ -329,9 +321,9 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
                 this._singleClickFunc = undefined;
             } else {
                 let clickFunc: undefined | (() => any);
-                if (!this.disableClickScriptFunc && this.onClickHandler?.script) {
+                if (!this.disableClickScriptFunc && this.onClickHdlr?.script) {
                     clickFunc = undoable(() => {
-                        this.onClickHandler?.script.run(scriptProps, console.log).result?.select && this._props.select(false);
+                        this.onClickHdlr?.script.run(scriptProps, console.log).result?.select && this._props.select(false);
                     }, 'click ' + this.Document.title);
                 } else {
                     // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
@@ -409,10 +401,10 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
         this.cleanupPointerEvents();
         this._longPressSelector && clearTimeout(this._longPressSelector);
 
-        if (this.onPointerUpHandler?.script) {
-            this.onPointerUpHandler.script.run({ this: this.Document }, console.log);
+        if (this.onPointerUpHdlr?.script) {
+            this.onPointerUpHdlr.script.run({ this: this.Document }, console.log);
         } else if (e.button === 0 && ClientUtils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
-            this._doubleTap = (this.onDoubleClickHandler?.script || this.Document.defaultDoubleClick !== 'ignore') && Date.now() - this._lastTap < ClientUtils.CLICK_TIME;
+            this._doubleTap = (this.onDoubleClickHdlr?.script || this.Document.defaultDoubleClick !== 'ignore') && Date.now() - this._lastTap < ClientUtils.CLICK_TIME;
             if (!this.isContentActive()) this._lastTap = Date.now(); // don't want to process the start of a double tap if the doucment is selected
         }
         // eslint-disable-next-line no-use-before-define
@@ -585,7 +577,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
                 !Doc.noviceMode && onClicks.push({ description: 'Toggle Detail', event: this.setToggleDetail, icon: 'concierge-bell' });
 
                 if (!this.Document.annotationOn) {
-                    onClicks.push({ description: this.onClickHandler ? 'Remove Click Behavior' : 'Follow Link', event: () => this.toggleFollowLink(false, false), icon: 'link' });
+                    onClicks.push({ description: this.onClickHdlr ? 'Remove Click Behavior' : 'Follow Link', event: () => this.toggleFollowLink(false, false), icon: 'link' });
                     !Doc.noviceMode && onClicks.push({ description: 'Edit onClick Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.Document, undefined, 'onClick'), 'edit onClick'), icon: 'terminal' });
                     !existingOnClick && cm.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' });
                 } else if (Doc.Links(this.Document).length) {
@@ -688,7 +680,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
     rootSelected = () => this._rootSelected;
     panelHeight = () => this._props.PanelHeight() - this.headerMargin;
     screenToLocalContent = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin);
-    onClickFunc = this.disableClickScriptFunc ? undefined : () => this.onClickHandler;
+    onClickFunc = 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)); } // prettier-ignore
     setContentView = action((view: ViewBoxInterface<FieldViewProps>) => { this._componentView = view; }); // prettier-ignore
     isContentActive = (): boolean | undefined => this._isContentActive;
@@ -793,7 +785,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
                     width: 100 - sidebarWidthPercent + '%',
                     color: background === 'transparent' ? SnappingManager.userColor : lightOrDark(background),
                     background,
-                    pointerEvents: (!this.disableClickScriptFunc && this.onClickHandler) || this.Document.ignoreClick ? 'none' : this.isContentActive() || this._props.isDocumentActive?.() ? 'all' : undefined,
+                    pointerEvents: (!this.disableClickScriptFunc && this.onClickHdlr) || this.Document.ignoreClick ? 'none' : this.isContentActive() || this._props.isDocumentActive?.() ? 'all' : undefined,
                 }}>
                 {!dropdownWidth ? null : (
                     <div className="documntViewInternal-dropdown" style={{ width: dropdownWidth }}>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 624721d7c..e62a639c8 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -320,7 +320,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
         return '';
     };
     dispatchTransaction = (tx: Transaction) => {
-        if (this._editorView) {
+        if (this._editorView && !this._editorView.isDestroyed) {
             const state = this._editorView.state.apply(tx);
             this._editorView.updateState(state);
             this.tryUpdateDoc(false);
@@ -353,6 +353,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
 
                 let unchanged = true;
                 const textChange = newText !== prevData?.Text; // the Text string can change even if the RichText doesn't because dashFieldViews may return new strings as the data they reference changes
+                const rtField = (layoutData !== prevData ? layoutData : undefined) ?? protoData;
                 if (this._applyingChange !== this.fieldKey && (force || textChange || removeSelection(newJson) !== removeSelection(prevData?.Data))) {
                     this._applyingChange = this.fieldKey;
                     textChange && (dataDoc[this.fieldKey + '_modificationDate'] = new DateField(new Date(Date.now())));
@@ -366,10 +367,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
                             this._applyingChange = ''; // turning this off here allows a Doc to retrieve data from template if noTemplate below is changed to false
                             unchanged = false;
                         }
-                    } else {
+                    } else if (rtField) {
                         // if we've deleted all the text in a note driven by a template, then restore the template data
                         dataDoc[this.fieldKey] = undefined;
-                        this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse(((layoutData !== prevData ? layoutData : undefined) ?? protoData)?.Data)));
+                        this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse(rtField.Data)));
                         ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, text: newText });
                         unchanged = false;
                     }
-- 
cgit v1.2.3-70-g09d2

