From a44756168dcbce0813aaefa073f9dc7e59420636 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 22 Mar 2026 17:18:04 +0000 Subject: [PATCH] WYSIWYG: Aligned double click to set label for details functionality Aligned the behaviour across the WYSIWYG editors, and also for nested details blocks (which wasn't working in the TinyMCE implementation). Closes #6059 --- .../js/wysiwyg-tinymce/plugins-details.js | 10 ++++++++-- .../js/wysiwyg/lexical/core/LexicalEditor.ts | 19 +++++++++++++++++++ .../lexical/rich-text/LexicalDetailsNode.ts | 11 +++++++++++ .../js/wysiwyg/ui/defaults/buttons/objects.ts | 2 +- resources/js/wysiwyg/ui/framework/manager.ts | 7 +++++-- 5 files changed, 44 insertions(+), 5 deletions(-) diff --git a/resources/js/wysiwyg-tinymce/plugins-details.js b/resources/js/wysiwyg-tinymce/plugins-details.js index c4a6d927d..58b0ac9d8 100644 --- a/resources/js/wysiwyg-tinymce/plugins-details.js +++ b/resources/js/wysiwyg-tinymce/plugins-details.js @@ -19,6 +19,8 @@ function setSummary(editor, summaryContent) { } summary.textContent = summaryContent; }); + + editor.selection.select(details); } /** @@ -202,8 +204,12 @@ function register(editor) { }); editor.on('dblclick', event => { - if (!getSelectedDetailsBlock(editor) || event.target.closest('doc-root')) return; - showDetailLabelEditWindow(editor); + const domElClass = event?.target?.ownerDocument?.defaultView?.HTMLDetailsElement; + if (domElClass && event.target instanceof domElClass && getSelectedDetailsBlock(editor)) { + showDetailLabelEditWindow(editor); + event.preventDefault(); + event.stopPropagation(); + } }); editor.ui.registry.addButton('toggledetails', { diff --git a/resources/js/wysiwyg/lexical/core/LexicalEditor.ts b/resources/js/wysiwyg/lexical/core/LexicalEditor.ts index 364f6c6b7..46660c9b7 100644 --- a/resources/js/wysiwyg/lexical/core/LexicalEditor.ts +++ b/resources/js/wysiwyg/lexical/core/LexicalEditor.ts @@ -45,6 +45,7 @@ import {LineBreakNode} from './nodes/LexicalLineBreakNode'; import {ParagraphNode} from './nodes/LexicalParagraphNode'; import {RootNode} from './nodes/LexicalRootNode'; import {TabNode} from './nodes/LexicalTabNode'; +import {EditorUiContext} from "../../ui/framework/core"; export type Spread = Omit & T1; @@ -621,6 +622,8 @@ export class LexicalEditor { _editable: boolean; /** @internal */ _blockCursorElement: null | HTMLDivElement; + /** @internal */ + _context: null | EditorUiContext; /** @internal */ constructor( @@ -682,6 +685,7 @@ export class LexicalEditor { this._headless = parentEditor !== null && parentEditor._headless; this._window = null; this._blockCursorElement = null; + this._context = null; } /** @@ -1285,6 +1289,21 @@ export class LexicalEditor { triggerListeners('editable', this, true, editable); } } + + /** + * Set the UI context that this editor is intended to be part of. + */ + setUiContext(context: EditorUiContext) { + this._context = context; + } + + /** + * Get the UI context that this editor is considered to be part of. + */ + getUiContext(): EditorUiContext|null { + return this._context; + } + /** * Returns a JSON-serializable javascript object NOT a JSON string. * You still must call JSON.stringify (or something else) to turn the diff --git a/resources/js/wysiwyg/lexical/rich-text/LexicalDetailsNode.ts b/resources/js/wysiwyg/lexical/rich-text/LexicalDetailsNode.ts index cdf32fdcb..70ae7f0f9 100644 --- a/resources/js/wysiwyg/lexical/rich-text/LexicalDetailsNode.ts +++ b/resources/js/wysiwyg/lexical/rich-text/LexicalDetailsNode.ts @@ -9,6 +9,7 @@ import { } from 'lexical'; import {extractDirectionFromElement} from "lexical/nodes/common"; +import {$showDetailsForm} from "../../ui/defaults/forms/objects"; export type SerializedDetailsNode = Spread<{ id: string; @@ -90,6 +91,16 @@ export class DetailsNode extends ElementNode { }); }); + summary.addEventListener('dblclick', event => { + event.preventDefault(); + const uiContext = _editor.getUiContext(); + if (uiContext) { + _editor.read(() => { + $showDetailsForm(this, uiContext); + }); + } + }); + el.append(summary); return el; diff --git a/resources/js/wysiwyg/ui/defaults/buttons/objects.ts b/resources/js/wysiwyg/ui/defaults/buttons/objects.ts index 00dc9500e..bd6e41da9 100644 --- a/resources/js/wysiwyg/ui/defaults/buttons/objects.ts +++ b/resources/js/wysiwyg/ui/defaults/buttons/objects.ts @@ -221,7 +221,7 @@ export const detailsEditLabel: EditorButtonDefinition = { if ($isDetailsNode(details)) { $showDetailsForm(details, context); } - }) + }); }, isActive(selection: BaseSelection | null): boolean { return false; diff --git a/resources/js/wysiwyg/ui/framework/manager.ts b/resources/js/wysiwyg/ui/framework/manager.ts index 78d0cc9a2..3b4d5b495 100644 --- a/resources/js/wysiwyg/ui/framework/manager.ts +++ b/resources/js/wysiwyg/ui/framework/manager.ts @@ -29,7 +29,7 @@ export class EditorUIManager { setContext(context: EditorUiContext) { this.context = context; this.setupEventListeners(); - this.setupEditor(context.editor); + this.setupEditor(context.editor, context); } getContext(): EditorUiContext { @@ -256,7 +256,10 @@ export class EditorUIManager { } } - protected setupEditor(editor: LexicalEditor) { + protected setupEditor(editor: LexicalEditor, context: EditorUiContext) { + // Pass the context to the editor + editor.setUiContext(context); + // Register our DOM decorate listener with the editor const domDecorateListener: DecoratorListener = (decorators: Record) => { editor.getEditorState().read(() => {