This is an automated email from the ASF dual-hosted git repository. nmalin pushed a commit to branch release24.09 in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/release24.09 by this push: new 81b60b029d Improved: Support Trumbowyg configuration parameter (OFBIZ-13224) 81b60b029d is described below commit 81b60b029d61bf83c655fb9f7d2c89b59e2b157b Author: Florian Motteau <florian.mott...@nereide.fr> AuthorDate: Wed Apr 23 10:41:21 2025 +0200 Improved: Support Trumbowyg configuration parameter (OFBIZ-13224) On textarea field, uses "visual-editor-buttons" attribute value as a configuration description for Trumbowyg, as described in [the documentation](https://alex-d.github.io/Trumbowyg/documentation/#button-pane). Also fixes visual glitches on Trumbowyg for some themes. Thanks: Néréide team --- applications/content/widget/forum/ForumForms.xml | 2 +- framework/widget/dtd/widget-form.xsd | 11 +++-- .../macro/RenderableFtlFormElementsBuilder.java | 4 +- .../RenderableFtlFormElementsBuilderTest.java | 50 ++++++++++++++++++++++ .../webapp/common-theme/js/util/OfbizUtil.js | 45 ++++++++----------- themes/common-theme/widget/Theme.xml | 3 ++ .../webapp/helveticus/helveticus-main-theme.less | 12 +++++- .../rainbowstone/rainbowstone-main-theme.less | 4 +- themes/rainbowstone/webapp/rainbowstone/style.css | 14 +----- 9 files changed, 95 insertions(+), 50 deletions(-) diff --git a/applications/content/widget/forum/ForumForms.xml b/applications/content/widget/forum/ForumForms.xml index c83c37e268..fd67248438 100644 --- a/applications/content/widget/forum/ForumForms.xml +++ b/applications/content/widget/forum/ForumForms.xml @@ -227,7 +227,7 @@ under the License. <field name="ownerContentId"><hidden value="${parameters.forumId}"/></field> <field name="caContentId"><hidden value="${parameters.forumMessageIdTo}"/></field> <field name="caContentAssocTypeId"><hidden value="RESPONSE"/></field> - <field name="forumMessageText" parameter-name="textData"><textarea rows="10" visual-editor-enable="true" visual-editor-buttons="compact"/></field> + <field name="forumMessageText" parameter-name="textData"><textarea rows="10" visual-editor-enable="true"/></field> <field name="addButton" title="${uiLabelMap.CommonAdd}" widget-style="smallSubmit"><submit button-type="button"/></field> </form> <form name="AddForumThreadMessage" type="single" extends="AddForumMessage" target="updateForumThreadMessage" diff --git a/framework/widget/dtd/widget-form.xsd b/framework/widget/dtd/widget-form.xsd index 09b382faa4..cc24839629 100644 --- a/framework/widget/dtd/widget-form.xsd +++ b/framework/widget/dtd/widget-form.xsd @@ -1510,13 +1510,18 @@ under the License. <xs:attribute name="visual-editor-enable" type="xs:boolean" default="false"> <xs:annotation> - <xs:documentation>This will enable the html editor on this text area from www.unverse.net (more info there), only one textarea can be used on one page</xs:documentation> + <xs:documentation> + This will enable the HTML editor on this text area from https://alex-d.github.io/Trumbowyg/ + </xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute type="xs:string" name="visual-editor-buttons"> <xs:annotation> - <xs:documentation>In here you can specify which buttons you want to see and in which order separated by blanks. Available buttons are:formatblock fontname fontsize newline bold italic underline left center right number bullet indent outdent undo redo color hilite rule link image - table clean html spellcheck |(separator) Default is that all buttons are shown</xs:documentation> + <xs:documentation> + Trumbowyg buttons configuration object, as a JSON.parse parsable string (2 dimensions string array). + Ex: [['formatting'],['strong','em','del'],['link'],['unorderedList','orderedList'],['horizontalRule']] + See https://alex-d.github.io/Trumbowyg/documentation/#button-pane + </xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute type="xs:string" name="placeholder"> diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilder.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilder.java index 79af56caee..0aef73be00 100644 --- a/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilder.java +++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilder.java @@ -355,9 +355,7 @@ public final class RenderableFtlFormElementsBuilder { if (textareaField.getVisualEditorEnable()) { builder.booleanParameter("visualEditorEnable", true); - - String buttons = textareaField.getVisualEditorButtons(context); - builder.stringParameter("buttons", UtilValidate.isEmpty(buttons) ? "maxi" : buttons); + builder.stringParameter("buttons", textareaField.getVisualEditorButtons(context)); } if (textareaField.isReadOnly()) { diff --git a/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilderTest.java b/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilderTest.java index 80debaed87..dfc804660b 100644 --- a/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilderTest.java +++ b/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilderTest.java @@ -291,6 +291,56 @@ public class RenderableFtlFormElementsBuilderTest { MacroCallParameterMatcher.hasNameAndBooleanValue("disabled", true))); } + @Test + public void textareaFieldVisualEditorEnabledNoButtons(@Mocked final ModelFormField.TextareaField textareaField) { + new Expectations() { + { + modelFormField.getDisabled(withNotNull()); + result = true; + + textareaField.getVisualEditorEnable(); + result = true; + + textareaField.getVisualEditorButtons(withNotNull()); + result = ""; + } + }; + + final HashMap<String, Object> context = new HashMap<>(); + + final RenderableFtl renderableFtl = renderableFtlFormElementsBuilder.textArea(context, textareaField); + assertThat(renderableFtl, MacroCallMatcher.hasNameAndParameters("renderTextareaField", + MacroCallParameterMatcher.hasNameAndBooleanValue("visualEditorEnable", true))); + } + + @Test + public void textareaFieldVisualEditorEnabledButtons(@Mocked final ModelFormField.TextareaField textareaField) { + String editorConfiguration = "[['formatting'],['strong','em','del'],['link'],['unorderedList','orderedList']," + + "['horizontalRule'],['removeformat'],['indent','outdent'],['fullscreen']]"; + + new Expectations() { + { + modelFormField.getDisabled(withNotNull()); + result = true; + + textareaField.getVisualEditorEnable(); + result = true; + + textareaField.getVisualEditorButtons(withNotNull()); + result = editorConfiguration; + } + }; + + final HashMap<String, Object> context = new HashMap<>(); + + final RenderableFtl renderableFtl = renderableFtlFormElementsBuilder.textArea(context, textareaField); + assertThat(renderableFtl, MacroCallMatcher.hasNameAndParameters("renderTextareaField", + MacroCallParameterMatcher.hasNameAndBooleanValue("visualEditorEnable", true))); + assertThat(renderableFtl, MacroCallMatcher.hasNameAndParameters( + "renderTextareaField", + MacroCallParameterMatcher.hasNameAndStringValue("buttons", editorConfiguration))); + } + @Test public void fieldGroupOpenRendersCollapsibleAreaId(@Mocked final ModelForm.FieldGroup fieldGroup) { new Expectations() { diff --git a/themes/common-theme/webapp/common-theme/js/util/OfbizUtil.js b/themes/common-theme/webapp/common-theme/js/util/OfbizUtil.js index c5714fb987..7c69a1421f 100644 --- a/themes/common-theme/webapp/common-theme/js/util/OfbizUtil.js +++ b/themes/common-theme/webapp/common-theme/js/util/OfbizUtil.js @@ -147,34 +147,23 @@ function bindObservers(bind_element) { }) }); jQuery(bind_element).find(".visual-editor").each(function () { - var self = this; - var libraryFiles = ["/common/js/node_modules/trumbowyg/dist/trumbowyg.min.js", - "/common/js/node_modules/trumbowyg/dist/plugins/indent/trumbowyg.indent.min.js"]; - importLibrary(libraryFiles, function () { - var element = jQuery(self); - var language = element.data('language'); - var buttons = [['viewHTML'], - ['undo', 'redo'], - ['formatting'], - ['strong', 'em', 'del'], - ['superscript', 'subscript'], - ['link'], - ['insertImage'], - ['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull'], - ['unorderedList', 'orderedList'], - ['horizontalRule'], - ['removeformat'], - ['indent', 'outdent'], - ['fullscreen'] - ] - var opts = { - lang: language, - btns: buttons, - semantic: false, - tagsToRemove: ['script', 'link'], - svgPath: '/common/js/node_modules/trumbowyg/dist/ui/icons.svg' - } - element.trumbowyg(opts); + const element = $(this); + const lang = element.data('language'); + const toolbarAttr = element.data('toolbar'); + const providedBtns = toolbarAttr ? JSON.parse(toolbarAttr.replace(/'/g, '"')) : undefined; + const defaultBtns = [ + ['undo', 'redo'], ['formatting'], ['strong', 'em', 'del'], ['superscript', 'subscript'], ['link'], + ['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull'], ['unorderedList', 'orderedList'], + ['horizontalRule'], ['removeformat'], ['indent', 'outdent'], ['fullscreen'] + ]; + element.trumbowyg({ + lang, + btns: providedBtns ?? defaultBtns, + semantic: false, + tagsToRemove: ['script', 'link'], + svgPath: '/common/js/node_modules/trumbowyg/dist/ui/icons.svg', + resetCss: true, + linkTargets: ['_blank'] }); }); jQuery(bind_element).find(".ajaxAutoCompleter").each(function () { diff --git a/themes/common-theme/widget/Theme.xml b/themes/common-theme/widget/Theme.xml index ec51955a92..c0d4f30a2f 100644 --- a/themes/common-theme/widget/Theme.xml +++ b/themes/common-theme/widget/Theme.xml @@ -63,6 +63,8 @@ under the License. <property name="VT_HDR_JAVASCRIPT['add']" value="/common/js/node_modules/jquery-ui-dist/jquery-ui.min.js"/> <property name="VT_HDR_JAVASCRIPT['add']" value="/common/js/node_modules/jquery-validation/dist/jquery.validate.min.js"/> <property name="VT_HDR_JAVASCRIPT['add']" value="/common/js/node_modules/dompurify/dist/purify.min.js"/> + <property name="VT_HDR_JAVASCRIPT['add']" value="/common/js/node_modules/trumbowyg/dist/trumbowyg.min.js"/> + <property name="VT_HDR_JAVASCRIPT['add']" value="/common/js/node_modules/trumbowyg/dist/plugins/indent/trumbowyg.indent.min.js"/> <property name="VT_HDR_JAVASCRIPT['add']" value="/common/js/util/OfbizUtil.js"/> <property name="VT_HDR_JAVASCRIPT['add']" value="/common/js/util/fieldlookup.js"/> <property name="VT_HDR_JAVASCRIPT['add']" value="/common/js/plugins/date/date.timezone-min.js"/> @@ -75,6 +77,7 @@ under the License. <!--Css styles: don't load them since they differ depending on theme --> <property name="VT_STYLESHEET['add']" value="/common/js/node_modules/jquery-ui-dist/jquery-ui.min.css"/> <property name="VT_STYLESHEET['add']" value="/common/css/info.css"/> + <property name="VT_STYLESHEET['add']" value="/common/js/node_modules/trumbowyg/dist/ui/trumbowyg.min.css"/> </theme-properties> <templates><!-- Freemarker template use by this theme to render widget model--> diff --git a/themes/helveticus/webapp/helveticus/helveticus-main-theme.less b/themes/helveticus/webapp/helveticus/helveticus-main-theme.less index f9e7c7401f..d686e8e9ec 100644 --- a/themes/helveticus/webapp/helveticus/helveticus-main-theme.less +++ b/themes/helveticus/webapp/helveticus/helveticus-main-theme.less @@ -62,10 +62,20 @@ body { background: @grey-lighter; } -ul, li { +ul li { list-style-type: none } +/* restore list styles for Trumbowyg text editor */ +.trumbowyg-editor.trumbowyg-reset-css { + ul li { + list-style-type: disc; + } + ol li { + list-style-type: decimal; + } +} + br.clear, .clear { display: none } diff --git a/themes/rainbowstone/webapp/rainbowstone/rainbowstone-main-theme.less b/themes/rainbowstone/webapp/rainbowstone/rainbowstone-main-theme.less index 1a6ee86289..c176fae70b 100644 --- a/themes/rainbowstone/webapp/rainbowstone/rainbowstone-main-theme.less +++ b/themes/rainbowstone/webapp/rainbowstone/rainbowstone-main-theme.less @@ -1339,7 +1339,9 @@ a.user-pref-btn { padding: 0.4em; } -.screenlet-body div { +/* this rule is way too broad, targets all divs in screenlets (which is a lot of divs :) */ +/* just excluding Trumbowyg elements to avoid a visual glitch */ +.screenlet-body div:not([class^="trumbowyg"]) { margin: 0.8em 0.1em } diff --git a/themes/rainbowstone/webapp/rainbowstone/style.css b/themes/rainbowstone/webapp/rainbowstone/style.css index d55919b3a3..8d06162a4c 100644 --- a/themes/rainbowstone/webapp/rainbowstone/style.css +++ b/themes/rainbowstone/webapp/rainbowstone/style.css @@ -1927,16 +1927,4 @@ html > /**/ body .jstree-default a { /* The custom CSS to show mouse pointer on links using featherlight plugin */ a[data-featherlight] { cursor: pointer; -} - -/*The custom css for Trumbowyg*/ -.trumbowyg-button-pane { - margin: 0 !important; -} -.trumbowyg-button-pane .trumbowyg-button-group { - display: inline-block; - margin: 0 !important; -} -.trumbowyg-button-pane button { - color: #000; -} +} \ No newline at end of file