From f290b6ca12ef4712c527e215144d9bb5719b2add Mon Sep 17 00:00:00 2001 From: Thomas Boutell Date: Tue, 18 Nov 2025 14:07:22 -0500 Subject: [PATCH] PRO-8708: bring back passing of the actual area options in the form developers expect to see them to custom insert menu item components --- CHANGELOG.md | 1 + .../components/AposRichTextWidgetEditor.vue | 120 ++++++++++-------- 2 files changed, 67 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7763e1b4c5..d27c282a1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ * `@apostrophecms/migration:requirements` handler now runs the migration requirements like `insertIfMissing`, `implementParkAllInDefaultLocale`, `replicate` and `implementParkAllInOtherLocales`. * Bump nodemailer to v7.x. * Improves client error log when unable to render a widget. +* Rich text `styles` are once again available to insert menu items, such as our optional `@apostrophecms/ai-helper` module. ### Fixes diff --git a/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue b/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue index fcdc69b274..4bfa4d264c 100644 --- a/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue +++ b/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue @@ -73,7 +73,7 @@ :name="item" :menu-item="insertMenu[item]" :editor="editor" - :editor-options="editorOptions" + :editor-options="getOptionsForInsertItem()" @done="doSuppressInsertMenu" @set-active-insert-menu="setActiveInsertMenu" /> @@ -242,59 +242,7 @@ export default { return this.moduleOptions.defaultOptions; }, editorOptions() { - // Deep clone to prevent runaway recursive rendering - // as the subproperties are mutated in several places - // by this code and its dependencies - let activeOptions = klona(this.options); - - activeOptions = { - ...activeOptions, - ...this.enhanceStyles( - activeOptions.styles?.length - ? activeOptions.styles - : this.defaultOptions.styles - ) - }; - delete activeOptions.styles; - - // Allow default options to pass through if `false` - Object.keys(this.defaultOptions).forEach((option) => { - if (option !== 'styles') { - activeOptions[option] = (activeOptions[option] !== undefined) - ? activeOptions[option] - : this.defaultOptions[option]; - } - }); - - activeOptions.className = (activeOptions.className !== undefined) - ? activeOptions.className - : this.moduleOptions.className; - - if (activeOptions.toolbar.includes('styles')) { - activeOptions.toolbar = activeOptions.toolbar.filter(t => t !== 'styles'); - if (activeOptions.marks.length) { - activeOptions.toolbar = [ 'marks', ...activeOptions.toolbar ]; - } - if (activeOptions.nodes.length) { - activeOptions.toolbar = [ 'nodes', ...activeOptions.toolbar ]; - } - } - - // The table tool is no longer part of the toolbar but will - // automatically appear when interacting with a table element, - // no configuration needed. If: - // 1. The table is configured for the toolbar but not insert, move it - // 2. remove the table tool from the toolbar - if (activeOptions.toolbar?.some(tool => tool === 'table')) { - if (!activeOptions.insert?.some(tool => tool === 'table')) { - activeOptions.insert = [ - ...(activeOptions.insert || []), - 'table' - ]; - } - activeOptions.toolbar = activeOptions.toolbar.filter(tool => tool !== 'table'); - } - return activeOptions; + return this.getOptionsForEditor(); }, autofocus() { // Only true for a new rich text widget @@ -488,6 +436,70 @@ export default { apos.bus.$off('apos-refreshing', this.onAposRefreshing); }, methods: { + // Insert menu items just want to know what the original options were, + // while "editorOptions" has morphed into a different, internal + // representation + getOptionsForInsertItem() { + return klona({ + ...this.defaultOptions, + ...this.options + }); + }, + getOptionsForEditor() { + // Deep clone to prevent runaway recursive rendering + // as the subproperties are mutated in several places + // by this code and its dependencies + let activeOptions = klona(this.options); + + activeOptions = { + ...activeOptions, + ...this.enhanceStyles( + activeOptions.styles?.length + ? activeOptions.styles + : klona(this.defaultOptions.styles) + ) + }; + delete activeOptions.styles; + + // Allow default options to pass through if `false` + Object.keys(this.defaultOptions).forEach((option) => { + if (option !== 'styles') { + activeOptions[option] = (activeOptions[option] !== undefined) + ? activeOptions[option] + : this.defaultOptions[option]; + } + }); + + activeOptions.className = (activeOptions.className !== undefined) + ? activeOptions.className + : this.moduleOptions.className; + + if (activeOptions.toolbar.includes('styles')) { + activeOptions.toolbar = activeOptions.toolbar.filter(t => t !== 'styles'); + if (activeOptions.marks.length) { + activeOptions.toolbar = [ 'marks', ...activeOptions.toolbar ]; + } + if (activeOptions.nodes.length) { + activeOptions.toolbar = [ 'nodes', ...activeOptions.toolbar ]; + } + } + + // The table tool is no longer part of the toolbar but will + // automatically appear when interacting with a table element, + // no configuration needed. If: + // 1. The table is configured for the toolbar but not insert, move it + // 2. remove the table tool from the toolbar + if (activeOptions.toolbar?.some(tool => tool === 'table')) { + if (!activeOptions.insert?.some(tool => tool === 'table')) { + activeOptions.insert = [ + ...(activeOptions.insert || []), + 'table' + ]; + } + activeOptions.toolbar = activeOptions.toolbar.filter(tool => tool !== 'table'); + } + return activeOptions; + }, showTableControls() { return this.editor?.isActive('table') ?? false; },