From 705975eb43e7904c62e7e847478f6d0dac60d443 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 23 Mar 2025 18:14:31 -0400
Subject: more _props.Document  to .Document refactoring.  type updates to
 prosemirrortransfer

---
 .../views/nodes/formattedText/SummaryView.tsx      | 46 ++++++++++------------
 1 file changed, 21 insertions(+), 25 deletions(-)

(limited to 'src/client/views/nodes/formattedText/SummaryView.tsx')

diff --git a/src/client/views/nodes/formattedText/SummaryView.tsx b/src/client/views/nodes/formattedText/SummaryView.tsx
index 238267f6e..6dea891a0 100644
--- a/src/client/views/nodes/formattedText/SummaryView.tsx
+++ b/src/client/views/nodes/formattedText/SummaryView.tsx
@@ -1,12 +1,11 @@
 import { TextSelection } from 'prosemirror-state';
-import { Fragment, Node, Slice } from 'prosemirror-model';
+import { Attrs, Fragment, Node, Slice } from 'prosemirror-model';
 import * as ReactDOM from 'react-dom/client';
 import * as React from 'react';
+import { EditorView } from 'prosemirror-view';
 
-interface ISummaryView {}
 // currently nothing needs to be rendered for the internal view of a summary.
-// eslint-disable-next-line react/prefer-stateless-function
-export class SummaryViewInternal extends React.Component<ISummaryView> {
+export class SummaryViewInternal extends React.Component<object> {
     render() {
         return null;
     }
@@ -18,30 +17,30 @@ export class SummaryViewInternal extends React.Component<ISummaryView> {
 // method instead of changing prosemirror's text when the expand/elide buttons are clicked.
 export class SummaryView {
     dom: HTMLSpanElement; // container for label and value
-    root: any;
+    root: ReactDOM.Root;
 
-    constructor(node: any, view: any, getPos: any) {
+    constructor(node: Node, view: EditorView, getPos: () => number | undefined) {
         this.dom = document.createElement('span');
         this.dom.className = this.className(node.attrs.visibility);
-        this.dom.onpointerdown = (e: any) => {
+        this.dom.onpointerdown = (e: PointerEvent) => {
             this.onPointerDown(e, node, view, getPos);
         };
-        this.dom.onkeypress = function (e: any) {
+        this.dom.onkeypress = function (e: KeyboardEvent) {
             e.stopPropagation();
         };
-        this.dom.onkeydown = function (e: any) {
+        this.dom.onkeydown = function (e: KeyboardEvent) {
             e.stopPropagation();
         };
-        this.dom.onkeyup = function (e: any) {
+        this.dom.onkeyup = function (e: KeyboardEvent) {
             e.stopPropagation();
         };
-        this.dom.onmousedown = function (e: any) {
+        this.dom.onmousedown = function (e: MouseEvent) {
             e.stopPropagation();
         };
 
         const js = node.toJSON;
-        node.toJSON = function (...args: any[]) {
-            return js.apply(this, args);
+        node.toJSON = function (...args: unknown[]) {
+            return js.apply(this, args as []);
         };
 
         this.root = ReactDOM.createRoot(this.dom);
@@ -54,7 +53,7 @@ export class SummaryView {
     }
     selectNode() {}
 
-    updateSummarizedText(start: any, view: any) {
+    updateSummarizedText(start: number, view: EditorView) {
         const mtype = view.state.schema.marks.summarize;
         const mtypeInc = view.state.schema.marks.summarizeInclusive;
         let endPos = start;
@@ -65,7 +64,7 @@ export class SummaryView {
             // eslint-disable-next-line no-loop-func
             view.state.doc.nodesBetween(start, i, (node: Node /* , pos: number, parent: Node, index: number */) => {
                 if (node.isLeaf && !visited.has(node) && !skip) {
-                    if (node.marks.find((m: any) => m.type === mtype || m.type === mtypeInc)) {
+                    if (node.marks.find(m => m.type === mtype || m.type === mtypeInc)) {
                         visited.add(node);
                         endPos = i + node.nodeSize - 1;
                     } else skip = true;
@@ -75,21 +74,18 @@ export class SummaryView {
         return TextSelection.create(view.state.doc, start, endPos);
     }
 
-    onPointerDown = (e: any, node: any, view: any, getPos: any) => {
+    onPointerDown = (e: PointerEvent, node: Node, view: EditorView, getPos: () => number | undefined) => {
         const visible = !node.attrs.visibility;
-        const attrs = { ...node.attrs, visibility: visible };
-        let textSelection = TextSelection.create(view.state.doc, getPos() + 1);
-        if (!visible) {
-            // update summarized text and save in attrs
-            textSelection = this.updateSummarizedText(getPos() + 1, view);
-            attrs.text = textSelection.content();
-            attrs.textslice = attrs.text.toJSON();
-        }
+        const textSelection = visible //
+            ? TextSelection.create(view.state.doc, (getPos() ?? 0) + 1)
+            : this.updateSummarizedText((getPos() ?? 0) + 1, view); // update summarized text and save in attrs
+        const text = textSelection.content();
+        const attrs = { ...node.attrs, visibility: visible, ...(!visible ? { text, textslice: text.toJSON() } : {}) } as Attrs;
         view.dispatch(
             view.state.tr
                 .setSelection(textSelection) // select the current summarized text (or where it will be if its collapsed)
                 .replaceSelection(!visible ? new Slice(Fragment.fromArray([]), 0, 0) : node.attrs.text) // collapse/expand it
-                .setNodeMarkup(getPos(), undefined, attrs)
+                .setNodeMarkup(getPos() ?? 0, undefined, attrs)
         ); // update the attrs
         e.preventDefault();
         e.stopPropagation();
-- 
cgit v1.2.3-70-g09d2


From 62c88503ba43c864f7fe981111a1f7577879916e Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 15 Apr 2025 13:53:42 -0400
Subject: fixing summary/elision text node to work better with lists or
 hierarchical text nodes.

---
 src/client/views/nodes/KeyValueBox.tsx                |  2 +-
 src/client/views/nodes/formattedText/RichTextMenu.tsx | 11 -----------
 src/client/views/nodes/formattedText/SummaryView.tsx  |  7 +++++--
 src/client/views/nodes/formattedText/nodes_rts.ts     |  1 +
 4 files changed, 7 insertions(+), 14 deletions(-)

(limited to 'src/client/views/nodes/formattedText/SummaryView.tsx')

diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 706607fe1..aa66b5ba9 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -104,7 +104,7 @@ export class KeyValueBox extends ViewBoxBaseComponent<FieldViewProps>() {
             default: {
                 const _setCacheResult_ = (value: FieldResult) => {
                     field = value as FieldType;
-                    if (setResult) setResult?.(value);
+                    if (setResult) setResult(value);
                     else target[key] = field;
                 };
                 const res = script.run({ this: doc, _setCacheResult_ }, console.log);
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index d31a58030..c7731e812 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -414,17 +414,6 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
         this.view.focus();
     };
 
-    insertSummarizer(state: EditorState, dispatch: (tr: Transaction) => void) {
-        if (state.selection.empty) return false;
-        const mark = state.schema.marks.summarize.create();
-        const { tr } = state;
-        tr.addMark(state.selection.from, state.selection.to, mark);
-        const content = tr.selection.content();
-        const newNode = state.schema.nodes.summary.create({ visibility: false, text: content, textslice: content.toJSON() });
-        dispatch?.(tr.replaceSelectionWith(newNode).removeMark(tr.selection.from - 1, tr.selection.from, mark));
-        return true;
-    }
-
     vcenterToggle = () => {
         if (this.dataDoc) this.dataDoc.text_centered = !this.dataDoc.text_centered;
         else Doc.UserDoc().textCentered = !Doc.UserDoc().textCentered;
diff --git a/src/client/views/nodes/formattedText/SummaryView.tsx b/src/client/views/nodes/formattedText/SummaryView.tsx
index 6dea891a0..eeb604b57 100644
--- a/src/client/views/nodes/formattedText/SummaryView.tsx
+++ b/src/client/views/nodes/formattedText/SummaryView.tsx
@@ -59,12 +59,15 @@ export class SummaryView {
         let endPos = start;
 
         const visited = new Set();
-        for (let i: number = start + 1; i < view.state.doc.nodeSize - 1; i++) {
+        const summarized = new Set();
+        const isSummary = (node: Node) => summarized.has(node) || node.marks.find(m => m.type === mtype || m.type === mtypeInc);
+        for (let i = start + 1; i < view.state.doc.nodeSize - 1; i++) {
             let skip = false;
             // eslint-disable-next-line no-loop-func
             view.state.doc.nodesBetween(start, i, (node: Node /* , pos: number, parent: Node, index: number */) => {
+                isSummary(node) && Array.from(node.children).forEach(child => summarized.add(child));
                 if (node.isLeaf && !visited.has(node) && !skip) {
-                    if (node.marks.find(m => m.type === mtype || m.type === mtypeInc)) {
+                    if (summarized.has(node) || isSummary(node)) {
                         visited.add(node);
                         endPos = i + node.nodeSize - 1;
                     } else skip = true;
diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts
index fe7b77e74..5d34afc8a 100644
--- a/src/client/views/nodes/formattedText/nodes_rts.ts
+++ b/src/client/views/nodes/formattedText/nodes_rts.ts
@@ -353,6 +353,7 @@ export const nodes: { [index: string]: NodeSpec } = {
     hard_break: {
         inline: true,
         group: 'inline',
+        marks: '_',
         selectable: false,
         parseDOM: [{ tag: 'br' }],
         toDOM() {
-- 
cgit v1.2.3-70-g09d2

