From 371031992520e051d9367b57edfbb1c0380e1773 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke <ben@bnf.dev> Date: Thu, 14 Dec 2023 09:12:51 +0100 Subject: [PATCH] [TASK] Enable tablecaption in CKEditor5 CKEditor5 renders tablecaptions as figcaption elements, therefore we allow them to be included in RTE and in frontend rendering. Resolves: #101874 Releases: main, 12.4 Change-Id: I0d1c05b2d8a35d765e64713741a0ab05a5aa1a5c Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/82187 Reviewed-by: Benjamin Franzke <ben@bnf.dev> Tested-by: core-ci <typo3@b13.com> Tested-by: Benjamin Franzke <ben@bnf.dev> --- Build/Sources/TypeScript/rte_ckeditor/ckeditor5.ts | 2 +- typo3/sysext/core/Classes/Html/RteHtmlParser.php | 2 +- .../TypoScript/Helper/ParseFunc.typoscript | 5 ++++- .../Configuration/TypoScript/constants.typoscript | 2 +- .../sysext/rte_ckeditor/Configuration/RTE/Default.yaml | 1 + typo3/sysext/rte_ckeditor/Configuration/RTE/Full.yaml | 10 ++++++++++ .../Resources/Public/JavaScript/ckeditor5.js | 2 +- 7 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Build/Sources/TypeScript/rte_ckeditor/ckeditor5.ts b/Build/Sources/TypeScript/rte_ckeditor/ckeditor5.ts index 2be8a73e8f27..267b353218c7 100644 --- a/Build/Sources/TypeScript/rte_ckeditor/ckeditor5.ts +++ b/Build/Sources/TypeScript/rte_ckeditor/ckeditor5.ts @@ -47,7 +47,7 @@ const defaultPlugins: PluginModuleDescriptor[] = [ { module: '@ckeditor/ckeditor5-clipboard', exports: ['PastePlainText'] }, { module: '@ckeditor/ckeditor5-paste-from-office', exports: ['PasteFromOffice'] }, { module: '@ckeditor/ckeditor5-remove-format', exports: ['RemoveFormat'] }, - { module: '@ckeditor/ckeditor5-table', exports: ['Table', 'TableToolbar', 'TableProperties', 'TableCellProperties'] }, + { module: '@ckeditor/ckeditor5-table', exports: ['Table', 'TableToolbar', 'TableProperties', 'TableCellProperties', 'TableCaption'] }, { module: '@ckeditor/ckeditor5-typing', exports: ['TextTransformation'] }, { module: '@ckeditor/ckeditor5-source-editing', exports: ['SourceEditing'] }, { module: '@ckeditor/ckeditor5-alignment', exports: ['Alignment'] }, diff --git a/typo3/sysext/core/Classes/Html/RteHtmlParser.php b/typo3/sysext/core/Classes/Html/RteHtmlParser.php index d0359b7cc66e..2573439b3c6c 100644 --- a/typo3/sysext/core/Classes/Html/RteHtmlParser.php +++ b/typo3/sysext/core/Classes/Html/RteHtmlParser.php @@ -43,7 +43,7 @@ class RteHtmlParser extends HtmlParser implements LoggerAwareInterface /** * List of elements that are not wrapped into a "p" tag while doing the transformation. */ - protected string $blockElementList = 'DIV,TABLE,BLOCKQUOTE,PRE,UL,OL,H1,H2,H3,H4,H5,H6,ADDRESS,DL,DD,HEADER,SECTION,FOOTER,NAV,ARTICLE,ASIDE,FIGURE'; + protected string $blockElementList = 'DIV,TABLE,BLOCKQUOTE,PRE,UL,OL,H1,H2,H3,H4,H5,H6,ADDRESS,DL,DD,HEADER,SECTION,FOOTER,NAV,ARTICLE,ASIDE,FIGURE,FIGCAPTION'; /** * List of all tags that are allowed by default diff --git a/typo3/sysext/fluid_styled_content/Configuration/TypoScript/Helper/ParseFunc.typoscript b/typo3/sysext/fluid_styled_content/Configuration/TypoScript/Helper/ParseFunc.typoscript index 65d3e8b7590a..74cebd65ff95 100644 --- a/typo3/sysext/fluid_styled_content/Configuration/TypoScript/Helper/ParseFunc.typoscript +++ b/typo3/sysext/fluid_styled_content/Configuration/TypoScript/Helper/ParseFunc.typoscript @@ -49,7 +49,7 @@ lib.parseFunc { lib.parseFunc_RTE < lib.parseFunc lib.parseFunc_RTE { # Processing <ol>, <ul> and <table> blocks separately - externalBlocks = article, aside, blockquote, div, dd, dl, footer, header, nav, ol, section, table, ul, pre, figure + externalBlocks = article, aside, blockquote, div, dd, dl, footer, header, nav, ol, section, table, ul, pre, figure, figcaption externalBlocks { ol { stripNL = 1 @@ -95,6 +95,9 @@ lib.parseFunc_RTE { article < .div aside < .div figure < .div + figcaption { + stripNL = 1 + } blockquote < .div footer < .div header < .div diff --git a/typo3/sysext/fluid_styled_content/Configuration/TypoScript/constants.typoscript b/typo3/sysext/fluid_styled_content/Configuration/TypoScript/constants.typoscript index 7aaadf5c222c..fbb30841e63b 100644 --- a/typo3/sysext/fluid_styled_content/Configuration/TypoScript/constants.typoscript +++ b/typo3/sysext/fluid_styled_content/Configuration/TypoScript/constants.typoscript @@ -15,7 +15,7 @@ styles.content { shortcut.tables = tt_content # cat=content/parseFunc/a0; type=string; label=List of allowed HTML tags when rendering RTE content - allowTags = a, abbr, acronym, address, article, aside, b, bdo, big, blockquote, br, caption, center, cite, code, col, colgroup, dd, del, dfn, dl, div, dt, em, figure, font, footer, header, h1, h2, h3, h4, h5, h6, hr, i, img, ins, kbd, label, li, link, meta, nav, ol, p, pre, q, s, samp, sdfield, section, small, span, strike, strong, style, sub, sup, table, thead, tbody, tfoot, td, th, tr, title, tt, u, ul, var + allowTags = a, abbr, acronym, address, article, aside, b, bdo, big, blockquote, br, caption, center, cite, code, col, colgroup, dd, del, dfn, dl, div, dt, em, figcaption, figure, font, footer, header, h1, h2, h3, h4, h5, h6, hr, i, img, ins, kbd, label, li, link, meta, nav, ol, p, pre, q, s, samp, sdfield, section, small, span, strike, strong, style, sub, sup, table, thead, tbody, tfoot, td, th, tr, title, tt, u, ul, var # cat=content/cImage/a0; type=options[lazy,eager,auto,]; label=Default settings for browser-native image lazy loading: Can be "lazy" (browsers could choose to load images later), "eager" (load images right away) or "auto" (browser will determine whether the image should be lazy loaded or not) image.lazyLoading = lazy diff --git a/typo3/sysext/rte_ckeditor/Configuration/RTE/Default.yaml b/typo3/sysext/rte_ckeditor/Configuration/RTE/Default.yaml index 174bd111d26e..1abf52afffce 100644 --- a/typo3/sysext/rte_ckeditor/Configuration/RTE/Default.yaml +++ b/typo3/sysext/rte_ckeditor/Configuration/RTE/Default.yaml @@ -66,3 +66,4 @@ editor: - mergeTableCells - tableProperties - tableCellProperties + - toggleTableCaption diff --git a/typo3/sysext/rte_ckeditor/Configuration/RTE/Full.yaml b/typo3/sysext/rte_ckeditor/Configuration/RTE/Full.yaml index e23b867d5bec..09a7013f06c7 100644 --- a/typo3/sysext/rte_ckeditor/Configuration/RTE/Full.yaml +++ b/typo3/sysext/rte_ckeditor/Configuration/RTE/Full.yaml @@ -77,3 +77,13 @@ editor: - { name: 'center', className: 'text-center' } - { name: 'right', className: 'text-end' } - { name: 'justify', className: 'text-justify' } + + table: + defaultHeadings: { rows: 1 } + contentToolbar: + - tableColumn + - tableRow + - mergeTableCells + - tableProperties + - tableCellProperties + - toggleTableCaption diff --git a/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/ckeditor5.js b/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/ckeditor5.js index 7734542c76c3..facb997c5707 100644 --- a/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/ckeditor5.js +++ b/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/ckeditor5.js @@ -10,7 +10,7 @@ * * The TYPO3 project - inspiring people to share! */ -var __decorate=function(e,t,o,r){var i,n=arguments.length,s=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,o):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,o,r);else for(var l=e.length-1;l>=0;l--)(i=e[l])&&(s=(n<3?i(s):n>3?i(t,o,s):i(t,o))||s);return n>3&&s&&Object.defineProperty(t,o,s),s};import{html,LitElement}from"lit";import{customElement,property,query}from"lit/decorators.js";import AjaxRequest from"@typo3/core/ajax/ajax-request.js";import{prefixAndRebaseCss}from"@typo3/rte-ckeditor/css-prefixer.js";import{ClassicEditor}from"@ckeditor/ckeditor5-editor-classic";const defaultPlugins=[{module:"@ckeditor/ckeditor5-block-quote",exports:["BlockQuote"]},{module:"@ckeditor/ckeditor5-essentials",exports:["Essentials"]},{module:"@ckeditor/ckeditor5-find-and-replace",exports:["FindAndReplace"]},{module:"@ckeditor/ckeditor5-heading",exports:["Heading"]},{module:"@ckeditor/ckeditor5-indent",exports:["Indent"]},{module:"@ckeditor/ckeditor5-link",exports:["Link"]},{module:"@ckeditor/ckeditor5-list",exports:["List"]},{module:"@ckeditor/ckeditor5-paragraph",exports:["Paragraph"]},{module:"@ckeditor/ckeditor5-clipboard",exports:["PastePlainText"]},{module:"@ckeditor/ckeditor5-paste-from-office",exports:["PasteFromOffice"]},{module:"@ckeditor/ckeditor5-remove-format",exports:["RemoveFormat"]},{module:"@ckeditor/ckeditor5-table",exports:["Table","TableToolbar","TableProperties","TableCellProperties"]},{module:"@ckeditor/ckeditor5-typing",exports:["TextTransformation"]},{module:"@ckeditor/ckeditor5-source-editing",exports:["SourceEditing"]},{module:"@ckeditor/ckeditor5-alignment",exports:["Alignment"]},{module:"@ckeditor/ckeditor5-style",exports:["Style"]},{module:"@ckeditor/ckeditor5-html-support",exports:["GeneralHtmlSupport"]},{module:"@ckeditor/ckeditor5-basic-styles",exports:["Bold","Italic","Subscript","Superscript","Strikethrough","Underline"]},{module:"@ckeditor/ckeditor5-special-characters",exports:["SpecialCharacters","SpecialCharactersEssentials"]},{module:"@ckeditor/ckeditor5-horizontal-line",exports:["HorizontalLine"]}];let CKEditor5Element=class extends LitElement{constructor(){super(...arguments),this.options={},this.formEngine={},this.styleSheets=new Map}connectedCallback(){if(super.connectedCallback(),Array.isArray(this.options.contentsCss))for(const e of this.options.contentsCss)this.prefixAndLoadContentsCss(e,this.getAttribute("id"))}disconnectedCallback(){super.disconnectedCallback(),document.adoptedStyleSheets=document.adoptedStyleSheets.filter((e=>!this.styleSheets.has(e))),this.styleSheets.clear()}async firstUpdated(){if(!(this.target instanceof HTMLElement))throw new Error("No rich-text content target found.");const{importModules:e,removeImportModules:t,width:o,height:r,readOnly:i,debug:n,toolbar:s,placeholder:l,htmlSupport:d,wordCount:a,typo3link:c,removePlugins:p,...u}=this.options;"extraPlugins"in u&&delete u.extraPlugins,"contentsCss"in u&&delete u.contentsCss;const m=await this.resolvePlugins(defaultPlugins,e,t),h={...u,toolbar:s,plugins:m,placeholder:l,wordCount:a,typo3link:c||null,removePlugins:p||[]};void 0!==d&&(h.htmlSupport=convertPseudoRegExp(d)),ClassicEditor.create(this.target,h).then((e=>{if(this.applyEditableElementStyles(e,o,r),this.handleWordCountPlugin(e,a),this.applyReadOnly(e,i),e.plugins.has("SourceEditing")){const t=e.plugins.get("SourceEditing");e.model.document.on("change:data",(()=>{t.isSourceEditingMode||e.updateSourceElement(),this.target.dispatchEvent(new Event("change",{bubbles:!0,cancelable:!0}))}))}n&&import("@ckeditor/ckeditor5-inspector").then((({default:t})=>t.attach(e,{isCollapsed:!0})))}))}createRenderRoot(){return this}render(){return html` +var __decorate=function(e,t,o,r){var i,n=arguments.length,s=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,o):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,o,r);else for(var l=e.length-1;l>=0;l--)(i=e[l])&&(s=(n<3?i(s):n>3?i(t,o,s):i(t,o))||s);return n>3&&s&&Object.defineProperty(t,o,s),s};import{html,LitElement}from"lit";import{customElement,property,query}from"lit/decorators.js";import AjaxRequest from"@typo3/core/ajax/ajax-request.js";import{prefixAndRebaseCss}from"@typo3/rte-ckeditor/css-prefixer.js";import{ClassicEditor}from"@ckeditor/ckeditor5-editor-classic";const defaultPlugins=[{module:"@ckeditor/ckeditor5-block-quote",exports:["BlockQuote"]},{module:"@ckeditor/ckeditor5-essentials",exports:["Essentials"]},{module:"@ckeditor/ckeditor5-find-and-replace",exports:["FindAndReplace"]},{module:"@ckeditor/ckeditor5-heading",exports:["Heading"]},{module:"@ckeditor/ckeditor5-indent",exports:["Indent"]},{module:"@ckeditor/ckeditor5-link",exports:["Link"]},{module:"@ckeditor/ckeditor5-list",exports:["List"]},{module:"@ckeditor/ckeditor5-paragraph",exports:["Paragraph"]},{module:"@ckeditor/ckeditor5-clipboard",exports:["PastePlainText"]},{module:"@ckeditor/ckeditor5-paste-from-office",exports:["PasteFromOffice"]},{module:"@ckeditor/ckeditor5-remove-format",exports:["RemoveFormat"]},{module:"@ckeditor/ckeditor5-table",exports:["Table","TableToolbar","TableProperties","TableCellProperties","TableCaption"]},{module:"@ckeditor/ckeditor5-typing",exports:["TextTransformation"]},{module:"@ckeditor/ckeditor5-source-editing",exports:["SourceEditing"]},{module:"@ckeditor/ckeditor5-alignment",exports:["Alignment"]},{module:"@ckeditor/ckeditor5-style",exports:["Style"]},{module:"@ckeditor/ckeditor5-html-support",exports:["GeneralHtmlSupport"]},{module:"@ckeditor/ckeditor5-basic-styles",exports:["Bold","Italic","Subscript","Superscript","Strikethrough","Underline"]},{module:"@ckeditor/ckeditor5-special-characters",exports:["SpecialCharacters","SpecialCharactersEssentials"]},{module:"@ckeditor/ckeditor5-horizontal-line",exports:["HorizontalLine"]}];let CKEditor5Element=class extends LitElement{constructor(){super(...arguments),this.options={},this.formEngine={},this.styleSheets=new Map}connectedCallback(){if(super.connectedCallback(),Array.isArray(this.options.contentsCss))for(const e of this.options.contentsCss)this.prefixAndLoadContentsCss(e,this.getAttribute("id"))}disconnectedCallback(){super.disconnectedCallback(),document.adoptedStyleSheets=document.adoptedStyleSheets.filter((e=>!this.styleSheets.has(e))),this.styleSheets.clear()}async firstUpdated(){if(!(this.target instanceof HTMLElement))throw new Error("No rich-text content target found.");const{importModules:e,removeImportModules:t,width:o,height:r,readOnly:i,debug:n,toolbar:s,placeholder:l,htmlSupport:d,wordCount:a,typo3link:c,removePlugins:p,...u}=this.options;"extraPlugins"in u&&delete u.extraPlugins,"contentsCss"in u&&delete u.contentsCss;const m=await this.resolvePlugins(defaultPlugins,e,t),h={...u,toolbar:s,plugins:m,placeholder:l,wordCount:a,typo3link:c||null,removePlugins:p||[]};void 0!==d&&(h.htmlSupport=convertPseudoRegExp(d)),ClassicEditor.create(this.target,h).then((e=>{if(this.applyEditableElementStyles(e,o,r),this.handleWordCountPlugin(e,a),this.applyReadOnly(e,i),e.plugins.has("SourceEditing")){const t=e.plugins.get("SourceEditing");e.model.document.on("change:data",(()=>{t.isSourceEditingMode||e.updateSourceElement(),this.target.dispatchEvent(new Event("change",{bubbles:!0,cancelable:!0}))}))}n&&import("@ckeditor/ckeditor5-inspector").then((({default:t})=>t.attach(e,{isCollapsed:!0})))}))}createRenderRoot(){return this}render(){return html` <textarea id="${this.formEngine.id}" name="${this.formEngine.name}" -- GitLab