From b3a9cddf2ccecdfc07e2c7d0bc9ef33be81f7d23 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 20 May 2025 19:37:44 +1000 Subject: [PATCH 01/60] DOC-3147: TinyMCE 8.0.0 Release notes and community changelog. --- modules/ROOT/pages/8.0-release-notes.adoc | 65 ++++++++++------------- modules/ROOT/pages/migration-from-7x.adoc | 6 ++- 2 files changed, 32 insertions(+), 39 deletions(-) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index afcee2aab4..7c62f25b54 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -14,10 +14,7 @@ include::partial$misc/admon-releasenotes-for-stable.adoc[] {productname} {release-version} was released for {enterpriseversion} and {cloudname} on ,
^^, . These release notes provide an overview of the changes for {productname} {release-version}, including: -// Remove sections and section boilerplates as necessary. -// Pluralise as necessary or remove the placeholder plural marker. * xref:new-premium-plugin[New Premium plugin] -* xref:new-open-source-plugin[New Open Source plugin] * xref:accompanying-premium-plugin-changes[Accompanying Premium plugin changes] * xref:accompanying-premium-plugin-end-of-life-announcement[Accompanying Premium plugin end-of-life announcement] * xref:accompanying-open-source-plugin-end-of-life-announcement[Accompanying open source plugin end-of-life-announcement] @@ -30,29 +27,19 @@ include::partial$misc/admon-releasenotes-for-stable.adoc[] * xref:deprecated[Deprecated] * xref:known-issues[Known issues] +[NOTE] +For additional details on {productname} {release-version} breaking changes when considering upgrading, see xref:migration-from-7x.adoc[Migrating from {productname} 7 to {productname} {release-version}]. [[new-premium-plugin]] New Premium plugin The following new Premium plugin was released alongside {productname} {release-version}. -=== +// === -The new Premium plugin, **** // description here. +// The new Premium plugin, **** // description here. -For information on the **** plugin, see xref:.adoc[]. - - -[[new-open-source-plugin]] -== New Open Source plugin - -The following new Open Source plugin was released alongside {productname} {release-version}. - -=== - -The new open source plugin, **** // description here. - -For information on the **** plugin, see xref:.adoc[]. +// For information on the **** plugin, see xref:.adoc[]. [[accompanying-premium-plugin-changes]] @@ -60,17 +47,17 @@ For information on the **** plugin, see xref: +// === -The {productname} {release-version} release includes an accompanying release of the **** premium plugin. +// The {productname} {release-version} release includes an accompanying release of the **** premium plugin. -**** includes the following . +// **** includes the following . -==== +// ==== -// CCFR here. +// // CCFR here. -For information on the **** plugin, see: xref:.adoc[]. +// For information on the **** plugin, see: xref:.adoc[]. [[accompanying-premium-plugin-end-of-life-announcement]] @@ -78,9 +65,9 @@ For information on the **** plugin, see: xref: +// === -{productname}’s xref:.adoc[] plugin will be deactivated on
, , and is no longer available for purchase. +// {productname}’s xref:.adoc[] plugin will be deactivated on
, , and is no longer available for purchase. [[accompanying-open-source-plugin-end-of-life-announcement]] @@ -88,9 +75,9 @@ The following Premium plugin has been announced as reaching its end-of-life: The following open source plugin has been announced as reaching its end-of-life: -=== +// === -{productname}’s xref:.adoc[] plugin will be deactivated on
, , and is no longer available for purchase. +// {productname}’s xref:.adoc[] plugin will be deactivated on
, , and is no longer available for purchase. [[accompanying-enhanced-skins-and-icon-packs-changes]] @@ -112,7 +99,7 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a {productname} {release-version} also includes the following improvement: -=== +// === // #TINY-vwxyz1 // CCFR here. @@ -123,7 +110,7 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a {productname} {release-version} also includes the following addition: -=== +// === // #TINY-vwxyz1 // CCFR here. @@ -134,7 +121,7 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a {productname} {release-version} also includes the following change: -=== +// === // #TINY-vwxyz1 // CCFR here. @@ -145,7 +132,7 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a {productname} {release-version} also includes the following removal: -=== +// === // #TINY-vwxyz1 // CCFR here. @@ -156,7 +143,7 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a {productname} {release-version} also includes the following bug fix: -=== +// === // #TINY-vwxyz1 // CCFR here. @@ -167,7 +154,7 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a {productname} {release-version} includes : -=== +// === // #TINY-vwxyz1 // CCFR here. @@ -178,9 +165,10 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a {productname} {release-version} includes the following deprecation: -=== The `` configuration property, ``, has been deprecated +// === The `` configuration property, ``, has been deprecated +// #TINY-vwxyz1 -// placeholder here. +// CCFR here. [[known-issues]] @@ -190,7 +178,8 @@ This section describes issues that users of {productname} {release-version} may There known issue in {productname} {release-version}. -=== +// === // #TINY-vwxyz1 -// CCFR here. \ No newline at end of file +// CCFR here. +// **Status**: This issue is currently being investigated. \ No newline at end of file diff --git a/modules/ROOT/pages/migration-from-7x.adoc b/modules/ROOT/pages/migration-from-7x.adoc index e7c6054b80..f556e5a8a2 100644 --- a/modules/ROOT/pages/migration-from-7x.adoc +++ b/modules/ROOT/pages/migration-from-7x.adoc @@ -4,4 +4,8 @@ :keywords: migration, considerations, premigration, pre-migration :release-version: 8.0 -// TODO \ No newline at end of file +// TODO + +== {productname} {release-version} core changes. + +For additional details on {productname} {release-version} changes, see xref:8.0-release-notes.adoc#overview[{productname} {release-version} release notes]. \ No newline at end of file From bcb696017d2b314c86b28b550aff09c576e410ff Mon Sep 17 00:00:00 2001 From: "CODE:AG" <57781325+abhinavgandham@users.noreply.github.com> Date: Fri, 11 Jul 2025 14:41:22 +1000 Subject: [PATCH 02/60] DOC-3147: HTML schema did not treat colgroup or col elements as block elements. (#3790) --- modules/ROOT/pages/8.0-release-notes.adoc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 7c62f25b54..086565cc14 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -143,10 +143,12 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a {productname} {release-version} also includes the following bug fix: -// === -// #TINY-vwxyz1 +=== The HTML schema did not treat `colgroup` or `col` elements as block elements. +// #TINY-12092 -// CCFR here. +In previous versions of {productname}, whitespace between `` and `` tags was not removed by {productname}'s HTML schema. This behavior caused the editor to preserve unnecessary whitespace characters in the table markup. + +This issue has been resolved in `{release-version}`. Both `colgroup` and `col` elements are now treated as block-level elements, ensuring that extraneous whitespace is stripped from these areas. As a result, the editor now produces cleaner and more concise table markup. [[security-fixes]] From cdb714af2242acd2758f363f14d583e4b20b8bdd Mon Sep 17 00:00:00 2001 From: "CODE:AG" <57781325+abhinavgandham@users.noreply.github.com> Date: Fri, 11 Jul 2025 14:45:57 +1000 Subject: [PATCH 03/60] DOC-3147: Decorative images would lose their decorative properties when the subtoolbar was closed using the confirmation button. (#3774) Co-authored-by: Karl Kemister-Sheppard --- modules/ROOT/pages/8.0-release-notes.adoc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 086565cc14..fc7007be6f 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -143,6 +143,14 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a {productname} {release-version} also includes the following bug fix: + +=== Decorative images would lose their decorative status when the `alt` subtoolbar was closed when using the apply button. +// #TINY-11912 + +Previously, an issue was identified where closing the `alt` subtoolbar using the `Apply` button would inadvertently remove the decorative status from an image that was already marked as decorative. This occurred because the `onSetup` API disabled the input group, leading the `Apply` logic to incorrectly interpret the image as non-decorative. + +This issue has been resolved in {productname} {release-version}. The `onSetup` and `Apply` behavior has been aligned to consistently evaluate the input group, ensuring the decorative status is preserved as expected. + === The HTML schema did not treat `colgroup` or `col` elements as block elements. // #TINY-12092 From 8120b790feab19fa8a41daeaf424aeb685001e77 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Fri, 11 Jul 2025 14:48:49 +1000 Subject: [PATCH 04/60] DOC-3147: Word import of lists with a lighter level failed parsing. (#3765) --- modules/ROOT/pages/8.0-release-notes.adoc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index fc7007be6f..9513c6eb0c 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -1,4 +1,3 @@ - = {productname} {release-version} :release-version: 8.0.0 :navtitle: {productname} {release-version} @@ -59,6 +58,16 @@ The following premium plugin updates were released alongside {productname} {rele // For information on the **** plugin, see: xref:.adoc[]. +=== PowerPaste + +The {productname} {release-version} release includes an accompanying release of the **PowerPaste** premium plugin. + +==== Word import of lists with a "lighter" level failed parsing. + +When users pasted content from Microsoft Word documents containing lists styled with Word’s "No List" setting into the editor with PowerPaste enabled, the operation failed due to a parsing error. As a result, the content was not inserted into the editor, causing disruption to content workflows. {productname} {release-version} addresses this issue by updating the **PowerPaste** parser to correctly handle lists with the "No List" style. As a result, users can now successfully paste such content into the editor without encountering errors. + +For information on the **PowerPaste** plugin, see: xref:introduction-to-powerpaste.adoc[PowerPaste]. + [[accompanying-premium-plugin-end-of-life-announcement]] == Accompanying Premium plugin end-of-life announcement From e43b3531ab99f098d7e95a100a2b45b3db3e0f0a Mon Sep 17 00:00:00 2001 From: "CODE:AG" <57781325+abhinavgandham@users.noreply.github.com> Date: Fri, 11 Jul 2025 15:11:19 +1000 Subject: [PATCH 05/60] DOC-3147: It wasn't possible to navigate out of a using the left and right arrow keys in Firefox. (#3773) Co-authored-by: Karl Kemister-Sheppard --- modules/ROOT/pages/8.0-release-notes.adoc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 9513c6eb0c..181995211f 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -152,6 +152,12 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a {productname} {release-version} also includes the following bug fix: +=== It was not possible to navigate out of a `figcaption` using the left and right arrow keys in Firefox. +// #TINY-11982 + +Prior to {productname} {release-version}, Firefox exhibited an issue where pressing the left or right arrow keys would not allow users to exit the image `figcaption` element. This behavior was inconsistent with other major browsers such as Google Chrome and Safari, where the arrow keys functioned as expected and allowed seamless navigation out of the `figcaption`. + +With {productname} {release-version}, this issue has been resolved. Users can now exit the `figcaption` using the left/right arrow keys in Firefox, aligning its behavior with that of other browsers. This update ensures a more consistent user experience. === Decorative images would lose their decorative status when the `alt` subtoolbar was closed when using the apply button. // #TINY-11912 From 2fff2ecb1d940b0a8deb05957782d1a47a8056bd Mon Sep 17 00:00:00 2001 From: "CODE:AG" <57781325+abhinavgandham@users.noreply.github.com> Date: Fri, 11 Jul 2025 15:13:53 +1000 Subject: [PATCH 06/60] DOC-3147: Using arrow navigation between buttons when a button had the mouse over could stop the navigation. (#3772) Co-authored-by: Karl Kemister-Sheppard --- modules/ROOT/pages/8.0-release-notes.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 181995211f..253246b9a6 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -152,6 +152,13 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a {productname} {release-version} also includes the following bug fix: +=== Arrow key navigation between buttons was blocked when a button is hovered by the mouse. +// #TINY-12163 + +In previous versions of {productname}, if a button was hovered by the mouse while using arrow keys for navigation, focus would return to the previously focused element. This caused the selection to become stuck on the button with the `mouseover` event. + +{productname} {release-version} resolves this issue by preventing the `mouseover` event from being triggered again during arrow key navigation, ensuring a seamless user experience when navigating with arrow keys. + === It was not possible to navigate out of a `figcaption` using the left and right arrow keys in Firefox. // #TINY-11982 From b1a21b2734647adbbdbb7b2e2c1fd80a25874609 Mon Sep 17 00:00:00 2001 From: "CODE:AG" <57781325+abhinavgandham@users.noreply.github.com> Date: Sun, 13 Jul 2025 19:59:45 +1000 Subject: [PATCH 07/60] DOC-3147: Resize handles are more accessible with and attributes. (#3749) --- modules/ROOT/pages/8.0-release-notes.adoc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 253246b9a6..e6c3b3e008 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -108,10 +108,12 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a {productname} {release-version} also includes the following improvement: -// === -// #TINY-vwxyz1 +=== Resize handles are more accessible with `role` and `aria-valuetext` attributes. +// #TINY-11421 -// CCFR here. +In previous versions of {productname}, the editor's resize handle lacked a `role` attribute, raising accessibility concerns. + +In {productname} {release-version}, the resize handle now includes a `role` seperator and an `aria-valuetext` attribute that dynamically reflects the current dimensions of the editor. These improvements enhance accessibility and ensure more accurate announcements by screen readers. [[additions]] From 4bcd9e997aff4f11925bbfa0c8d041a3f789358c Mon Sep 17 00:00:00 2001 From: "CODE:AG" <57781325+abhinavgandham@users.noreply.github.com> Date: Sun, 13 Jul 2025 20:00:43 +1000 Subject: [PATCH 08/60] DOC-3147: Toolbar drawer now closes when the editor loses focus. (#3750) Co-authored-by: Karl Kemister-Sheppard --- modules/ROOT/pages/8.0-release-notes.adoc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index e6c3b3e008..89d0798e11 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -154,6 +154,14 @@ In {productname} {release-version}, the resize handle now includes a `role` sepe {productname} {release-version} also includes the following bug fix: + +=== Toolbar drawer now closes when the editor loses focus. +// #TINY-12125 + +In previous versions of {productname}, the floating toolbar remained visible even when the editor lost focus. This behavior introduced potential accessibility concerns, as the toolbar was not properly associated with the editor it controlled, potentially causing confusion for users. + +In {productname} {release-version}, the toolbar now automatically closes when the editor loses focus. This ensures it is only displayed within the appropriate context, enhancing accessibility and improving the overall user experience. + === Arrow key navigation between buttons was blocked when a button is hovered by the mouse. // #TINY-12163 From 1053f8b06b55898a71c41286431d0f4779623028 Mon Sep 17 00:00:00 2001 From: "CODE:AG" <57781325+abhinavgandham@users.noreply.github.com> Date: Mon, 14 Jul 2025 12:59:17 +1000 Subject: [PATCH 09/60] DOC-3147: Instructions on how to navigate the color swatch, image select and insert (#3788) table widget are now announced by the screen readers. Co-authored-by: Karl Kemister-Sheppard --- modules/ROOT/pages/8.0-release-notes.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 89d0798e11..44cef0c985 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -108,6 +108,13 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a {productname} {release-version} also includes the following improvement: +=== Instructions on how to navigate the color swatch, image select and insert table widget are now announced by screen readers. +// #TINY-12189 + +Previously, interactive elements such as the color swatch, create table grid, and image select were missing an `aria-label`. This resulted in a lack of instructions for keyboard users and hindered overall accessibility. + +{productname} {release-version} now includes `aria-labels` for these elements, providing clear keyboard navigation instructions. This improvement ensures a more accessible experience for all users. + === Resize handles are more accessible with `role` and `aria-valuetext` attributes. // #TINY-11421 From b2a8207afe7b708315ff2114dffb1231995b8e34 Mon Sep 17 00:00:00 2001 From: "CODE:AG" <57781325+abhinavgandham@users.noreply.github.com> Date: Mon, 14 Jul 2025 13:02:24 +1000 Subject: [PATCH 10/60] DOC-3147: Default value for `pagebreak_separator` option to better suit modern standards. (#3780) * DOC-3147: Default value for option to better suit modern standards. * DOC-3147: Fixed syntax issue. * Update modules/ROOT/partials/configuration/pagebreak_separator.adoc * Update modules/ROOT/partials/configuration/pagebreak_separator.adoc * Update modules/ROOT/pages/8.0-release-notes.adoc --------- Co-authored-by: Karl Kemister-Sheppard --- modules/ROOT/pages/8.0-release-notes.adoc | 13 ++++++++++--- .../partials/configuration/pagebreak_separator.adoc | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 44cef0c985..e84bbf1a88 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -139,10 +139,17 @@ In {productname} {release-version}, the resize handle now includes a `role` sepe {productname} {release-version} also includes the following change: -// === -// #TINY-vwxyz1 +=== Changed the default value for the `pagebreak_separator` option. +// #TINY-12013 -// CCFR here. +In previous versions of {productname}, inserting a page break in the editor did not translate correctly when exporting using the xref:exportpdf.adoc[Export to PDF] plugin. Similarly, the xref:exportword.adoc[Export to Word] plugin also failed to preserve page breaks in the exported documents. As a result, exported files lacked the intended page breaks, leading to confusing output for users. + +With the release of {productname} {release-version}, this issue has been resolved by updating the default HTML value of the `pagebreak_separator` option: + +* **Old value** – `''` +* **New value** – `'
'` + +This change aligns better with modern standards and ensures that page breaks are now accurately rendered in exported documents. [[removed]] diff --git a/modules/ROOT/partials/configuration/pagebreak_separator.adoc b/modules/ROOT/partials/configuration/pagebreak_separator.adoc index e5624ca5cf..5ba3a93393 100644 --- a/modules/ROOT/partials/configuration/pagebreak_separator.adoc +++ b/modules/ROOT/partials/configuration/pagebreak_separator.adoc @@ -3,7 +3,7 @@ *Type:* `+String+` -*Default value:* `+''+` +*Default value:* `+'
'+` === Example: using `+pagebreak_separator+` @@ -13,6 +13,6 @@ tinymce.init({ selector: 'textarea', // change this value according to your HTML plugins: 'pagebreak', toolbar: 'pagebreak', - pagebreak_separator: '' + pagebreak_separator: '
My page break
' }); ---- From 74cee8e7c4300d454398bc90a6f672f9d071ab7d Mon Sep 17 00:00:00 2001 From: "CODE:AG" <57781325+abhinavgandham@users.noreply.github.com> Date: Mon, 14 Jul 2025 13:17:14 +1000 Subject: [PATCH 11/60] The `contextform` subtoolbar is no longer dismissed when using the back button in inline editors. (#3770) * The subtoolbar is no longer dismissed when using the back button in inline editors. * Update modules/ROOT/pages/8.0-release-notes.adoc --------- Co-authored-by: Karl Kemister-Sheppard --- modules/ROOT/pages/8.0-release-notes.adoc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index e84bbf1a88..141fcda19f 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -168,6 +168,12 @@ This change aligns better with modern standards and ensures that page breaks are {productname} {release-version} also includes the following bug fix: +=== In inline mode, pressing the back button dismissed the context toolbar and moved focus from the selected image to the editor. +// #TINY-12118 + +In inline mode, the context form toolbar incorrectly shifted focus from the selected image to the editor container. As a result, the plugin which relies on the current selection to apply changes was unable to apply attributes like `alt` text to the correct image. + +{productname} {release-version} resolves this by ensuring that the focus is preserved properly, ensuring that the plugin now applies changes such as `alt` text to the correct image in inline mode. === Toolbar drawer now closes when the editor loses focus. // #TINY-12125 From 7b2614505aea8e5967bd9adec4dcb4abc1be2916 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Mon, 14 Jul 2025 13:18:49 +1000 Subject: [PATCH 12/60] DOC-3147: Deleting a whole element would sometimes modify nearby content (#3752) * DOC-3147: Deleting a whole element would sometimes modify nearby content. * copy edits. * Update modules/ROOT/pages/8.0-release-notes.adoc --- modules/ROOT/pages/8.0-release-notes.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 141fcda19f..f2aa1fe02e 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -210,6 +210,13 @@ In previous versions of {productname}, whitespace between `` and `` element that precedes a `

` tag could cause the `

` to be transformed into a `

`, resulting in unintended structural changes. + +This issue has been resolved in {productname} {release-version} by improving how element deletions are handled within the editor's DOM logic. Cutting or deleting a selected element now preserves the integrity and tag type of adjacent elements. Users can expect consistent and predictable editing behavior when modifying HTML source content. + [[security-fixes]] == Security fixes From 27a69636923726cb70d0d3038327fc9ecd003869 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Mon, 14 Jul 2025 14:12:13 +1000 Subject: [PATCH 13/60] DOC-3147: Removed undocumented documentBaseUrl property from Editor instances. documentBaseURI is the supported property now. (#3787) --- modules/ROOT/pages/8.0-release-notes.adoc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index f2aa1fe02e..b3c53cf97a 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -162,6 +162,12 @@ This change aligns better with modern standards and ensures that page breaks are // CCFR here. +=== Removed undocumented `documentBaseUrl` property from Editor instances. `documentBaseURI` is the supported property now. +// #TINY-12182 + +An undocumented `documentBaseUrl` property was previously accessible on `Editor` instances. This property was not part of the supported public API and could lead to confusion or inconsistent usage across implementations. + +To improve API clarity and maintain a well-defined interface, the `documentBaseUrl` property has been removed. Integrators should use the officially supported `documentBaseURI` property to access the base URI of the document. [[bug-fixes]] == Bug fixes From 08564790aa3540fe397638e8dcb377dcdd05e706 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Mon, 14 Jul 2025 14:15:26 +1000 Subject: [PATCH 14/60] DOC-3147: The translate API now automatically replaces three dots in a row with an ellipsis character. (#3792) --- modules/ROOT/pages/8.0-release-notes.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index b3c53cf97a..61564a3271 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -122,6 +122,10 @@ In previous versions of {productname}, the editor's resize handle lacked a `role In {productname} {release-version}, the resize handle now includes a `role` seperator and an `aria-valuetext` attribute that dynamically reflects the current dimensions of the editor. These improvements enhance accessibility and ensure more accurate announcements by screen readers. +=== The translate API now automatically replaces three dots in a row with an ellipsis character. +// #TINY-12155 + +Previously, menu items and tooltips containing three consecutive periods (`...`) were read aloud by the JAWS screen reader as "dot dot dot," which could confuse users relying on assistive technologies. To enhance accessibility, the `translate` API in {productname} {release-version} now automatically replaces three dots with the typographic ellipsis character (`…`) across all translations. This update ensures a consistent visual appearance while improving screen reader behavior, as the ellipsis character is not read aloud. The change is implemented directly in the translation function, ensuring comprehensive coverage across all languages. [[additions]] == Additions From bb1d6abd7373a65c94ec80627366a41a8b68f2db Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Mon, 14 Jul 2025 14:17:51 +1000 Subject: [PATCH 15/60] DOC-3147: Strikethrough format could be added outside font size format, which renders incorrectly in some browsers. (#3778) * DOC-3147: Strikethrough format could be added outside font size format, which renders incorrectly in some browsers. * Update modules/ROOT/pages/8.0-release-notes.adoc Co-authored-by: CODE:AG <57781325+abhinavgandham@users.noreply.github.com> --------- Co-authored-by: CODE:AG <57781325+abhinavgandham@users.noreply.github.com> --- modules/ROOT/pages/8.0-release-notes.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 61564a3271..ed7130bb95 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -227,6 +227,13 @@ Previously, deleting a complete HTML element using the "Source Code" editor eith This issue has been resolved in {productname} {release-version} by improving how element deletions are handled within the editor's DOM logic. Cutting or deleting a selected element now preserves the integrity and tag type of adjacent elements. Users can expect consistent and predictable editing behavior when modifying HTML source content. +=== Strikethrough format could be added outside font size format, which renders incorrectly in some browsers. +// #TINY-12004 + +Previously, there was an issue where combining strikethrough (`s` element) and font size formatting could lead to incorrect rendering in some browsers, particularly Chrome. This occurred when the `s` (strikethrough) element was placed outside a font size `span`, causing the strikethrough line to render incorrectly. + +The fix ensures that the `s` element is now properly nested inside the font size element, improving visual consistency across browsers. + [[security-fixes]] == Security fixes From 8f727d52082b12d1c970105eb6e16ec007ebf23a Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Mon, 14 Jul 2025 20:25:46 +1000 Subject: [PATCH 16/60] DOC-3147: Accessibility: Enhanced image accessibility checks & rules in `a11ychecker` plugin. (#3794) * DOC-3147: Accessibility: Enhanced image accessibility checks in a11ychecker plugin. * DOC-3147: Add a11ychecker_alt_text_max_length new option to the release notes. * DOC-3147: Fix lvl heading issues for TOC. * DOC-3147: Update accessibility rules and configuration options for image handling * Update modules/ROOT/partials/configuration/a11ychecker_allow_decorative_images.adoc Co-authored-by: CODE:AG <57781325+abhinavgandham@users.noreply.github.com> --------- Co-authored-by: Arvin Han <20640097+ArvinJ-H@users.noreply.github.com> Co-authored-by: CODE:AG <57781325+abhinavgandham@users.noreply.github.com> --- .../examples/live-demos/a11ychecker/index.js | 3 + modules/ROOT/pages/8.0-release-notes.adoc | 34 ++ modules/ROOT/pages/a11ychecker.adoc | 301 ++---------------- modules/ROOT/partials/a11y-rules/d1.adoc | 51 +++ modules/ROOT/partials/a11y-rules/d2.adoc | 57 ++++ modules/ROOT/partials/a11y-rules/d3.adoc | 42 +++ modules/ROOT/partials/a11y-rules/d4o.adoc | 44 +++ modules/ROOT/partials/a11y-rules/d4u.adoc | 44 +++ modules/ROOT/partials/a11y-rules/d5.adoc | 81 +++++ modules/ROOT/partials/a11y-rules/h93.adoc | 60 ++++ modules/ROOT/partials/a11y-rules/i1.adoc | 71 +++++ modules/ROOT/partials/a11y-rules/i2.adoc | 63 ++++ modules/ROOT/partials/a11y-rules/i3.adoc | 56 ++++ modules/ROOT/partials/a11y-rules/i4.adoc | 46 +++ modules/ROOT/partials/a11y-rules/t1.adoc | 80 +++++ modules/ROOT/partials/a11y-rules/t2.adoc | 83 +++++ modules/ROOT/partials/a11y-rules/t3.adoc | 71 +++++ modules/ROOT/partials/a11y-rules/t4a.adoc | 93 ++++++ modules/ROOT/partials/a11y-rules/t4b.adoc | 113 +++++++ modules/ROOT/partials/a11y-rules/t4c.adoc | 97 ++++++ .../a11ychecker_allow_decorative_images.adoc | 36 ++- .../a11ychecker_alt_text_max_length.adoc | 20 ++ 22 files changed, 1269 insertions(+), 277 deletions(-) create mode 100644 modules/ROOT/partials/a11y-rules/d1.adoc create mode 100644 modules/ROOT/partials/a11y-rules/d2.adoc create mode 100644 modules/ROOT/partials/a11y-rules/d3.adoc create mode 100644 modules/ROOT/partials/a11y-rules/d4o.adoc create mode 100644 modules/ROOT/partials/a11y-rules/d4u.adoc create mode 100644 modules/ROOT/partials/a11y-rules/d5.adoc create mode 100644 modules/ROOT/partials/a11y-rules/h93.adoc create mode 100644 modules/ROOT/partials/a11y-rules/i1.adoc create mode 100644 modules/ROOT/partials/a11y-rules/i2.adoc create mode 100644 modules/ROOT/partials/a11y-rules/i3.adoc create mode 100644 modules/ROOT/partials/a11y-rules/i4.adoc create mode 100644 modules/ROOT/partials/a11y-rules/t1.adoc create mode 100644 modules/ROOT/partials/a11y-rules/t2.adoc create mode 100644 modules/ROOT/partials/a11y-rules/t3.adoc create mode 100644 modules/ROOT/partials/a11y-rules/t4a.adoc create mode 100644 modules/ROOT/partials/a11y-rules/t4b.adoc create mode 100644 modules/ROOT/partials/a11y-rules/t4c.adoc create mode 100644 modules/ROOT/partials/configuration/a11ychecker_alt_text_max_length.adoc diff --git a/modules/ROOT/examples/live-demos/a11ychecker/index.js b/modules/ROOT/examples/live-demos/a11ychecker/index.js index bd41b7b2b9..dd694f2b25 100644 --- a/modules/ROOT/examples/live-demos/a11ychecker/index.js +++ b/modules/ROOT/examples/live-demos/a11ychecker/index.js @@ -2,8 +2,11 @@ tinymce.init({ selector: 'textarea#a11ychecker', plugins: 'a11ychecker advcode table advlist lists image media anchor link autoresize', toolbar: 'a11ycheck | blocks bold forecolor backcolor | bullist numlist | link image media anchor | table | code', + max_height: 500, a11y_advanced_options: true, a11ychecker_html_version: 'html5', a11ychecker_level: 'aaa', + a11ychecker_allow_decorative_images: true, + a11ychecker_alt_text_max_length: 150, content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }' }); diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index ed7130bb95..b4759ac0ee 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -58,6 +58,40 @@ The following premium plugin updates were released alongside {productname} {rele // For information on the **** plugin, see: xref:.adoc[]. +=== Accessibility Checker + +The {productname} {release-version} release includes an accompanying release of the **Accessibility Checker** premium plugin. + +**Accessibility Checker** Premium plugin includes the following improvements. + +=== Accessibility: Enhanced image accessibility checks in a11ychecker plugin +// #TINY-10903 + +The {productname} {release-version} introduces four new image accessibility rules (xref:a11ychecker.adoc##image-rules[Image rules]) in the xref:a11ychecker.adoc[a11ychecker] plugin to improve compliance and authoring guidance. These rules help identify common accessibility issues related to image use and provide actionable recommendations: + +* *xref:a11ychecker.adoc#I1[I1: Mixed Signals & Decorative Policy]*: Flags images with conflicting accessibility indicators (e.g., `alt` with `role="presentation"`) and ensures decorative images comply with best practices. +* *xref:a11ychecker.adoc#I2[I2: Alt Attribute Requirement]*: Enforces the presence of the `alt` attribute on all `` elements, regardless of other labeling mechanisms like `aria-label`, `aria-labelledby`, or `title`. +* *xref:a11ychecker.adoc#I3[I3: Filename Detection]*: Warns when `alt` text appears to be a filename (e.g., `image123.jpg`), including cases with URL encoding. +* *xref:a11ychecker.adoc#I4[I4: Alt Text Length]*: Detects `alt` text that exceeds a configurable maximum length, promoting concise descriptions. The default limit is 100 characters and can be adjusted using the new xref:a11ychecker.adoc#a11ychecker_alt_text_max_length[`a11ychecker_alt_text_max_length`] setting. + +Additional improvements include a rule precedence system to avoid duplicate violations, centralized image intent detection (e.g., decorative, informative, mixed signals, incomplete), and more readable user-facing messages. Technical terminology such as "alternative text" has been replaced with "text description," and repair instructions are now more contextual and user-friendly. + +=== New `a11ychecker_alt_text_max_length` configuration option for Accessibility Checker alt text length +// #TINY-10903 + +A new configuration option, xref:a11ychecker.adoc#a11ychecker_alt_text_max_length[`a11ychecker_alt_text_max_length`], has been added to the Accessibility Checker plugin. This option allows users to configure the maximum allowed length for image alt text descriptions. The default value is 150 characters. For example: + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'a11ychecker', + a11ychecker_alt_text_max_length: 150 // Set maximum length to 150 characters +}); +---- + +For more information on the Accessibility Checker plugin, see: xref:a11ychecker.adoc[Accessibility Checker]. + === PowerPaste The {productname} {release-version} release includes an accompanying release of the **PowerPaste** premium plugin. diff --git a/modules/ROOT/pages/a11ychecker.adoc b/modules/ROOT/pages/a11ychecker.adoc index 240c08ac70..6abb3f1fda 100644 --- a/modules/ROOT/pages/a11ychecker.adoc +++ b/modules/ROOT/pages/a11ychecker.adoc @@ -46,300 +46,59 @@ Each rule has a severity level, which will be one of the following, listed in or * Warning * Error -[[D1]] -=== D1 - Usage of paragraphs as headings +[[document-structure-rules]] +=== Document structure rules -*Rule description:* this rule checks that `+h1+`-`+h6+` tags are used for heading content, not `+p+` tags. Not using correct heading markup will make it difficult for assistive technologies to represent and navigate through your content. +include::partial$a11y-rules/d1.adoc[] -==== {pluginname} rule details - D1 +include::partial$a11y-rules/d2.adoc[] -Notification level (severity):: Warning +include::partial$a11y-rules/d3.adoc[] -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA +include::partial$a11y-rules/d4o.adoc[] -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 +include::partial$a11y-rules/d4u.adoc[] -WCAG 2.1 specifications:: +include::partial$a11y-rules/d5.adoc[] -* https://www.w3.org/WAI/WCAG21/Techniques/html/H42.html[H42 - Using h1-h6 to identify headings]. -* https://www.w3.org/WAI/WCAG21/Techniques/html/H69.html[H69 - Providing heading elements at the beginning of each section of content]. +''' -[[D2]] -=== D2 - Sequential headings +[[html-rules]] +=== HTML rules -*Rule description:* this rule checks that headings tags are used sequentially. +include::partial$a11y-rules/h93.adoc[] -For example: A `+h1+` heading should be followed by a `+h2+` heading, not a `+h3+` heading. Using sequential headings will make it easier for assistive technology to parse your content. +''' -==== {pluginname} rule details - D2 +[[image-rules]] +=== Image rules -Notification level (severity):: Error +include::partial$a11y-rules/i1.adoc[] -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA +include::partial$a11y-rules/i2.adoc[] -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 +include::partial$a11y-rules/i3.adoc[] -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/general/G141.html[G141 - Organizing a page using headings]. +include::partial$a11y-rules/i4.adoc[] -[[D3]] -=== D3 - Adjacent links +''' -*Rule description:* this rule checks that links next to other links do not have the same `+href+` attribute. +[[table-rules]] +=== Table rules -For example: If an image link and a text link have the same `+href+` attribute, both elements should be in the same `+a+` element. If an image link and a text link point to the same URL but are two separate elements, it can be confusing for users of screen readers and other assistive technologies. +include::partial$a11y-rules/t1.adoc[] -==== {pluginname} rule details - D3 +include::partial$a11y-rules/t2.adoc[] -Notification level (severity):: Error +include::partial$a11y-rules/t3.adoc[] -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA +include::partial$a11y-rules/t4a.adoc[] -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 +include::partial$a11y-rules/t4b.adoc[] -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H2.html[H2 - Combining adjacent image and text links for the same resource]. +include::partial$a11y-rules/t4c.adoc[] -[[D4O]] -=== D4O - Ordered list structure - -*Rule description:* this rule checks that an `+ol+` element is used for ordered lists. Do not use paragraphs beginning with numbers or roman numerals instead of an `+ol+` element containing `+li+` items. This is to simplify navigation and parsing of the content for users of assistive technologies. - -==== {pluginname} rule details - D4O - -Notification level (severity):: Error - -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA - -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 - -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H48.html[H48 - Using ol, ul and dl for lists or groups of links]. - -[[D4U]] -=== D4U - Unordered list structure - -*Rule description:* this rule checks that a `+ul+` element is used for unordered lists. Do not use paragraphs beginning with `+*+` or `+-+` or some similar character instead of an `+ol+` element containing `+li+` items. This is to simplify navigation and parsing of the content for users of assistive technologies. - -==== {pluginname} rule details - D4U - -Notification level (severity):: Error - -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA - -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 - -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H48.html[H48 - Using ol, ul and dl for lists or groups of links]. - -[[D5]] -=== D5 - Contrast ratio of the text (D5A, D5B, and D5C) - -*Rule description:* this rule checks that the contrast ratio of the text is above the following values: - -* When the compliance level is set to AA, -** 4.5:1 for normal text -** 3:1 for large text -* When the compliance level is set to AAA, -** 7:1 for any text - -Text with a low contrast ratio is hard to read for users with impaired vision. - -[[D5A]] -==== {pluginname} rule details - D5A - -Notification level (severity):: Error - -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level AA - -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 - -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/general/G145.html[G145 - Ensuring that a contrast ratio of at least 3:1 exists between text (and images of text) and background behind the text]. - -[[D5B]] -==== {pluginname} rule details - D5B - -Notification level (severity):: Error - -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level AA - -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 - -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/general/G18.html[G18 - Ensuring that a contrast ratio of at least 4.5:1 exists between text (and images of text) and background behind the text]. - -[[D5C]] -==== {pluginname} rule details - D5C - -Notification level (severity):: Error - -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level AAA - -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 - -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/general/G17.html[G17 - Ensuring that a contrast ratio of at least 7:1 exists between text (and images of text) and background behind the text]. - -[[H93]] -=== H93 - IDs must be unique - -*Rule description:* this rule checks that all `+id+` attributes are unique in the editor. Duplicate `+id+` attributes are known to cause problems for assistive technologies when parsing the content. - -==== {pluginname} rule details - H93 - -Notification level (severity):: Error - -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA - -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 - -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H93.html[H93 - Ensuring that id attributes are unique on a Web page]. - -[[I1]] -=== I1 - Image `+alt+` text - -*Rule description:* this rule checks that all images have alternative (`+alt+`) text for screen readers and other assistive technologies. - -==== {pluginname} rule details - I1 - -Notification level (severity):: Error - -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA - -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 - -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/general/G95.html[G95 - Providing short text alternatives that provide a brief description of the non-text content]. - -include::partial$misc/admon-accessibility-rule-i3-can-also-be-applied.adoc[] - -[[I2]] -=== I2 - Image `+alt+` text is not the image filename - -*Rule description:* this rule checks that the `+alt+` attribute text of the image is not the same as the filename of the image. - -==== {pluginname} rule details - I2 - -Notification level (severity):: Error - -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA - -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 - -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/general/G95.html[G95 - Providing short text alternatives that provide a brief description of the non-text content]. - -include::partial$misc/admon-accessibility-rule-i3-can-also-be-applied.adoc[] - -[[I3]] -=== I3 - Image `+alt+` text is not greater than 100 characters - -*Rule description:* this rule checks that the `+alt+` attribute text of the image is not more than 100 characters. - -An _Image alternative text should be less than 100 characters_ warning dialog presents if the alternative (`+alt+`) text is longer than 100 characters. This dialog also presents the alternative text in an editable field, for immediate repair. - -==== {pluginname} rule details - I3 - -Notification level (severity):: Warning - -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA - -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 - -WCAG 2.1 specification:: n/a. - - -[[T1]] -=== T1 - Table caption - -*Rule description:* this rule checks that all `+table+` elements have a `+caption+` element describing the data inside the table to simplify parsing and navigation of the content for users of assistive technologies. - -==== {pluginname} rule details - T1 - -Notification level (severity):: Error - -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA - -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 - -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H39.html[H39 - Using caption elements to associate data table captions with data tables]. - -[[T2]] -=== T2 - Complex table summary - -*Rule description:* this rule checks that all complex tables must have a `+summary+` attribute explaining to users of assistive technologies how to navigate through the data inside of the table. - -[NOTE] -==== -This rule only applies to HTML 4 content and is not checked when `+a11ychecker_html_version+` is set to `+html5+`. -==== - -==== {pluginname} rule details - T2 - -Notification level (severity):: Warning - -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA - -xref:a11ychecker_html_version[HTML version]:: HTML4 - -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H73.html[H73 - Using the summary attribute of the table element to give an overview of data tables]. - -[[T3]] -=== T3 - Table caption and summary - -*Rule description:* this rule checks that the table caption and summary does not have the same text content. The caption should explain *what* the table is about while the summary should explain *how* to navigate the data inside of the table. - -[NOTE] -==== -The table `+summary+` attribute was deprecated in HTML 5, both the *what* and *how* information should be moved to the table caption. -==== - -==== {pluginname} rule details - T3 - -Notification level (severity):: Error - -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA - -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 - -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H73.html[H73 - Using the summary attribute of the table element to give an overview of data tables]. - -[[T4A]] -=== T4A - Table markup - -*Rule description:* this rule checks that all `+tables+` contain both `+tr+` and `+td+` elements. - -==== {pluginname} rule details - T4A - -Notification level (severity):: Error - -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA - -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 - -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H51.html[H51 - Using table markup to present tabular information]. - -[[T4B]] -=== T4B - Table headers - -*Rule description:* this rule checks that all `+table+` elements contain at least one table header (`+th+`) element. - -==== {pluginname} rule details - T4B - -Notification level (severity):: Error - -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA - -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 - -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H51.html[H51 - Using table markup to present tabular information]. - -[[T4C]] -=== T4C - Table heading scope - -*Rule description:* this rule checks that all table header (`+th+`) elements have a `+scope+` attribute clarifying what scope the heading has inside of the `+table+`. The allowed values are `+row+`, `+col+`, `+rowgroup+`, and `+colgroup+`. This is important for users of assistive technologies to be able to parse table data. - -==== {pluginname} rule details - T4C - -Notification level (severity):: Error - -https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA - -xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 - -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H63.html[H63 - Using the scope attribute to associate header cells and data cells in data tables]. +''' == Options @@ -347,6 +106,8 @@ The following configuration options affect the behavior of the {pluginname} plug include::partial$configuration/a11y_advanced_options.adoc[leveloffset=+1] +include::partial$configuration/a11ychecker_alt_text_max_length.adoc[leveloffset=+1] + include::partial$configuration/a11ychecker_allow_decorative_images.adoc[leveloffset=+1] include::partial$configuration/a11ychecker_filter_issue.adoc[leveloffset=+1] diff --git a/modules/ROOT/partials/a11y-rules/d1.adoc b/modules/ROOT/partials/a11y-rules/d1.adoc new file mode 100644 index 0000000000..22f0f7715a --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/d1.adoc @@ -0,0 +1,51 @@ +[[D1]] +==== D1 - Usage of paragraphs as headings + +*Rule description:* this rule checks that `+h1+`-`+h6+` tags are used for heading content, not `+p+` tags. Not using correct heading markup will make it difficult for assistive technologies to represent and navigate through your content. + +===== {pluginname} rule details - D1 + +Notification level (severity):: Warning + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: +* https://www.w3.org/WAI/WCAG21/Techniques/html/H42.html[H42 - Using h1-h6 to identify headings]. +* https://www.w3.org/WAI/WCAG21/Techniques/html/H69.html[H69 - Providing heading elements at the beginning of each section of content]. + +.Examples +[%collapsible] +==== +.Non-compliant examples + +[source,html] +---- + +

This looks like a heading

+ + +
Another pseudo heading
+ + +

Not a real heading

+---- + +These examples use non-semantic markup that looks like headings but won't be recognized as such by assistive technologies. + +.Compliant examples + +[source,html] +---- + +

Main page title

+ +

Section heading

+ + +

Subsection heading

+---- + +These examples use proper heading tags that will be correctly interpreted by assistive technologies. +==== \ No newline at end of file diff --git a/modules/ROOT/partials/a11y-rules/d2.adoc b/modules/ROOT/partials/a11y-rules/d2.adoc new file mode 100644 index 0000000000..d0144c0268 --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/d2.adoc @@ -0,0 +1,57 @@ +[[D2]] +==== D2 - Sequential headings + +*Rule description:* this rule checks that heading levels are sequential. Each heading level in a document should follow a logical sequence. That is, you should not skip heading levels (for example, from `+h2+` to `+h4+`). + +===== {pluginname} rule details - D2 + +Notification level (severity):: Error + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/general/G141.html[G141 - Organizing a page using headings]. + +.Examples +[%collapsible] +==== +.Non-compliant examples + +[source,html] +---- + +

Main title

+

Subsection

+ + +

Section

+

Sub-subsection

+ + +

Higher level

+

Lower level

+---- + +These examples show incorrect heading level progression that can confuse users of assistive technologies. + +.Compliant examples + +[source,html] +---- + +

Main title

+

Section

+

Subsection

+

Sub-subsection

+ + +

Main title

+

First section

+

Subsection

+

Second section

+

Another subsection

+---- + +These examples demonstrate proper heading level progression. +==== diff --git a/modules/ROOT/partials/a11y-rules/d3.adoc b/modules/ROOT/partials/a11y-rules/d3.adoc new file mode 100644 index 0000000000..e078c7b38e --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/d3.adoc @@ -0,0 +1,42 @@ +[[D3]] +==== D3 - Adjacent links + +*Rule description:* this rule checks that links next to other links do not have the same `+href+` attribute. + +For example: If an image link and a text link have the same `+href+` attribute, both elements should be in the same `+a+` element. If an image link and a text link point to the same URL but are two separate elements, it can be confusing for users of screen readers and other assistive technologies. + +==== {pluginname} rule details - D3 + +Notification level (severity):: Error + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H2.html[H2 - Combining adjacent image and text links for the same resource]. + +.Examples +[%collapsible] +==== +.Non-compliant example + +[source,html] +---- +
Download +Download User Guide +---- + +This example has two separate links pointing to the same resource. Screen readers will announce these as two different links, which is redundant and potentially confusing. + +.Compliant example + +[source,html] +---- + + + Download User Guide + +---- + +This example combines the image and text into a single link. The image is given an empty alt attribute since the text provides the link's purpose. +==== diff --git a/modules/ROOT/partials/a11y-rules/d4o.adoc b/modules/ROOT/partials/a11y-rules/d4o.adoc new file mode 100644 index 0000000000..9aaae1e653 --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/d4o.adoc @@ -0,0 +1,44 @@ +[[D4O]] +==== D4O - Ordered list structure + +*Rule description:* this rule checks that an `+ol+` element is used for ordered lists. Do not use paragraphs beginning with numbers or roman numerals instead of an `+ol+` element containing `+li+` items. This is to simplify navigation and parsing of the content for users of assistive technologies. + +==== {pluginname} rule details - D4O + +Notification level (severity):: Error + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H48.html[H48 - Using ol, ul and dl for lists or groups of links]. + +.Examples +[%collapsible] +==== +.Non-compliant example + +[source,html] +---- +

1. First prepare the ingredients

+

2. Mix the dry ingredients together

+

3. Add wet ingredients slowly

+

4. Bake at 350°F

+---- + +This example uses paragraphs with manual numbering instead of proper list markup. Screen readers won't recognize this as a list structure. + +.Compliant example + +[source,html] +---- +
    +
  1. First prepare the ingredients
  2. +
  3. Mix the dry ingredients together
  4. +
  5. Add wet ingredients slowly
  6. +
  7. Bake at 350°F
  8. +
+---- + +This example uses proper ordered list markup, allowing screen readers to announce the list structure and item count. +==== diff --git a/modules/ROOT/partials/a11y-rules/d4u.adoc b/modules/ROOT/partials/a11y-rules/d4u.adoc new file mode 100644 index 0000000000..17ee1569df --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/d4u.adoc @@ -0,0 +1,44 @@ +[[D4U]] +==== D4U - Unordered list structure + +*Rule description:* this rule checks that a `+ul+` element is used for unordered lists. Do not use paragraphs beginning with `+*+` or `+-+` or some similar character instead of an `+ol+` element containing `+li+` items. This is to simplify navigation and parsing of the content for users of assistive technologies. + +==== {pluginname} rule details - D4U + +Notification level (severity):: Error + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H48.html[H48 - Using ol, ul and dl for lists or groups of links]. + +.Examples +[%collapsible] +==== +.Non-compliant example + +[source,html] +---- +

• Fresh vegetables

+

• Whole grains

+

- Lean proteins

+

* Healthy fats

+---- + +This example uses paragraphs with bullet characters instead of proper list markup. Screen readers won't recognize this as a list structure. + +.Compliant example + +[source,html] +---- +
    +
  • Fresh vegetables
  • +
  • Whole grains
  • +
  • Lean proteins
  • +
  • Healthy fats
  • +
+---- + +This example uses proper unordered list markup, allowing screen readers to announce it as a list and navigate through items efficiently. +==== diff --git a/modules/ROOT/partials/a11y-rules/d5.adoc b/modules/ROOT/partials/a11y-rules/d5.adoc new file mode 100644 index 0000000000..3e52746c60 --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/d5.adoc @@ -0,0 +1,81 @@ +[[D5]] +==== D5 - Contrast ratio of the text (D5A, D5B, and D5C) + +*Rule description:* this rule checks that the contrast ratio of the text is above the following values: + +* When the compliance level is set to AA, +** 4.5:1 for normal text +** 3:1 for large text +* When the compliance level is set to AAA, +** 7:1 for any text + +Text with a low contrast ratio is hard to read for users with impaired vision. + +[[D5A]] +==== {pluginname} rule details - D5A + +Notification level (severity):: Error + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level AA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/general/G145.html[G145 - Ensuring that a contrast ratio of at least 3:1 exists between text (and images of text) and background behind the text]. + +[[D5B]] +==== {pluginname} rule details - D5B + +Notification level (severity):: Error + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level AA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/general/G18.html[G18 - Ensuring that a contrast ratio of at least 4.5:1 exists between text (and images of text) and background behind the text]. + +[[D5C]] +==== {pluginname} rule details - D5C + +Notification level (severity):: Error + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/general/G17.html[G17 - Ensuring that a contrast ratio of at least 7:1 exists between text (and images of text) and background behind the text]. + +.Examples +[%collapsible] +==== +.Non-compliant examples + +[source,html] +---- + +

This text has insufficient contrast

+ + +

This text is very hard to read

+ + +

Large heading with poor contrast

+---- + +These examples demonstrate text with insufficient contrast ratios that fail WCAG requirements. + +.Compliant examples + +[source,html] +---- + +

This text meets AA standard for normal text

+ + +

This text exceeds AAA requirements

+ + +

Large heading with good contrast

+---- + +These examples meet WCAG contrast requirements for their respective sizes and levels. +==== diff --git a/modules/ROOT/partials/a11y-rules/h93.adoc b/modules/ROOT/partials/a11y-rules/h93.adoc new file mode 100644 index 0000000000..ae1ef70c15 --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/h93.adoc @@ -0,0 +1,60 @@ +[[H93]] +==== H93 - IDs must be unique + +*Rule description:* this rule checks that all `+id+` attributes are unique in the editor. Duplicate `+id+` attributes are known to cause problems for assistive technologies when parsing the content. + +===== {pluginname} rule details - H93 + +Notification level (severity):: Error + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H93.html[H93: Ensuring that id attributes are unique on a Web page]. + +.Examples +[%collapsible] +==== +.Non-compliant examples + +[source,html] +---- + +
First section
+
Second section
+ + + + + + + + + + +---- + +These examples show incorrect use of duplicate IDs that can confuse assistive technologies. + +.Compliant examples + +[source,html] +---- + +
First section
+
Second section
+ + + + + + + + + + +---- + +These examples demonstrate proper use of unique IDs. +==== diff --git a/modules/ROOT/partials/a11y-rules/i1.adoc b/modules/ROOT/partials/a11y-rules/i1.adoc new file mode 100644 index 0000000000..18b4a7242a --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/i1.adoc @@ -0,0 +1,71 @@ +[[I1]] +==== I1 - Conflicting or incomplete image accessibility + +*Rule description:* this rule checks that all images have complete and non-conflicting accessibility information. It flags images that send mixed signals about their purpose (both decorative and informative) or have incomplete accessibility information. When `+a11ychecker_allow_decorative_images+` is `+false+`, this rule also flags decorative images as not allowed. + +===== {pluginname} rule details - I1 + +Notification level (severity):: Error + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/general/G95.html[G95 - Providing short text alternatives that provide a brief description of the non-text content]. + +include::partial$misc/admon-accessibility-rule-i3-can-also-be-applied.adoc[] + +.Examples +[%collapsible] +==== +.Non-compliant examples +[source,html] +---- + +Company Logo + + + + + + + + + + + + + + +Description + + + +---- + +These examples show various accessibility issues: mixed signals, incomplete intent, and decorative images when not allowed. + +.Compliant examples +[source,html] +---- + +Company Logo + + + + + + + + + + + +Sales performance chart +

Detailed breakdown of Q3 sales performance...

+---- + +These examples demonstrate proper accessibility markup with clear intent and ARIA compliance. +==== diff --git a/modules/ROOT/partials/a11y-rules/i2.adoc b/modules/ROOT/partials/a11y-rules/i2.adoc new file mode 100644 index 0000000000..06467ba1a1 --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/i2.adoc @@ -0,0 +1,63 @@ +[[I2]] +==== I2 - Missing `+alt+` attribute + +*Rule description:* this rule checks that all `` elements include an `+alt+` attribute, even if other accessible name properties like `+aria-label+`, `+aria-labelledby+`, or `+title+` are present. The `+alt+` attribute is required for all images, and informative images must have at least one meaningful text alternative. + +===== {pluginname} rule details - I2 + +Notification level (severity):: Error + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/failures/F65.html[F65 - Failure of Success Criterion 1.1.1 due to omitting the alt attribute on `+img+` elements]. + +include::partial$misc/admon-accessibility-rule-i3-can-also-be-applied.adoc[] + +.Examples +[%collapsible] +==== +.Non-compliant examples + +[source,html] +---- + + + + + + + + + + + +---- + +These examples fail because they're missing the required `+alt+` attribute. Note: Images with no attributes at all trigger rule I1 for incomplete intent, not I2. + +.Compliant examples + +[source,html] +---- + +Red coffee mug + + + + + +Sales performance chart +

Detailed breakdown of Q3 sales performance...

+ + +Settings +---- + +These examples all include the required `+alt+` attribute and provide meaningful text alternatives for informative images. +==== \ No newline at end of file diff --git a/modules/ROOT/partials/a11y-rules/i3.adoc b/modules/ROOT/partials/a11y-rules/i3.adoc new file mode 100644 index 0000000000..b7bb2b1446 --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/i3.adoc @@ -0,0 +1,56 @@ +[[I3]] +==== I3 - Filename used as `+alt+` text + +*Rule description:* this rule checks that the `+alt+` attribute does not use a filename (e.g., `+photo.jpg+`) as a substitute for meaningful image description. Filenames like "IMG_1234.jpg" or "photo.png" don't help users understand the image content. + +===== {pluginname} rule details - I3 + +Notification level (severity):: Error + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/general/G95.html[G95 - Providing short text alternatives that provide a brief description of the non-text content]. + +include::partial$misc/admon-accessibility-rule-i3-can-also-be-applied.adoc[] + +.Examples +[%collapsible] +==== +.Non-compliant examples +[source,html] +---- + +sunset.jpg + + +photo + + +DSC_0123.jpg + + +john-smith.png +---- + +These examples use filenames as alt text, which provides no meaningful information about the image content. + +.Compliant examples +[source,html] +---- + +Vibrant orange sunset over ocean waves + + +Team celebrating product launch + + +Students collaborating in the library + + +John Smith, Senior Developer +---- + +These examples use descriptive alt text that explains what the image shows or represents. +==== diff --git a/modules/ROOT/partials/a11y-rules/i4.adoc b/modules/ROOT/partials/a11y-rules/i4.adoc new file mode 100644 index 0000000000..c879925ef7 --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/i4.adoc @@ -0,0 +1,46 @@ +[[I4]] +==== I4 - Overly long `+alt+` text + +*Rule description:* this rule checks for `+alt+` text that exceeds the configured character limit (default: 150 characters). Long descriptions can be difficult for screen reader users to process. Complex images might need detailed descriptions in the surrounding text instead, though some images may require longer descriptions to be fully understood. + +===== {pluginname} rule details - I4 + +Notification level (severity):: Warning + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: N/A + +.Examples +[%collapsible] +==== +.Non-compliant examples +[source,html] +---- +Our modern office space features an open floor plan with collaborative workstations, standing desks, and multiple meeting rooms. The space is brightly lit with natural light from floor-to-ceiling windows, and includes a fully stocked kitchen area, relaxation zone with comfortable seating, and a game room with ping pong tables and video games for employee breaks. + +Bar graph showing monthly sales data for the past year, with blue bars representing domestic sales and red bars representing international sales, demonstrating a steady increase in both markets with particular growth in Q3 and Q4, reaching peak sales in December. +---- + +These examples use overly detailed alt text that may overwhelm screen reader users with too much information at once. + +.Compliant examples +[source,html] +---- +Modern open-plan office with collaborative spaces +

Our office features collaborative workstations, standing desks, and meeting rooms, complemented by natural lighting, a kitchen area, and recreational spaces including a game room.

+ +Monthly sales growth chart for domestic and international markets +

The bar graph shows steady growth in both domestic (blue) and international (red) sales throughout the year, with significant increases in Q3 and Q4, peaking in December.

+---- + +These examples use concise alt text with additional details provided in the surrounding content. +==== diff --git a/modules/ROOT/partials/a11y-rules/t1.adoc b/modules/ROOT/partials/a11y-rules/t1.adoc new file mode 100644 index 0000000000..4f8df561a8 --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/t1.adoc @@ -0,0 +1,80 @@ +[[T1]] +==== T1 - Table caption + +*Rule description:* this rule checks that all `+table+` elements have a `+caption+` element describing the data inside the table to simplify parsing and navigation of the content for users of assistive technologies. + +===== {pluginname} rule details - T1 + +Notification level (severity):: Error + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H39.html[H39 - Using caption elements to associate data table captions with data tables]. + +.Examples +[%collapsible] +==== +.Non-compliant examples + +[source,html] +---- + + + + + + + + + + +
ProductPrice
Widget A$10.00
+ + +

Product Pricing Table

+ + + + + + +
ProductPrice
+---- + +These examples lack proper caption elements, making it harder for screen reader users to understand the table's purpose. + +.Compliant examples + +[source,html] +---- + + + + + + + + + + + +
Product Pricing
ProductPrice
Widget A$10.00
+ + + + + + + + + + + + +
2023 Quarterly Sales by Region (in thousands USD)
RegionQ1Q2Q3Q4
+---- + +These examples include proper caption elements that describe the table's contents and purpose. +==== diff --git a/modules/ROOT/partials/a11y-rules/t2.adoc b/modules/ROOT/partials/a11y-rules/t2.adoc new file mode 100644 index 0000000000..c190a56411 --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/t2.adoc @@ -0,0 +1,83 @@ +[[T2]] +==== T2 - Complex table summary + +*Rule description:* this rule checks that all complex tables must have a `+summary+` attribute explaining to users of assistive technologies how to navigate through the data inside of the table. + +[NOTE] +==== +This rule only applies to HTML 4 content and is not checked when `+a11ychecker_html_version+` is set to `+html5+`. +==== + +===== {pluginname} rule details - T2 + +Notification level (severity):: Warning + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H73.html[H73 - Using the summary attribute of the table element to give an overview of data tables]. + +.Examples +[%collapsible] +==== +.Non-compliant examples + +[source,html] +---- + + + + + + + + + + + + + + + +
Employee Performance Review Scores
DepartmentQ1 2023Q2 2023
AverageRangeAverageRange
+ + + + + +
Employee Performance Review Scores
+---- + +These examples either lack a summary or provide one that doesn't explain the table's structure. + +.Compliant examples + +[source,html] +---- + + + + + + + + + + + + + + + +
Employee Performance Review Scores
DepartmentQ1 2023Q2 2023
AverageRangeAverageRange
+ + + + + +
2023 Product Sales by Month
+---- + +These examples include summaries that explain the table's structure and how to navigate it. +==== diff --git a/modules/ROOT/partials/a11y-rules/t3.adoc b/modules/ROOT/partials/a11y-rules/t3.adoc new file mode 100644 index 0000000000..37a08e396d --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/t3.adoc @@ -0,0 +1,71 @@ +[[T3]] +==== T3 - Table caption and summary + +*Rule description:* this rule checks that the table caption and summary does not have the same text content. The caption should explain *what* the table is about while the summary should explain *how* to navigate the data inside of the table. + +[NOTE] +==== +The table `+summary+` attribute was deprecated in HTML 5, both the *what* and *how* information should be moved to the table caption. +==== + +===== {pluginname} rule details - T3 + +Notification level (severity):: Error + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H73.html[H73 - Using the summary attribute of the table element to give an overview of data tables]. + +.Examples +[%collapsible] +==== +.Non-compliant examples + +[source,html] +---- + + + + +
Quarterly Sales Report 2023
+ + + + + +
Quarterly Sales Report 2023
+ + + + + +
Sales Data 2023
+---- + +These examples show redundant or insufficient information in captions and summaries. + +.Compliant examples + +[source,html] +---- + + + + +
2023 Quarterly Sales by Product Category
+ + + + + +
+ 2023 Quarterly Sales by Product Category + (Data organized with product categories in rows and quarters in columns. + Each cell shows revenue and units sold, with totals in the bottom row) +
+---- + +These examples show proper differentiation between what the table contains and how to navigate it. +==== diff --git a/modules/ROOT/partials/a11y-rules/t4a.adoc b/modules/ROOT/partials/a11y-rules/t4a.adoc new file mode 100644 index 0000000000..e8be7ee1f3 --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/t4a.adoc @@ -0,0 +1,93 @@ +[[T4A]] +==== T4A - Table markup + +*Rule description:* this rule checks that all `+tables+` contain both `+tr+` and `+td+` elements. + +===== {pluginname} rule details - T4A + +Notification level (severity):: Error + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H51.html[H51 - Using table markup to present tabular information]. + +.Examples +[%collapsible] +==== +.Non-compliant examples + +[source,html] +---- + + + Content without rows or cells +
+ + + +
Row 1, Cell 1
+
Row 1, Cell 2
+
Row 2, Cell 1
+
Row 2, Cell 2
+
+ + + +

Header 1

+

Header 2

+

Data 1

+

Data 2

+
+---- + +These examples lack proper table structure with rows and cells, making them inaccessible to screen readers. + +.Compliant examples + +[source,html] +---- + + + + + + + + + + +
Row 1, Cell 1Row 1, Cell 2
Row 2, Cell 1Row 2, Cell 2
+ + + + + + + + + + + +
Header 1Header 2
Data 1Data 2
+ + + + + + + + + + + + + + + +
Column 1Column 2
Data 1Data 2
+---- + +These examples use proper table markup with rows and cells, ensuring accessibility. +==== diff --git a/modules/ROOT/partials/a11y-rules/t4b.adoc b/modules/ROOT/partials/a11y-rules/t4b.adoc new file mode 100644 index 0000000000..1a93b2c608 --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/t4b.adoc @@ -0,0 +1,113 @@ +[[T4B]] +==== T4B - Table headers + +*Rule description:* this rule checks that all `+table+` elements contain at least one table header (`+th+`) element. + +===== {pluginname} rule details - T4B + +Notification level (severity):: Error + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H51.html[H51 - Using table markup to present tabular information]. + +.Examples +[%collapsible] +==== +.Non-compliant examples + +[source,html] +---- + + + + + + + + + + +
ProductPrice
Widget$10.00
+ + + + + + + + + + + +
NamePosition
John SmithDeveloper
+---- + +These examples lack proper header cells, making it difficult for screen readers to understand the table's structure. + +.Compliant examples + +[source,html] +---- + + + + + + + + + + +
ProductPrice
Widget$10.00
+ + + + + + + + + + + + + + + + + + +
QuarterRevenueGrowth
Q1$10,0005%
Q2$15,00050%
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Product20232024
Q1Q2Q1Q2
Widget A100150200250
+---- + +These examples demonstrate proper use of table headers for different levels of complexity. +==== diff --git a/modules/ROOT/partials/a11y-rules/t4c.adoc b/modules/ROOT/partials/a11y-rules/t4c.adoc new file mode 100644 index 0000000000..31e4e33289 --- /dev/null +++ b/modules/ROOT/partials/a11y-rules/t4c.adoc @@ -0,0 +1,97 @@ +[[T4C]] +==== T4C - Table heading scope + +*Rule description:* this rule checks that all table header (`+th+`) elements have a `+scope+` attribute clarifying what scope the heading has inside of the `+table+`. The allowed values are `+row+`, `+col+`, `+rowgroup+`, and `+colgroup+`. This is important for users of assistive technologies to be able to parse table data. + +==== {pluginname} rule details - T4C + +Notification level (severity):: Error + +https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Level AAA + +xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 + +WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H63.html[H63 - Using the scope attribute to associate header cells and data cells in data tables]. + +.Examples +[%collapsible] +==== +.Non-compliant examples +[source,html] +---- + + + + + + + + + + + + +
ProductQ1Q2
Widget A100150
+ + + + + + + + + + + +
NameDepartment
John SmithEngineering
+---- + +These examples either lack scope attributes or use them incorrectly. + +.Compliant examples +[source,html] +---- + + + + + + + + + + + + +
ProductQ1Q2
Widget A100150
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Department20232024
BudgetActualBudgetForecast
Engineering
Development100K95K120K125K
+---- + +These examples demonstrate proper use of scope attributes for different table structures. +==== diff --git a/modules/ROOT/partials/configuration/a11ychecker_allow_decorative_images.adoc b/modules/ROOT/partials/configuration/a11ychecker_allow_decorative_images.adoc index 1273b98df0..c669276576 100644 --- a/modules/ROOT/partials/configuration/a11ychecker_allow_decorative_images.adoc +++ b/modules/ROOT/partials/configuration/a11ychecker_allow_decorative_images.adoc @@ -1,23 +1,45 @@ [[a11ychecker_allow_decorative_images]] == `+a11ychecker_allow_decorative_images+` -This option sets whether the Accessibility Checker should allow decorative images. When this option is set to `+true+`, a decorative image must have *both*: +This option determines whether the Accessibility Checker should allow decorative images. Decorative images are those that are used purely for visual enhancement and do not convey meaningful content or serve a specific function. -* An empty alternative text attribute. -* The `+role="presentation"+` attribute. +When this option is set to `+true+`, decorative images must have *both*: -For example: +* An empty alternative text attribute (`+alt=""+`). +* and the `+role="presentation"+` attribute. + +This combination explicitly tells assistive technologies to ignore these images, improving the browsing experience for users of screen readers. + +=== Common Use Cases for Decorative Images + +* Background patterns or textures +* Aesthetic borders or dividers +* Purely decorative icons that repeat nearby text +* Images that are described by adjacent text content +* Spacer images used for layout purposes + +=== Example of a Decorative Image: + +[source,html] +---- + +---- + +=== Example of an Informative Image (non-decorative): [source,html] ---- - +Company Name Logo ---- +=== Validation Rules + If `+a11ychecker_allow_decorative_images+` is set to `+true+`, the Accessibility Checker will present an error when: * An image does not have the alternative text attribute (`+alt+`). -* An image has an empty alternative text attribute, but is missing the `+role="presentation"+` attribute. +* An image has an empty alternative text attribute but is missing the `+role="presentation"+` attribute. * An image has alternative text and a conflicting `+role="presentation"+` attribute. +* A potentially meaningful image (like a logo or chart) is marked as decorative. If `+a11ychecker_allow_decorative_images+` is set to `+false+`, the Accessibility Checker will present an error when: @@ -32,7 +54,7 @@ If `+a11ychecker_allow_decorative_images+` is not explicitly set, the value defi *Type:* `+Boolean+` -*Default value:* `+false+` +*Default value:* `+true+` *Possible values:* `+true+`, `+false+` diff --git a/modules/ROOT/partials/configuration/a11ychecker_alt_text_max_length.adoc b/modules/ROOT/partials/configuration/a11ychecker_alt_text_max_length.adoc new file mode 100644 index 0000000000..4b27820e55 --- /dev/null +++ b/modules/ROOT/partials/configuration/a11ychecker_alt_text_max_length.adoc @@ -0,0 +1,20 @@ +[[a11ychecker_alt_text_max_length]] +== `+a11ychecker_alt_text_max_length+` + +This option sets the maximum length for image alternative text before triggering a warning. + +*Type:* `+Number+` + +*Default value:* `+150+` + +*Example:* + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'a11ychecker', + toolbar: 'a11ycheck', + a11ychecker_alt_text_max_length: 200 // Allow longer descriptions if needed +}); +---- From c9d4fa2aaa578fc581abdabad32b009b58bfbb8f Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 11:03:26 +1000 Subject: [PATCH 17/60] DOC-3231: Refactor documentation for server-side components to support Docker deployment. (#3757) * DOC-3231: Refactor documentation for server-side components to support Docker deployment - Removed the deprecated logging services configuration documentation. - Updated references from WAR file deployment to Docker container deployment across multiple documents. - Revised installation and configuration instructions for spellchecking, image proxy, and media embed services to reflect Docker usage. - Added new sections for Docker image retrieval, configuration, and requirements. - Clarified system requirements and troubleshooting steps for Dockerized services. - Adjusted custom dictionaries and Hunspell dictionaries path requirements to remove references to Java services. - Updated supported application servers section to emphasize Docker as the primary deployment method. * DOC-3231: Remove deprecated server-side component installation documentation duplication page. * File cleanup, removal of files not used during copy edits. * Update modules/ROOT/partials/misc/custom-dictionaries-path.adoc Co-authored-by: Tim Dettrick * Update modules/ROOT/partials/misc/hunspell-dictionaries-path.adoc Co-authored-by: Tim Dettrick * Update modules/ROOT/partials/misc/supported-application-servers.adoc Co-authored-by: Tim Dettrick * Update modules/ROOT/pages/support.adoc Co-authored-by: Tim Dettrick * Update modules/ROOT/pages/support.adoc Co-authored-by: Tim Dettrick * Update modules/ROOT/partials/misc/supported-application-servers.adoc --------- Co-authored-by: Tim Dettrick --- modules/ROOT/nav.adoc | 2 - modules/ROOT/pages/8.0-release-notes.adoc | 17 +- .../pages/configure-logging-services.adoc | 45 ---- .../pages/introduction-to-mediaembed.adoc | 2 +- ...uction-to-premium-selfhosted-services.adoc | 243 ------------------ .../introduction-to-tiny-spellchecker.adoc | 2 +- .../ROOT/pages/mediaembed-server-config.adoc | 2 +- modules/ROOT/pages/support.adoc | 26 +- modules/ROOT/pages/troubleshoot-server.adoc | 79 ++---- .../autocorrect_service_url.adoc | 4 +- .../image_proxy_service_url.adoc | 2 +- .../configuration/mediaembed_service_url.adoc | 2 +- .../configuration/spellchecker_rpc_url.adoc | 4 +- .../misc/custom-dictionaries-path.adoc | 2 +- .../misc/hunspell-dictionaries-path.adoc | 2 +- .../misc/supported-application-servers.adoc | 20 +- 16 files changed, 78 insertions(+), 376 deletions(-) delete mode 100644 modules/ROOT/pages/configure-logging-services.adoc delete mode 100644 modules/ROOT/pages/introduction-to-premium-selfhosted-services.adoc diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc index 04ebfa9fe1..9d5dd4006f 100644 --- a/modules/ROOT/nav.adoc +++ b/modules/ROOT/nav.adoc @@ -140,8 +140,6 @@ **** xref:configure-imageproxy-service.adoc[Image Proxy service settings] **** xref:configure-spelling-service.adoc[Spelling service settings] **** xref:self-hosting-hunspell.adoc[Spelling service - Using Hunspell dictionaries] -**** xref:configure-logging-services.adoc[Activity logging] -*** xref:introduction-to-premium-selfhosted-services.adoc[Server-side component installation without Docker] *** xref:troubleshoot-server.adoc[Troubleshoot server-side components] ** Customizing the editor appearance *** xref:customize-ui.adoc[Customizing the UI] diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index b4759ac0ee..7f682f1b97 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -283,7 +283,22 @@ The fix ensures that the `s` element is now properly nested inside the font size [[deprecated]] == Deprecated -{productname} {release-version} includes the following deprecation: +{productname} {release-version} includes the following deprecations: + +=== Java application server-based server components have been deprecated +// #DOC-3231 + +{productname} {release-version} deprecates the Java application server-based deployment method for self-hosted services. Docker containers are now the **only** supported deployment method for self-hosted services. The Java `.war` files (`ephox-spelling.war`, `ephox-image-proxy.war`, `ephox-hyperlinking.war`) will be removed in a future release. + +For information about setting up containerized server-side components using Docker containers, see: xref:bundle-intro-setup.adoc[Introduction and initial setup for containerized server-side services from the premium self-hosted bundles] + +=== Docker container services + +* Enhanced Media Embed and Link Checker service, see: xref:individual-hyperlinking-container.adoc[Deploy the {productname} hyperlinking server-side component using Docker]. +* Image Editing and Export image proxy service, see: xref:individual-image-proxy-container.adoc[Deploy the {productname} image proxy server-side component using Docker]. +* Spell Checker service, see: xref:individual-spelling-container.adoc[Deploy the {productname} spelling service server-side component using Docker]. +* Export to PDF service, see: xref:individual-export-to-pdf-on-premises.adoc[Deploy the {productname} Export to PDF service server-side component using Docker]. +* Import from Word and Export to Word services, see: xref:individual-import-from-word-and-export-to-word-on-premises.adoc[Deploy the {productname} Import from Word and Export to Word service server-side component using Docker]. // === The `` configuration property, ``, has been deprecated // #TINY-vwxyz1 diff --git a/modules/ROOT/pages/configure-logging-services.adoc b/modules/ROOT/pages/configure-logging-services.adoc deleted file mode 100644 index 2722f9807e..0000000000 --- a/modules/ROOT/pages/configure-logging-services.adoc +++ /dev/null @@ -1,45 +0,0 @@ -= Activity logging -:description: Setting up logging for the premium server-side components. - -It may be useful to make the {productname} server-side components write to their own log file. This can assist in troubleshooting and make it easier to provide logs as part of a support ticket. - -The {productname} server-side components use the http://logback.qos.ch/manual/configuration.html[Logback] logging format. - -To write the logs to a specific file: - -. Create a logging configuration XML file. Save the snippet below as `+logback.xml+` after replacing `+{$LOG_LOCATION}+` with the full path to the destination log file (e.g. /var/log/tinymce_server_components.log). -+ -[source,xml,subs="attributes+"] ----- - - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger\{36} - %msg%n - - - - - {$LOG_LOCATION} - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger\{36} - %msg%n - - - - - - - - - - - - - ----- -. Pass the configuration file to the Java application server. Assuming you've saved your `+logback.xml+` file in `+/etc/opt/tinymce+`, follow xref:introduction-to-premium-selfhosted-services.adoc#pass-the-configuration-file-to-the-java-application-server[step 4] and xref:introduction-to-premium-selfhosted-services.adoc#restart-the-java-application-server[step 5] on the _Install Server-side Components_ page to set the following JVM system property on your Java application server: -+ -.... --Dlogback.configurationFile=/etc/opt/tinymce/logback.xml -.... diff --git a/modules/ROOT/pages/introduction-to-mediaembed.adoc b/modules/ROOT/pages/introduction-to-mediaembed.adoc index a24671abd3..2e2b0c8af8 100644 --- a/modules/ROOT/pages/introduction-to-mediaembed.adoc +++ b/modules/ROOT/pages/introduction-to-mediaembed.adoc @@ -73,4 +73,4 @@ include::partial$configuration/mediaembed_max_width.adoc[leveloffset=+1] == Downloading Enhanced Media Embed plugin -A link:{pricingpage}/[{enterpriseversion} subscription] includes the ability to download and install the *Media Embed* plugin and a *WAR* file to access the service backend. Please follow these xref:introduction-to-premium-selfhosted-services.adoc#set-up-editor-client-instances-to-use-the-server-side-functionality[instructions] to configure the *WAR* file. +A link:{pricingpage}/[{enterpriseversion} subscription] includes the ability to pull down the Docker image for the *Media Embed* plugin. For more information on how to deploy the *Media Embed* plugin, please see the xref:individual-hyperlinking-container.adoc[Deploy the {productname} hyperlinking server-side component using Docker] guide. diff --git a/modules/ROOT/pages/introduction-to-premium-selfhosted-services.adoc b/modules/ROOT/pages/introduction-to-premium-selfhosted-services.adoc deleted file mode 100644 index 7d02b98d05..0000000000 --- a/modules/ROOT/pages/introduction-to-premium-selfhosted-services.adoc +++ /dev/null @@ -1,243 +0,0 @@ -= Server-side component installation -:description: Server-side components for premium plugins like spelling as-you-type. -:keywords: enterprise, tinymcespellchecker, spell check, Spell Checker, editimage, server - -Some {productname} Enterprise features require a server-side component. If you're using the {cloudname} solution, we've done all the hard work for you and you can skip this page. Alternatively, if you've purchased our Self-hosted solution then please read on. - -Server-side components must be deployed onto a Java Servlet 3.0 compatible application server. We currently support Jetty, Apache Tomcat, and WebSphere Application Server. To discuss support for additional Java application servers, please contact us at mailto:sales@tiny.cloud[sales@tiny.cloud] - -The following server-side components are included in the {productname} Self-hosted package: - -[cols="<,<,<",options="header"] -|=== -|Component |File |Description -|xref:introduction-to-tiny-spellchecker.adoc[Spellchecking], xref:autocorrect.adoc[Spelling Autocorrect] |ephox-spelling.war |Spell checking and Autocorrect service for {productname} Enterprise. -|xref:editimage.adoc[Image Editing] |ephox-image-proxy.war |Image proxy service for the Export and Image Editing plugins. -|xref:introduction-to-mediaembed.adoc[Enhanced Media Embed], xref:linkchecker.adoc[Link Checker] |ephox-hyperlinking.war |Link Checker and Enhanced Media Embed service for {productname} Enterprise. -|=== - -NOTE: The "Allowed Origins" service (ephox-allowed-origins.war) has been deprecated. Trusted domains should now be specified directly in the configuration file. - -This guide will help you get these server-side components up and running. - -[[install-a-java-application-server]] -== Step 1. Install a Java application server - -If you've already got a Java application server like Jetty or Tomcat installed, skip to Step 2. - -If you don't, pick either http://tomcat.apache.org/[Tomcat] or https://www.eclipse.org/jetty/[Jetty] and install one of these with their default settings using the instructions on their website. - -[IMPORTANT] -.Memory requirement -==== -Please ensure that you configure your Java Server (Tomcat/Jetty etc) with a minimum of 4GB. Please refer to xref:troubleshoot-server.adoc#out-of-memory-errors[Out of memory errors] section of the Troubleshoot page if you require instructions on how to explicitly define how much RAM will be allocated to your Java server. -==== - -[[deploy-server-side-components]] -== Step 2. Deploy server-side components - -Deploy all the WAR files that came packaged with the {productname} Enterprise Self-hosted package to your newly installed application server: - -* `ephox-spelling.war` -* `ephox-image-proxy.war` -* `ephox-hyperlinking.war` - -The easiest way to deploy these files is to copy them into the _webapps_ directory of your Tomcat/Jetty installation and then restart the application server. - -IMPORTANT: Tomcat 10 will require the applications to be placed in the _webapps-javaee_ directory. Once placed there they will be converted by Tomcat to the Jakarta servlet framework. https://tomcat.apache.org/migration-10.html#Specification_APIs[Tomcat 10 Migration guide] - -More information can be found in the documentation of your chosen application server: - -* https://tomcat.apache.org/tomcat-9.0-doc/deployer-howto.html[Deploying applications with Tomcat 9.0] -* https://www.eclipse.org/jetty/documentation/current/#configuring-deployment[Deploying applications with Jetty] - -[[create-a-configuration-file]] -== Step 3. Create a configuration file - -Refer to the xref:configure-required-services.adoc[Configure] page for the details and come back here when you're done. - -[[pass-the-configuration-file-to-the-java-application-server]] -== Step 4. Pass the configuration file to the Java application server - -[IMPORTANT] -.HTTP proxy -==== -If you are relying on an HTTP proxy for outgoing HTTP/HTTPS connections to the Internet, consider configuring use of the proxy by the application server by setting JVM system properties at this point. These can be set in the same manner as `+ephox.config.file+` using the instructions below (using the `+-D+` option to the `+java+` command). Please refer to http://docs.oracle.com/javase/8/docs/api/java/net/doc-files/net-properties.html[Networking Properties for Java] for details on the relevant proxy system properties. The system properties `+http.proxyHost+`, `+http.proxyPort+`, `+http.nonProxyHosts+`, `+https.proxyHost+`, `+https.proxyPort+` are recognized as well as `+http.proxyUser+` and `+http.proxyPassword+` to support authenticating proxies. Alternatively, use of a proxy for server-side components can be set directly in their configuration file as discussed on the xref:configure-common-settings-services.adoc#proxy[Configure] page. -==== - -Tell the services about the configuration file by setting the `+ephox.config.file+` JVM system property to the absolute path of the configuration file. The exact method for doing this varies depending on your operating system, application server and whether the application server is being run as a system service. The authoritative reference for configuring any application server is the vendor documentation, but we'll do our best to get you started below. - -=== Windows - -All Windows examples will assume the name of your configuration file is `+application.conf+` and it is located in the directory `+C:\config\file\location\+`. You'll need to set the JVM system property `+-Dephox.config.file=C:\config\file\location\application.conf+`. - -==== Tomcat - -===== From the command line - -The following assumes you've downloaded the Tomcat 9.0 zip archive from the Tomcat website, unpacked it and you're working from the unpacked Tomcat directory. - -Create or edit the script `+.\bin\setenv.bat+` to contain the following line: - -[source,bat] ----- -set "CATALINA_OPTS= -Dephox.config.file=C:\config\file\location\application.conf" ----- - -There should only be a single line in this file defining the `+CATALINA_OPTS+` environment variable. - -You may also need to add another line with the path to your Java Runtime Environment installation (replace with the actual path on your system) such as: - -[source,bat] ----- -set "JRE_HOME=C:\Program Files\Java\jre1.8.0_131" ----- - -After editing `+setenv.bat+`, run the following command to start Tomcat: - -[source,sh] ----- -.\bin\startup.bat ----- - -For further information see the documentation on https://tomcat.apache.org/tomcat-9.0-doc/RUNNING.txt[running Tomcat 9.0]. - -===== As a Windows service - -If you download the Windows installer, Tomcat 9.0 will always be installed as a Windows system service. See the notes on https://tomcat.apache.org/tomcat-9.0-doc/setup.html#Windows[Windows setup] for Tomcat 9.0 and the instructions for setting JVM system properties in the https://tomcat.apache.org/tomcat-9.0-doc/windows-service-howto.html[Tomcat 9.0 Windows Service HOW-TO]. - -As a minimal example, if the installer installed Tomcat to `+C:\Program Files\Apache Software Foundation\Tomcat 9.0\+` (default option): - -* Run `+C:\Program Files\Apache Software Foundation\Tomcat 9.0\bin\Tomcat9w+` which opens the *Apache Tomcat 9.0 Tomcat9 Properties* dialog box -* Select the `+Java+` tab -* Add the following line to `+Java Options+`: -+ -[source] ----- --Dephox.config.file=C:\config\file\location\application.conf ----- - -For other versions of Tomcat on Windows, check the Tomcat documentation for that version. - -==== Jetty - -===== From the command line - -If you're following the instructions for https://www.eclipse.org/jetty/documentation/current/#quickstart-running-jetty[Starting Jetty] for Jetty 9.4.5, the path to the configuration file can simply be supplied as a command option: - -[source,sh] ----- -java -D"ephox.config.file=C:\config\file\location\application.conf" -jar C:\jetty\install\directory\start.jar ----- - -For other versions of Jetty on Windows, check the Jetty documentation for that version. - -===== As a Windows service - -Follow the instructions in https://www.eclipse.org/jetty/documentation/current/#startup-windows-service[Startup via Windows Service] for Jetty 9.4.5. Remember to append the following snippet to the line beginning with `+set PR_JVMOPTIONS+` in your `+install-jetty-service.bat+` script: - -[source,bat] ----- -;-Dephox.config.file="C:\config\file\location\application.conf" ----- - -NOTE: Check the `+install-jetty-service.bat+` has the correct paths to your Java installation. The service will fail to start with some rather unhelpful errors if the paths are incorrect. - -For other versions of Jetty on Windows, check the Jetty documentation for that version. - -=== Linux - -All Linux examples will assume the name of your configuration file is `+application.conf+` and it is located in the directory `+/config/file/location/+`. You'll need to set the JVM system property `+-Dephox.config.file=/config/file/location/application.conf+`. - -NOTE: If the path to your `+application.conf+` file has spaces in it, you must ensure you prefix each white space with an escape character (\). Example: `+-Dephox.config.file=/config/file/location/with/white\ space/application.conf+` - -Tomcat and/or Jetty can be obtained via the package manager for many Linux distributions. The commands for starting the service and the location of the configuration files will vary across distributions. If you installed an application server via the package manager, follow your distribution's documentation for configuring it. - -==== Tomcat - -The following assumes you've downloaded Tomcat 9.0 from the Tomcat website and unpacked the archive to `+/opt/tomcat+`. - -For other versions of Tomcat on Linux, check the Tomcat documentation for that version. - -If you've obtained Tomcat from your distribution's package manager, refer to your distribution's documentation for Tomcat. - -===== From the command line - -Create or edit the script `+/opt/tomcat/bin/setenv.sh+` to contain the following line: - -[source,sh] ----- -CATALINA_OPTS=" -Dephox.config.file=/config/file/location/application.conf" ----- - -There should only be a single line in this file defining the `+CATALINA_OPTS+` environment variable. - -After editing `+setenv.sh+`, run the following command to start Tomcat: - -[source,sh] ----- -/opt/tomcat/bin/startup.sh ----- - -For further information see the documentation on https://tomcat.apache.org/tomcat-9.0-doc/RUNNING.txt[running Tomcat 9.0]. - -==== Jetty - -The following assumes you've downloaded Jetty 9.4.5 from the Jetty website and unpacked the archive to `+/opt/jetty+`. - -For other versions of Jetty on Linux, check the Jetty documentation for that version. - -If you've obtained Jetty from your distribution's package manager, refer to your distribution's documentation for Jetty. - -===== From the command line - -The path to the configuration file can simply be supplied as a command option: - -[source,sh] ----- -java -Dephox.config.file="/config/file/location/application.conf" -jar /opt/jetty/start.jar ----- - -===== As a Linux service - -Assuming you've followed the instructions to https://www.eclipse.org/jetty/documentation/current/#startup-unix-service[Startup a Unix Service using jetty.sh] for Jetty 9.4.5, edit `+/etc/default/jetty+` and add the line: - -[source] ----- -JETTY_ARGS=" -Dephox.config.file=/config/file/location/application.conf" ----- - -There should only be a single line in this file defining the `+JETTY_ARGS+` variable. - -[[restart-the-java-application-server]] -== Step 5: Restart the Java application server - -After you've completed the steps on this page to xref:deploy-server-side-components[Deploy server-side components], xref:create-a-configuration-file[Create a configuration file] and xref:pass-the-configuration-file-to-the-java-application-server[Pass the configuration file to the Java application server], the application server may need to be restarted to pick up all your changes. Turn it off and on again now, just to be safe. - -[[set-up-editor-client-instances-to-use-the-server-side-functionality]] -== Step 6: Set up editor client instances to use the server-side functionality - -Now that the server-side components deployed and running, you'll need to tell your {productname} instances where to find them: - -* Set the {productname} `+spellchecker_rpc_url+` configuration property to the URL of the deployed server-side spelling component. -* Set the {productname} `+editimage_proxy_service_url+` and `+export_image_proxy_service_url+` configuration properties to the URL of the deployed server-side image proxy component. -* Set the {productname} `+mediaembed_service_url+` and `+linkchecker_service_url+` configuration properties to the URL of the deployed server-side linkchecker and media embed component. - -This example assume your Java application server is running on port 80 (http) on `+yourserver.example.com+` and that all the server-side components are deployed to the same Java application server. Replace `+yourserver.example.com+` with the actual domain name or IP address of your server. - -Example of {productname} client configuration: - -[source,js] ----- -tinymce.init({ - selector: 'textarea', // change this value according to your HTML - toolbar: 'image', - plugins: 'tinymcespellchecker image editimage media mediaembed', - spellchecker_rpc_url: 'http://yourserver.example.com/ephox-spelling/', - autocorrect_service_url: 'http://yourserver.example.com/ephox-spelling/', - editimage_proxy_service_url: 'http://yourserver.example.com/ephox-image-proxy/', - export_image_proxy_service_url: 'http://yourserver.example.com/ephox-image-proxy/', - mediaembed_service_url: 'http://yourserver.example.com/ephox-hyperlinking/', - linkchecker_service_url: 'http://yourserver.example.com/ephox-hyperlinking/' -}); ----- diff --git a/modules/ROOT/pages/introduction-to-tiny-spellchecker.adoc b/modules/ROOT/pages/introduction-to-tiny-spellchecker.adoc index c81e00a4bf..570c7498fd 100644 --- a/modules/ROOT/pages/introduction-to-tiny-spellchecker.adoc +++ b/modules/ROOT/pages/introduction-to-tiny-spellchecker.adoc @@ -37,7 +37,7 @@ tinymce.init({ To enable the {productname} Enterprise Spellchecking plugin, add `+tinymcespellchecker+` to the `+plugins+` list. -For information on installing the server-side component for spell checking, please see the xref:introduction-to-premium-selfhosted-services.adoc[server-side component installation guide]. +For information on installing the server-side component for spell checking, please see the xref:individual-spelling-container.adoc[Deploy the {productname} spelling service server-side component using Docker]. === Example: TinyMCE Self-hosted Installation diff --git a/modules/ROOT/pages/mediaembed-server-config.adoc b/modules/ROOT/pages/mediaembed-server-config.adoc index 8098f3b665..34b0da8f54 100644 --- a/modules/ROOT/pages/mediaembed-server-config.adoc +++ b/modules/ROOT/pages/mediaembed-server-config.adoc @@ -2,7 +2,7 @@ :description: Instructions for getting the Enhanced Media Embed server configured. :keywords: enterprise, pricing, video, youtube, vimeo, mp3, mp4, mov, movie, clip, film, link, linkchecking, linkchecker, mediaembed, media -Once you have the xref:introduction-to-premium-selfhosted-services.adoc[server-side component] installed, additional configuration to your `+application.conf+` file is required. (Don't forget to restart the Java application server after updating the configuration.) +Once you have the xref:individual-hyperlinking-container.adoc[Deploy the {productname} hyperlinking server-side component using Docker] installed, additional configuration to your `+application.conf+` file is required. (Don't forget to restart the Docker container after updating the configuration.) The Enhanced Media Embed service allows you to choose between using your own https://iframely.com/[Iframely] account, configuring custom http://oembed.com/[oEmbed] endpoints or using a combination of both. diff --git a/modules/ROOT/pages/support.adoc b/modules/ROOT/pages/support.adoc index e6c5e79206..88b0b3631d 100644 --- a/modules/ROOT/pages/support.adoc +++ b/modules/ROOT/pages/support.adoc @@ -32,16 +32,24 @@ include::partial$misc/plugin-support-table.adoc[leveloffset=+1] include::partial$misc/support-powerpaste.adoc[leveloffset=+1] -=== Supported Application Servers: Self-hosted Enterprise +=== System Requirements: Self-hosted Enterprise -The {productname} spell checking server-side component requires a Java Web Application Server that supports Servlet Implementation API 3.0. +The {productname} server-side components are delivered as Docker/OCI container images. The following requirements must be met: -Java Development Kit:: -* JDK 8 -Java (J2EE) Application Servers:: -include::partial$misc/supported-application-servers.adoc[] - -Minimum Hardware Requirements:: -* CPU: Dual Core Processor ~ 2Ghz. For higher loads, a quad core or higher is recommended. +Host System Requirements:: +* Operating System: +** Linux +** macOS +** Windows with WSL 2 +* CPU: Dual Core Processor ~ 2Ghz. For higher loads, a quad core or higher is recommended * RAM: 4 Gigabytes of RAM available for services +* Storage: At least 10GB of free disk space for container images and data + +Container Platform Support:: +* Docker standalone +* Container orchestration platforms (such as Kubernetes) +* Cloud container services + +[NOTE] +For production deployments, we recommend using container orchestration platforms or cloud container services that provide built-in scaling and monitoring capabilities. diff --git a/modules/ROOT/pages/troubleshoot-server.adoc b/modules/ROOT/pages/troubleshoot-server.adoc index 973197b1d9..81fc806924 100644 --- a/modules/ROOT/pages/troubleshoot-server.adoc +++ b/modules/ROOT/pages/troubleshoot-server.adoc @@ -4,17 +4,21 @@ == General troubleshooting advice -. Verify that that your JavaScript configuration is correct for the relevant {productname} plugin. -. Ensure that your firewall has the appropriate ports and rules configured correctly. Be sure that the server the service is running on is accessible from the browser via the port specified in the server configuration -. Check the logs of your Java server for information. When making changes to the configuration you will need to restart the application server each time a change is made for that change to take effect. Refresh your browser window and then try the service again. +. Verify that your JavaScript configuration is correct for the relevant {productname} plugin. +. Ensure that your firewall has the appropriate ports and rules configured correctly. Be sure Docker containers are accessible from the browser via the port specified in the container configuration. +. Check the Docker container logs for information using `docker logs `. When making configuration changes, you will need to restart the containers for changes to take effect. Refresh your browser window and try the service again. == Debug server configuration If a service does not appear to be working, this is generally caused by one of the following reasons. This guide will walk you through the debugging process to identify the specific problem and how to remedy the issue. -. The `+application.conf+` file is incorrect. Please go back and follow the steps listed in the xref:introduction-to-premium-selfhosted-services.adoc#create-a-configuration-file[installation guide]. This is the most common problem - often the origins are specified without the port numbers and this can cause things to fail, eg: use `+http://localhost:8080+` instead of `+http://localhost+`. After making changes to the `+application.conf+` file, please restart your Java web server (e.g. Jetty or Tomcat). -. The `+application.conf+` file is correct, but something is wrong with one of the services. See the section below to debug the services. -. The `+application.conf+` file is correct, and the services are working, but the server-side component URLs that the editor uses are not quite right. Refer to the xref:introduction-to-tiny-spellchecker.adoc[Spell Checker], xref:editimage.adoc[Image Editing], xref:introduction-to-mediaembed.adoc[Enhanced Media Embed] and xref:linkchecker.adoc[Link Checker] plugin pages for help. +. The `+application.conf+` configuration file is incorrect. Please go back and follow the steps listed in the individual service setup guides: +* xref:individual-spelling-container.adoc[Spelling service configuration] +* xref:individual-image-proxy-container.adoc[Image Proxy service configuration] +* xref:individual-hyperlinking-container.adoc[Hyperlinking service configuration] +This is most commonly due to incorrect origin configuration - make sure to include port numbers (e.g., use `+http://localhost:8080+` instead of `+http://localhost+`). After making configuration changes, restart the Docker containers. +. The configuration is correct, but one of the services is not responding properly. See the section below to debug the services. +. The services are working, but the component URLs that the editor uses are not quite right. Refer to the xref:introduction-to-tiny-spellchecker.adoc[Spell Checker], xref:editimage.adoc[Image Editing], xref:introduction-to-mediaembed.adoc[Enhanced Media Embed] and xref:linkchecker.adoc[Link Checker] plugin pages for help. . The browser is sending a different origin than expected (and configured in `+application.conf+`). Refer to step 6 of xref:using-browser-tooling-to-investigate-services-issues[Using browser tooling to investigate services issues] == Browser-specific issues @@ -42,73 +46,46 @@ If the server is not running on a standard HTTP or HTTPS port (80 or 443) then C image::spell-checking-browser-tools.png[Using browser tools to investigate services issues] -NOTE: The value of the Origin header sent by the must match the origin specified in the `+application.conf+` server configuration. If it does not match, you must make the server configuration match the browser. +NOTE: The value of the Origin header sent by the browser must match the origin specified in the `+application.conf+` for your Docker container configuration. If it does not match, you must update your container configuration to match the browser. == Windows Server specific issues Sometimes the Origin header is never sent to the services, which results in the editor and services not working as intended. Refer to step 6 of xref:using-browser-tooling-to-investigate-services-issues[Using browser tooling to investigate services issues] and determine what the origin is - if you do not see an Origin header at all, please do the following: . Try accessing the editor web page using your machine's fully qualified domain name (FQDN) and keep the network tools open so you can see if the Origin header is sent back to the services. For example, if you have been testing on port 8080 on your local machine and the editor is instantiated on a page with path `+tinymce/index.html+`, navigate to `+http://myserver.example.com:8080/tinymce/index.html+` rather than `+http://localhost:8080/tinymce/index.html+`. -. If you now see an Origin header being sent across, alter your `+application.conf+` and replace all instances of 'localhost' with the domain name of your machine. -. Restart the Tomcat / Jetty service. +. If you now see an Origin header being sent across, update your Docker container `+application.conf+` to replace all instances of 'localhost' with the domain name of your machine. +. Restart the Docker containers. . Reload the browser page and all should work well. -[[out-of-memory-errors]] -== Out of memory errors +[[container-troubleshooting]] +== Container Troubleshooting -=== The Java application server throws "Out of Memory" errors +=== Debugging Service Issues -Even though you may have a large amount of RAM available, the Java Virtual Machine doesn't get to see all of that - by default it is limited to only 256Mb. +If you encounter issues with the containerized services: -For example, if you are using Tomcat, you can view how much memory is being consumed by apps. To do this you need to have the management console enabled. - -On a vanilla install this is done by editing the file /tomcat/install/directory/conf/tomcat-users.xml adding these lines in: - -[source,xml] +. Check the container status: ++ +[source,sh] ---- - - +docker ps ---- -Then, restart the server and go to a browser and open the default tomcat page `+http://localhost:8080+`. On the top right hand side are three buttons, the first of which should be "Server Status". Click that link, login with the details you set above and you should be able to see the memory consumption (see the figure below for an example). - -image::spell-checking-server-status.png[Spell Checking Server Status] - -=== To increase the amount of memory - -==== Tomcat - -Edit the setenv.sh (Unix) or setenv.bat (Windows) to read as follows: - -On Windows, please prefix each line with 'set' and remove the quotes . So the configuration would look like: - +. View service logs for errors or warnings: ++ [source,sh] ---- -set CATALINA_OPTS= -Dephox.config.file=/config/file/location/application.conf -set JAVA_OPTS= -Xms2048m -Xmx2048m -XX:PermSize=64m -XX:MaxPermSize=512m -Dfile.encoding=utf-8 -Djava.awt.headless=true -XX:+UseParallelGC -XX:MaxGCPauseMillis=100 - -CATALINA_OPTS=" -Dephox.config.file=/config/file/location/application.conf" -JAVA_OPTS=" -Xms2048m -Xmx2048m -XX:PermSize=64m -XX:MaxPermSize=512m -Dfile.encoding=utf-8 -Djava.awt.headless=true -XX:+UseParallelGC -XX:MaxGCPauseMillis=100" +docker logs ---- -==== Jetty - -Edit the start.ini file to read as follows: - +. For persistent issues, collect logs for support: ++ [source,sh] ---- -#=========================================================== -# Jetty start.jar arguments -# Each line of this file is prepended to the command line -# arguments # of a call to: -# java -jar start.jar [arg...] -#=========================================================== --Xms2048m -Xmx2048m -XX:PermSize=64m -XX:MaxPermSize=512m -Dephox.config.file=/config/file/location/application.conf +docker logs > service-logs.txt ---- -Restart the service and confirm the settings have been applied like so: - -image::spell-checking-jetty-settings.png[Spell Checking Server Settings on Jetty] +TIP: When contacting support, include the service logs and details about your deployment configuration to help diagnose the issue. == Troubleshooting tools: curl diff --git a/modules/ROOT/partials/configuration/autocorrect_service_url.adoc b/modules/ROOT/partials/configuration/autocorrect_service_url.adoc index 3af2c91102..bf730be43f 100644 --- a/modules/ROOT/partials/configuration/autocorrect_service_url.adoc +++ b/modules/ROOT/partials/configuration/autocorrect_service_url.adoc @@ -3,7 +3,7 @@ This option specifies the URL of the server-side `+ephox-spelling+` service. -For instructions on how to set up a Spellchecking server-side component, see: the xref:introduction-to-premium-selfhosted-services.adoc[server-side component installation guide]. +For instructions on how to set up a Spellchecking server-side component, see: the xref:individual-spelling-container.adoc[Deploy the {productname} spelling service server-side component using Docker]. NOTE: `autocorrect_service_url` is *not* required when enabling this plugin via xref:editor-and-features.adoc[{cloudname}]. @@ -17,4 +17,4 @@ tinymce.init({ selector: 'textarea', // change this value according to your HTML autocorrect_service_url: 'http://example.com/ephox-spelling/' }); ----- \ No newline at end of file +---- diff --git a/modules/ROOT/partials/configuration/image_proxy_service_url.adoc b/modules/ROOT/partials/configuration/image_proxy_service_url.adoc index 6787a6c76d..6227d3dba5 100644 --- a/modules/ROOT/partials/configuration/image_proxy_service_url.adoc +++ b/modules/ROOT/partials/configuration/image_proxy_service_url.adoc @@ -11,7 +11,7 @@ endif::[] == `{proxy_setting_name}` -This option configures the URL to the server-side proxy service which allows remote images hosted on different domains to be retrieved by the {pluginname} plugin. If a proxy is not configured, then remote images may not be able to be {plugin_proxy_action}. Check the xref:introduction-to-premium-selfhosted-services.adoc[Install Server-side Components] guide for details on configuring the self-hosted Java proxy service. +This option configures the URL to the server-side proxy service which allows remote images hosted on different domains to be retrieved by the {pluginname} plugin. If a proxy is not configured, then remote images may not be able to be {plugin_proxy_action}. Check the xref:individual-image-proxy-container.adoc[Deploy the {productname} image proxy server-side component using Docker] guide for details on configuring the Docker container that you will get as a part of your link:{pricingpage}/[{enterpriseversion} subscription]. NOTE: `{proxy_setting_name}` is *not* required when enabling this plugin via xref:editor-and-features.adoc[{cloudname}]. diff --git a/modules/ROOT/partials/configuration/mediaembed_service_url.adoc b/modules/ROOT/partials/configuration/mediaembed_service_url.adoc index 6c448daa60..09b04dc09c 100644 --- a/modules/ROOT/partials/configuration/mediaembed_service_url.adoc +++ b/modules/ROOT/partials/configuration/mediaembed_service_url.adoc @@ -1,7 +1,7 @@ [[mediaembed_service_url]] == `+mediaembed_service_url+` -This option specifies the URL to the service that will handle your requests and return the embeddable snippets used by the *Media Embed* plugin. Please follow these xref:introduction-to-premium-selfhosted-services.adoc[instructions] to configure the *WAR* file that you will get as a part of your link:{pricingpage}/[{enterpriseversion} subscription]. This option is not required for xref:editor-and-features.adoc[{cloudname}]. +This option specifies the URL to the service that will handle your requests and return the embeddable snippets used by the *Media Embed* plugin. The service is available as a Docker container with your link:{pricingpage}/[{enterpriseversion} subscription]. For deployment instructions, see xref:individual-hyperlinking-container.adoc[Deploy the {productname} hyperlinking server-side component using Docker]. This option is not required for xref:editor-and-features.adoc[{cloudname}]. *Type:* `+String+` diff --git a/modules/ROOT/partials/configuration/spellchecker_rpc_url.adoc b/modules/ROOT/partials/configuration/spellchecker_rpc_url.adoc index a64ba2f882..bd29189f79 100644 --- a/modules/ROOT/partials/configuration/spellchecker_rpc_url.adoc +++ b/modules/ROOT/partials/configuration/spellchecker_rpc_url.adoc @@ -1,7 +1,7 @@ [[spellchecker_rpc_url]] == `+spellchecker_rpc_url+` -This option specifies the URL of the server-side `+ephox-spelling+` service. For instructions on how to set up a Spell Checker server-side component, see: the xref:introduction-to-premium-selfhosted-services.adoc[server-side component installation guide]. +This option specifies the URL of the server-side `+ephox-spelling+` service. For instructions on how to set up a Spell Checker server-side component, see: the xref:individual-spelling-container.adoc[Deploy the {productname} spelling service server-side component using Docker]. NOTE: `+spellchecker_rpc_url+` is *not* required when enabling this plugin via xref:editor-and-features.adoc[{cloudname}] @@ -16,4 +16,4 @@ tinymce.init({ plugins: 'tinymcespellchecker', spellchecker_rpc_url: 'localhost/ephox-spelling' }); ----- +---- \ No newline at end of file diff --git a/modules/ROOT/partials/misc/custom-dictionaries-path.adoc b/modules/ROOT/partials/misc/custom-dictionaries-path.adoc index c0197fa035..83af6b5dae 100644 --- a/modules/ROOT/partials/misc/custom-dictionaries-path.adoc +++ b/modules/ROOT/partials/misc/custom-dictionaries-path.adoc @@ -2,7 +2,7 @@ The `+ephox.spelling.custom-dictionaries-path+` element is used to define the lo Requirements: -* The directory containing the custom dictionaries must be on same server machine as the java service. +* The directory containing the custom dictionaries must be mounted as a volume in the container. * The directory should not contain subdirectories or non-dictionary files. {companyname} recommends storing the custom dictionaries in a similar location to the `+application.conf+` file. For example, if `+application.conf+` is in a directory called `+/opt/ephox+`, the dictionary files could be stored in the subdirectory `+/opt/ephox/dictionaries+`. diff --git a/modules/ROOT/partials/misc/hunspell-dictionaries-path.adoc b/modules/ROOT/partials/misc/hunspell-dictionaries-path.adoc index d335cf899a..037c70c892 100644 --- a/modules/ROOT/partials/misc/hunspell-dictionaries-path.adoc +++ b/modules/ROOT/partials/misc/hunspell-dictionaries-path.adoc @@ -3,7 +3,7 @@ The `+ephox.spelling.hunspell-dictionaries-path+` setting is used to define the Requirements: * The directory containing the Hunspell dictionaries must conform to the file structure defined in xref:self-hosting-hunspell.adoc#hunspell-dictionary-storage-for-spell-checker[Hunspell dictionary storage for Spell Checker]. -* The directory containing the Hunspell dictionaries must be on the same server machine (or docker container) as the java service. +* The directory containing the Hunspell dictionaries must be mounted as a volume in the container. {companyname} recommends storing the Hunspell dictionaries in a similar location to the `+application.conf+` file. For example, if `+application.conf+` is in a directory called `+/opt/ephox+`, the Hunspell dictionaries should be stored in the subdirectory `+/opt/ephox/hunspell-dictionaries+`. diff --git a/modules/ROOT/partials/misc/supported-application-servers.adoc b/modules/ROOT/partials/misc/supported-application-servers.adoc index 1e8aa7c9cc..9cbf13afa7 100644 --- a/modules/ROOT/partials/misc/supported-application-servers.adoc +++ b/modules/ROOT/partials/misc/supported-application-servers.adoc @@ -1,14 +1,6 @@ -* Eclipse Jetty: -** 9.4+ (with extended support) -* WebSphere Application Server (WAS) 8 or later -* Apache Tomcat: -+ --- -** 10 (See note below) -** 9+ -** 8.5.12+ -** 8.0.42+ -** 7.0.76+ --- -+ -IMPORTANT: Tomcat 10 will require WAR files to be placed in the _webapp-javaee_ directory rather than the _webapps_ directory due to the change to Jakarta servlets. Jetty 11 is not currently supported due to this change. +* Docker Engine: +** 24.0 or later (latest stable version recommended) +* Kubernetes: +** 1.31.x or later (latest stable version recommended) + +IMPORTANT: As of {productname} {productmajorversion}, server-side components are only supported via Docker containers. Java-based WAR file deployments have been deprecated and are no longer supported. From 35d40a5b994003bb79f544df2d227b49e9ecf0d2 Mon Sep 17 00:00:00 2001 From: "CODE:AG" <57781325+abhinavgandham@users.noreply.github.com> Date: Tue, 15 Jul 2025 11:23:51 +1000 Subject: [PATCH 18/60] DOC-3147: Attempting to add a newline directly after a element such as an image would cause an error. (#3737) Co-authored-by: Karl Kemister-Sheppard --- modules/ROOT/pages/8.0-release-notes.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 7f682f1b97..14cbfd84b9 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -212,6 +212,13 @@ To improve API clarity and maintain a well-defined interface, the `documentBaseU {productname} {release-version} also includes the following bug fix: +=== Attempting to add a newline directly after a `block` element such as an image would cause an error. +// #TINY-12045 + +In previous versions of {productname}, the content selection logic incorrectly assumed that the target element resided within a text node. In reality, it was placed directly inside a `
` element. This mismatch led to a scenario where the selected content was mistakenly reinserted into itself, resulting in errors when pressing `Enter` immediately after an image and introducing a risk of data loss. + +This issue has been resolved in {productname} {release-version}. The selection logic has been updated to correctly identify and handle content within `
` elements such that it does not try to insert content within itself. As a result, pressing `Enter` after an image inside a `
` element no longer triggers errors or causes unintended behavior. + === In inline mode, pressing the back button dismissed the context toolbar and moved focus from the selected image to the editor. // #TINY-12118 From 01969c9139d166909947438a9d74417c39919f86 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 13:00:50 +1000 Subject: [PATCH 19/60] DOC-3147: Language code standardization to RFC5646/BCP47 format. (#3771) --- .../examples/live-demos/spellchecker/index.js | 34 +++++------ modules/ROOT/pages/8.0-release-notes.adoc | 61 +++++++++++++++++++ ...om-dictionaries-for-tiny-spellchecker.adoc | 2 +- .../introduction-to-tiny-spellchecker.adoc | 6 +- .../ROOT/pages/localize-your-language.adoc | 4 +- .../ROOT/partials/configuration/language.adoc | 6 +- .../configuration/spellchecker_language.adoc | 4 +- .../configuration/spellchecker_languages.adoc | 4 +- .../spelling-service-installation.adoc | 19 +++--- .../partials/misc/spellchecker-languages.adoc | 32 +++++----- modules/ROOT/partials/misc/ui-languages.adoc | 59 ++++++++++-------- .../plugins/spellchecker-content_langs.adoc | 32 +++++----- 12 files changed, 163 insertions(+), 100 deletions(-) diff --git a/modules/ROOT/examples/live-demos/spellchecker/index.js b/modules/ROOT/examples/live-demos/spellchecker/index.js index 617b1a579d..7769778230 100644 --- a/modules/ROOT/examples/live-demos/spellchecker/index.js +++ b/modules/ROOT/examples/live-demos/spellchecker/index.js @@ -3,31 +3,31 @@ tinymce.init({ plugins: 'code tinymcespellchecker link', toolbar: 'spellchecker language spellcheckdialog', height: 500, - spellchecker_language: 'en_US', + spellchecker_language: 'en-US', content_langs: [ - { title: 'Afrikaans (South Africa)', code: 'af_ZA', customCode: 'af_ZA' }, - { title: 'English (Australia)', code: 'en_AU' }, - { title: 'English (Canada)', code: 'en_CA' }, - { title: 'English (United Kingdom)', code: 'en_GB' }, - { title: 'English (United States)', code: 'en_US' }, - { title: 'Medical English (US)', code: 'en_US', customCode: 'en_US-medical' }, - { title: 'Medical English (UK)', code: 'en_GB', customCode: 'en_GB-medical' }, + { title: 'Afrikaans (South Africa)', code: 'af-ZA', customCode: 'af-ZA' }, + { title: 'English (Australia)', code: 'en-AU' }, + { title: 'English (Canada)', code: 'en-CA' }, + { title: 'English (United Kingdom)', code: 'en-GB' }, + { title: 'English (United States)', code: 'en-US' }, + { title: 'Medical English (US)', code: 'en-US', customCode: 'en-US-medical' }, + { title: 'Medical English (UK)', code: 'en-GB', customCode: 'en-GB-medical' }, { title: 'Danish', code: 'da' }, - { title: 'Dutch', code: 'nl_NL' }, + { title: 'Dutch', code: 'nl-NL' }, { title: 'Finnish', code: 'fi' }, { title: 'French', code: 'fr' }, - { title: 'German', code: 'de_DE' }, + { title: 'German', code: 'de-DE' }, { title: 'Hungarian', code: 'hu' }, - { title: 'Italian', code: 'it_IT' }, - { title: 'Maori (New Zealand)', code: 'mi_NZ' }, - { title: 'Norwegian Bokmål', code: 'nb_NO' }, + { title: 'Italian', code: 'it-IT' }, + { title: 'Maori (New Zealand)', code: 'mi-NZ' }, + { title: 'Norwegian Bokmål', code: 'nb-NO' }, { title: 'Norwegian Nynorsk', code: 'nn' }, { title: 'Polish', code: 'pl' }, - { title: 'Portuguese (Brazil)', code: 'pt_BR' }, - { title: 'Portuguese (Portugal)', code: 'pt_PT' }, + { title: 'Portuguese (Brazil)', code: 'pt-BR' }, + { title: 'Portuguese (Portugal)', code: 'pt-PT' }, { title: 'Spanish', code: 'es' }, - { title: 'Swedish', code: 'sv_SE' }, - { title: 'Swedish (Finland)', code: 'sv_FI' } + { title: 'Swedish', code: 'sv-SE' }, + { title: 'Swedish (Finland)', code: 'sv-FI' } ], content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }' }); diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 14cbfd84b9..472dfbabd2 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -58,6 +58,67 @@ The following premium plugin updates were released alongside {productname} {rele // For information on the **** plugin, see: xref:.adoc[]. +=== Spell Checker + +The {productname} {release-version} includes an accompanying release of the **Spell Checker** premium plugin. + +**Spell Checker** includes the following improvement. + +=== Language code standardization to RFC5646/BCP47 format + +The {productname} {release-version} release introduces standardized support for language codes using the RFC5646 (also known as BCP47) format. This update applies to all language-related configurations, including: + +* UI language packs (premium and community) +* Spellchecker language codes +* HTML `lang` attributes +* Content language selection + +**Changes** + +* Language codes now use hyphens (`-`) instead of underscores (`_`). For example: +** `'en-US'` instead of `'en_US'` +** `'zh-TW'` instead of `'zh_TW'` +** `'pt-BR'` instead of `'pt_BR'` +* Base language codes without regions (e.g., `'en'`, `'es'`, `'fr'`) remain unchanged. +* File names for language packs have been updated to use hyphens. +* Premium plugins have been updated to recognize RFC5646-compliant codes. + +**Backward Compatibility** + +To ensure a smooth migration + +* Both hyphenated and underscore formats are supported in {productname} {release-version}. +* A console warning is displayed when the legacy underscore format is used. +* Both formats of language pack files are distributed with {productname} {release-version}. +* {productname} 9 will support only the RFC5646-compliant hyphenated format. + +**Migration** + +. Update language-related configuration in `tinymce.init`: ++ +[source,javascript] +---- +language: 'en-US', +spellchecker_language: 'en-US' +---- ++ +. Update `content_langs` configuration: ++ +[source,javascript] +---- +content_langs: [ + { title: 'English (US)', code: 'en-US' }, + { title: 'Portuguese (Brazil)', code: 'pt-BR' } +] +---- ++ +. Rename any custom dictionary files to use hyphens (e.g., `'en-GB.txt'` instead of `'en_GB.txt'`). +. Ensure any server-side integrations or custom language pack files follow the new naming convention. + +This standardization aligns {productname} with modern web standards and improves consistency across its multilingual features. + +For information on the **Spell Checker** premium plugin, see: xref:introduction-to-tiny-spellchecker.adoc[Spell Checker plugin] or for an complete list of supported languages, see: xref:introduction-to-tiny-spellchecker.adoc#supported-languages[Supported languages]. + === Accessibility Checker The {productname} {release-version} release includes an accompanying release of the **Accessibility Checker** premium plugin. diff --git a/modules/ROOT/pages/custom-dictionaries-for-tiny-spellchecker.adoc b/modules/ROOT/pages/custom-dictionaries-for-tiny-spellchecker.adoc index 1fe8d8cacc..65bb8f1e08 100644 --- a/modules/ROOT/pages/custom-dictionaries-for-tiny-spellchecker.adoc +++ b/modules/ROOT/pages/custom-dictionaries-for-tiny-spellchecker.adoc @@ -7,7 +7,7 @@ One custom dictionary can be created for each language already supported by the spell checker (see xref:introduction-to-tiny-spellchecker.adoc#supported-languages[supported languages]) or any arbitrary language added by additional Hunspell dictionary files included in Hunspell Dictionary Path (See xref:self-hosting-hunspell.adoc[Add Hunspell dictionaries to Spell Checker]). It's also possible to define an additional "global" dictionary that contains words that are valid across all languages, such as trademarks. -A custom dictionary file for a particular language must be named with the language code of the language (see xref:introduction-to-tiny-spellchecker.adoc#supported-languages[supported languages] for language code examples), plus the suffix `+.txt+`: E.g. `+en.txt+`, `+en_gb.txt+`, `+fr.txt+`, `+de.txt+` etc. +A custom dictionary file for a particular language must be named with the language code of the language (see xref:introduction-to-tiny-spellchecker.adoc#supported-languages[supported languages] for language code examples), plus the suffix `+.txt+`: E.g. `+en.txt+`, `+en-GB.txt+`, `+fr.txt+`, `+de.txt+` etc. The "global" dictionary file for language-independent words must be called "global.txt". diff --git a/modules/ROOT/pages/introduction-to-tiny-spellchecker.adoc b/modules/ROOT/pages/introduction-to-tiny-spellchecker.adoc index 570c7498fd..52ef2cc606 100644 --- a/modules/ROOT/pages/introduction-to-tiny-spellchecker.adoc +++ b/modules/ROOT/pages/introduction-to-tiny-spellchecker.adoc @@ -29,7 +29,7 @@ With {cloudname} the server-side spellchecking component is automatically config tinymce.init({ selector: 'textarea', plugins: 'tinymcespellchecker', - spellchecker_language: 'en_US' + spellchecker_language: 'en-US' // Note: Using RFC5646 format with hyphen }); ---- @@ -47,7 +47,7 @@ tinymce.init({ selector: 'textarea', plugins: 'tinymcespellchecker', spellchecker_rpc_url: 'localhost/ephox-spelling', - spellchecker_language: 'en_US' + spellchecker_language: 'en-US' // Note: Using RFC5646 format with hyphen }); ---- @@ -243,7 +243,7 @@ tinymce.init({ The `+spelling+` object, which is provided by the `+SpellcheckerUpdated+` event, contains the result of the spelling service spellcheck. -The keys of the outermost object are the language code for each checked language. +The keys of the outermost object are the language code for each checked language (using RFC5646 format, e.g., 'en-US', 'es-ES'). Under each returned language code is an object with diff --git a/modules/ROOT/pages/localize-your-language.adoc b/modules/ROOT/pages/localize-your-language.adoc index 38ca685103..6508fd67b9 100644 --- a/modules/ROOT/pages/localize-your-language.adoc +++ b/modules/ROOT/pages/localize-your-language.adoc @@ -25,7 +25,7 @@ IMPORTANT: The language settings will not work unless the language pack is place == Step 3 -Set the language option in {productname}'s configuration to the language code in the list on xref:ui-localization.adoc#language[this page]. +Set the language option in {productname}'s configuration to the RFC5646 language code in the list on xref:ui-localization.adoc#language[this page]. == Step 4 @@ -46,7 +46,7 @@ link:{gettiny}/language-packages/[Download the Chinese language] pack to test th diff --git a/modules/ROOT/partials/configuration/language.adoc b/modules/ROOT/partials/configuration/language.adoc index 9045a957f7..7915ca95c4 100644 --- a/modules/ROOT/partials/configuration/language.adoc +++ b/modules/ROOT/partials/configuration/language.adoc @@ -19,20 +19,20 @@ For information on: === Example: using `+language+` -In this example we will set the editor language to Swedish. +In this example we will set the editor language to Swedish using the RFC5646 format: [source,js] ---- tinymce.init({ selector: 'textarea', // change this value according to your HTML - language: 'sv_SE' + language: 'sv-SE' }); ---- [[using-the-premium-language-packs]] === Using the premium language packs -The following professionally localized language packs are provided to paid {cloudname} and premium self-hosted deployments. To use these language packs, set the `+language+` option to the corresponding language code. No additional configuration is required. +The following professionally localized language packs are provided to paid {cloudname} and premium self-hosted deployments. To use these language packs, set the `+language+` option to the corresponding language code in RFC5646 format. No additional configuration is required. include::partial$misc/ui-languages.adoc[leveloffset=+2] diff --git a/modules/ROOT/partials/configuration/spellchecker_language.adoc b/modules/ROOT/partials/configuration/spellchecker_language.adoc index 4314739a62..7161900fc3 100644 --- a/modules/ROOT/partials/configuration/spellchecker_language.adoc +++ b/modules/ROOT/partials/configuration/spellchecker_language.adoc @@ -5,7 +5,7 @@ This option specifies the default language used by Spell Checker. *Type:* `+String+` -*Default value:* `+'en_US'+` +*Default value:* `+'en-US'+` === Example: using `+spellchecker_language+` @@ -14,6 +14,6 @@ This option specifies the default language used by Spell Checker. tinymce.init({ selector: 'textarea', plugins: 'tinymcespellchecker', - spellchecker_language: 'de' + spellchecker_language: 'de' // Use ISO language code, hyphenated for regional variants (e.g., 'de-DE') }); ---- diff --git a/modules/ROOT/partials/configuration/spellchecker_languages.adoc b/modules/ROOT/partials/configuration/spellchecker_languages.adoc index d44edd128f..c99335297c 100644 --- a/modules/ROOT/partials/configuration/spellchecker_languages.adoc +++ b/modules/ROOT/partials/configuration/spellchecker_languages.adoc @@ -8,7 +8,7 @@ This option specifies the spellchecker languages that are available to the user, *Default value:* [source,js] ---- -'English (United States)=en_US,English (United Kingdom)=en_GB,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Norwegian Bokmål=nb_NO,Norwegian Nynorsk=nn,Brazilian Portuguese=pt_BR,Portuguese=pt,Portuguese (Portugal)=pt_PT,Spanish=es,Swedish=sv,Swedish (Finland)=sv_FI,Afrikaans (South Africa)=af_ZA,English (Australia)=en_AU,English (Canada)=en_CA,English (United Kingdom)=en_GB,English (United States)=en_US,Medical English (US)=en_US-medical,Medical English (UK)=en_GB-medical,Maori (New Zealand)=mi_NZ' +'English (United States)=en-US,English (United Kingdom)=en-GB,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Norwegian Bokmål=nb-NO,Norwegian Nynorsk=nn,Brazilian Portuguese=pt-BR,Portuguese=pt,Portuguese (Portugal)=pt-PT,Spanish=es,Swedish=sv,Swedish (Finland)=sv-FI,Afrikaans (South Africa)=af-ZA,English (Australia)=en-AU,English (Canada)=en-CA,English (United Kingdom)=en-GB,English (United States)=en-US,Medical English (US)=en-US-medical,Medical English (UK)=en-GB-medical,Maori (New Zealand)=mi-NZ' ---- @@ -19,6 +19,6 @@ This option specifies the spellchecker languages that are available to the user, tinymce.init({ selector: 'textarea', plugins: 'tinymcespellchecker', - spellchecker_languages: 'US English=en_US,UK English=en_GB,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Norwegian Bokmål=nb_NO,Norwegian Nynorsk=nn,Brazilian Portuguese=pt_BR,Portuguese=pt,Portuguese (Portugal)=pt_PT,Spanish=es,Swedish=sv,Swedish (Finland)=sv_FI,Afrikaans (South Africa)=af_ZA,English (Australia)=en_AU,English (Canada)=en_CA,English (United Kingdom)=en_GB,English (United States)=en_US,Medical English (US)=en_US-medical,Medical English (UK)=en_GB-medical,Maori (New Zealand)=mi_NZ' + spellchecker_languages: 'US English=en-US,UK English=en-GB,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Norwegian Bokmål=nb-NO,Norwegian Nynorsk=nn,Brazilian Portuguese=pt-BR,Portuguese=pt,Portuguese (Portugal)=pt-PT,Spanish=es,Swedish=sv,Swedish (Finland)=sv-FI,Afrikaans (South Africa)=af-ZA,English (Australia)=en-AU,English (Canada)=en-CA,English (United Kingdom)=en-GB,English (United States)=en-US,Medical English (US)=en-US-medical,Medical English (UK)=en-GB-medical,Maori (New Zealand)=mi-NZ' }); ---- \ No newline at end of file diff --git a/modules/ROOT/partials/docker/spelling-service/spelling-service-installation.adoc b/modules/ROOT/partials/docker/spelling-service/spelling-service-installation.adoc index afcc0d41ef..061d819be1 100644 --- a/modules/ROOT/partials/docker/spelling-service/spelling-service-installation.adoc +++ b/modules/ROOT/partials/docker/spelling-service/spelling-service-installation.adoc @@ -175,11 +175,11 @@ spelling-tiny-1 | 2025-02-11 09:51:11.104Z [io-compute-blocker-6] INFO c.e.i.d spelling-tiny-1 | 2025-02-11 09:51:11.161Z [io-compute-blocker-6] INFO com.ephox.nectar.data.Bees$ - Loading all dictionaries from WinterTree spelling-tiny-1 | 2025-02-11 09:51:11.482Z [io-compute-blocker-5] INFO c.e.nectar.hunspell.HunspellLoader$ - Loading hunspell dictionary from path: /app/resources/hunspell-dictionaries and locale es spelling-tiny-1 | 2025-02-11 09:51:11.536Z [io-compute-blocker-5] INFO c.e.nectar.hunspell.HunspellLoader$ - Finished loading hunspell for es -spelling-tiny-1 | 2025-02-11 09:51:11.537Z [io-compute-blocker-5] INFO c.e.nectar.hunspell.HunspellLoader$ - Loading hunspell dictionary from path: /app/resources/hunspell-dictionaries and locale pt_BR -spelling-tiny-1 | 2025-02-11 09:51:11.881Z [io-compute-blocker-5] INFO c.e.nectar.hunspell.HunspellLoader$ - Finished loading hunspell for pt_BR +spelling-tiny-1 | 2025-02-11 09:51:11.537Z [io-compute-blocker-5] INFO c.e.nectar.hunspell.HunspellLoader$ - Loading hunspell dictionary from path: /app/resources/hunspell-dictionaries and locale pt-BR +spelling-tiny-1 | 2025-02-11 09:51:11.881Z [io-compute-blocker-5] INFO c.e.nectar.hunspell.HunspellLoader$ - Finished loading hunspell for pt-BR ... -spelling-tiny-1 | 2025-02-11 09:51:13.593Z [io-compute-blocker-5] INFO c.e.nectar.hunspell.HunspellLoader$ - Loading hunspell dictionary from path: /app/resources/hunspell-dictionaries and locale de_DE -spelling-tiny-1 | 2025-02-11 09:51:13.651Z [io-compute-blocker-5] INFO c.e.nectar.hunspell.HunspellLoader$ - Finished loading hunspell for de_DE +spelling-tiny-1 | 2025-02-11 09:51:13.593Z [io-compute-blocker-5] INFO c.e.nectar.hunspell.HunspellLoader$ - Loading hunspell dictionary from path: /app/resources/hunspell-dictionaries and locale de-DE +spelling-tiny-1 | 2025-02-11 09:51:13.651Z [io-compute-blocker-5] INFO c.e.nectar.hunspell.HunspellLoader$ - Finished loading hunspell for de-DE spelling-tiny-1 | 2025-02-11 09:51:14.142Z [io-compute-9] INFO o.h.b.c.nio1.NIO1SocketServerGroup - Service bound to address /0:0:0:0:0:0:0:0:18080 spelling-tiny-1 | 2025-02-11 09:51:14.146Z [io-compute-9] INFO o.h.blaze.server.BlazeServerBuilder - spelling-tiny-1 | _ _ _ _ _ @@ -215,7 +215,7 @@ To confirm that a request is being sent to the {pluginname} service, use: + [source, sh] ---- -curl http://localhost:18080/2/check -d '{"words": ["teh"], "language": "en_US"}' -H "Origin: http://good.com" -H "Content-Type: application/json" +curl http://localhost:18080/2/check -d '{"words": ["teh"], "language": "en-US"}' -H "Origin: http://good.com" -H "Content-Type: application/json" ---- + @@ -224,7 +224,7 @@ Finally, to verify if a request is unauthorized and originates from an incorrect + [source, sh] ---- -curl http://localhost:18080/2/check -d '{"words": ["teh"], "language": "en_US"}' -H "Origin: http://bad.com" -H "Content-Type: application/json" +curl http://localhost:18080/2/check -d '{"words": ["teh"], "language": "en-US"}' -H "Origin: http://bad.com" -H "Content-Type: application/json" ---- + @@ -245,12 +245,7 @@ tinymce.init({ selector: 'textarea#spellchecker', // change this value according to your HTML plugins: 'code tinymcespellchecker link', toolbar: 'spellchecker language spellcheckdialog', - spellchecker_language: 'en_US', + spellchecker_language: 'en-US', // Note: Using RFC5646 format with hyphen spellchecker_rpc_url: "http://localhost:18080" }); ---- - - - - - diff --git a/modules/ROOT/partials/misc/spellchecker-languages.adoc b/modules/ROOT/partials/misc/spellchecker-languages.adoc index e6bc1bb04a..9646c60be1 100644 --- a/modules/ROOT/partials/misc/spellchecker-languages.adoc +++ b/modules/ROOT/partials/misc/spellchecker-languages.adoc @@ -6,27 +6,27 @@ The following languages are supported for the Spell Checker plugin. All of the l [cols="2,^1,^1,^1",options="header"] |=== |Language |Code |Pre-packaged with {productname} |Supported Hunspell dictionaries -|Afrikaans (South Africa) |af_ZA |{cross} |{tick} -|English (Australia) |en_AU |{cross} |{tick} -|English (Canada) |en_CA |{cross} |{tick} -|English (United Kingdom) |en_GB, en_UK, en_BR |{tick} |{tick} -|English (United States) |en, en_US |{tick} |{tick} -|Medical English (US) |en-medical, en_US-medical |{tick} |{tick} -|Medical English (UK) |en_GB-medical |{tick} |{cross} +|Afrikaans (South Africa) |af-ZA |{cross} |{tick} +|English (Australia) |en-AU |{cross} |{tick} +|English (Canada) |en-CA |{cross} |{tick} +|English (United Kingdom) |en-GB, en-UK, en-BR |{tick} |{tick} +|English (United States) |en, en-US |{tick} |{tick} +|Medical English (US) |en-medical, en-US-medical |{tick} |{tick} +|Medical English (UK) |en-GB-medical |{tick} |{cross} |Danish |da |{tick} |{tick} -|Dutch |nl, nl_NL |{tick} |{tick} +|Dutch |nl, nl-NL |{tick} |{tick} |Finnish |fi |{tick} |{cross} |French |fr |{tick} |{tick} -|German |de, de_DE |{tick} |{tick} +|German |de, de-DE |{tick} |{tick} |Hungarian |hu |{cross} |{tick} -|Italian |it, it_IT |{tick} |{tick} -|Maori (New Zealand) |mi_NZ |{cross} |{tick} -|Norwegian Bokmål |nb, nb_NO |{tick} |{tick} +|Italian |it, it-IT |{tick} |{tick} +|Maori (New Zealand) |mi-NZ |{cross} |{tick} +|Norwegian Bokmål |nb, nb-NO |{tick} |{tick} |Norwegian Nynorsk |nn |{cross} |{tick} |Polish |pl |{cross} |{tick} -|Portuguese (Brazil) |pt, pt_BR |{tick} |{tick} -|Portuguese (Portugal) |pt_PT |{tick} |{tick} +|Portuguese (Brazil) |pt, pt-BR |{tick} |{tick} +|Portuguese (Portugal) |pt-PT |{tick} |{tick} |Spanish |es |{tick} |{tick} -|Swedish |sv, sv_SE |{tick} |{tick} -|Swedish (Finland) |sv_FI |{cross} |{tick} +|Swedish |sv, sv-SE |{tick} |{tick} +|Swedish (Finland) |sv-FI |{cross} |{tick} |=== \ No newline at end of file diff --git a/modules/ROOT/partials/misc/ui-languages.adoc b/modules/ROOT/partials/misc/ui-languages.adoc index abe916ab5d..461fe1b3b3 100644 --- a/modules/ROOT/partials/misc/ui-languages.adoc +++ b/modules/ROOT/partials/misc/ui-languages.adoc @@ -1,45 +1,52 @@ [[supported-languages]] == Supported Languages +[IMPORTANT] +==== +From {productname} 8.0, language codes use RFC5646 format with hyphens (-) instead of underscores (_). For backward compatibility, both formats are supported in {productname} 8, but underscore format will show console warning. + +Example: "{productname} language code "en_US" is deprecated, please use "en-US" instead.". +==== + ifeval::[{forModuleLoaders} == true] [cols="<2,^1,^2",options="header"] |=== | Language | Code | Filename | Arabic | ar | `+./langs/ar.js+` | Basque | eu | `+./langs/eu.js+` -| Bulgarian (Bulgaria) | bg_BG | `+./langs/bg_BG.js+` +| Bulgarian (Bulgaria) | bg-BG | `+./langs/bg-BG.js+` | Catalan | ca | `+./langs/ca.js+` -| Chinese (China) | zh_CN | `+./langs/zh_CN.js+` -| Chinese (Taiwan) | zh_TW | `+./langs/zh_TW.js+` +| Chinese (China) | zh-CN | `+./langs/zh-CN.js+` +| Chinese (Taiwan) | zh-TW | `+./langs/zh-TW.js+` | Croatian | hr | `+./langs/hr.js+` | Czech | cs | `+./langs/cs.js+` | Danish | da | `+./langs/da.js+` | Dutch | nl | `+./langs/nl.js+` | Finnish | fi | `+./langs/fi.js+` -| French (France) | fr_FR | `+./langs/fr_FR.js+` +| French (France) | fr-FR | `+./langs/fr-FR.js+` | German | de | `+./langs/de.js+` | Greek | el | `+./langs/el.js+` -| Hebrew (Israel) | he_IL | `+./langs/he_IL.js+` +| Hebrew (Israel) | he-IL | `+./langs/he-IL.js+` | Hindi | hi | `+./langs/hi.js+` -| Hungarian (Hungary) | hu_HU | `+./langs/hu_HU.js+` +| Hungarian (Hungary) | hu-HU | `+./langs/hu-HU.js+` | Indonesian | id | `+./langs/id.js+` | Italian | it | `+./langs/it.js+` | Japanese | ja | `+./langs/ja.js+` | Kazakh | kk | `+./langs/kk.js+` -| Korean (Korea) | ko_KR | `+./langs/ko_KR.js+` +| Korean (Korea) | ko-KR | `+./langs/ko-KR.js+` | Malay | ms | `+./langs/ms.js+` -| Norwegian Bokmål (Norway) | nb_NO | `+./langs/nb_NO.js+` +| Norwegian Bokmål (Norway) | nb-NO | `+./langs/nb-NO.js+` | Persian | fa | `+./langs/fa.js+` | Polish | pl | `+./langs/pl.js+` -| Portuguese (Brazil) | pt_BR | `+./langs/pt_BR.js+` -| Portuguese (Portugal) | pt_PT | `+./langs/pt_PT.js+` +| Portuguese (Brazil) | pt-BR | `+./langs/pt-BR.js+` +| Portuguese (Portugal) | pt-PT | `+./langs/pt-PT.js+` | Romanian | ro | `+./langs/ro.js+` | Russian | ru | `+./langs/ru.js+` | Slovak | sk | `+./langs/sk.js+` -| Slovenian (Slovenia) | sl_SI | `+./langs/sl_SI.js+` +| Slovenian (Slovenia) | sl-SI | `+./langs/sl-SI.js+` | Spanish | es | `+./langs/es.js+` -| Swedish (Sweden) | sv_SE | `+./langs/sv_SE.js+` -| Thai (Thailand) | th_TH | `+./langs/th_TH.js+` +| Swedish (Sweden) | sv-SE | `+./langs/sv-SE.js+` +| Thai (Thailand) | th-TH | `+./langs/th-TH.js+` | Turkish | tr | `+./langs/tr.js+` | Ukrainian | uk | `+./langs/uk.js+` | Vietnamese | vi | `+./langs/vi.js+` @@ -51,39 +58,39 @@ ifeval::[{forModuleLoaders} != true] | Language | Code | Arabic | ar | Basque | eu -| Bulgarian (Bulgaria) | bg_BG +| Bulgarian (Bulgaria) | bg-BG | Catalan | ca -| Chinese (China) | zh_CN -| Chinese (Taiwan) | zh_TW +| Chinese (China) | zh-CN +| Chinese (Taiwan) | zh-TW | Croatian | hr | Czech | cs | Danish | da | Dutch | nl | Finnish | fi -| French (France) | fr_FR +| French (France) | fr-FR | German | de | Greek | el -| Hebrew (Israel) | he_IL +| Hebrew (Israel) | he-IL | Hindi | hi -| Hungarian (Hungary) | hu_HU +| Hungarian (Hungary) | hu-HU | Indonesian | id | Italian | it | Japanese | ja | Kazakh | kk -| Korean (Korea) | ko_KR +| Korean (Korea) | ko-KR | Malay | ms -| Norwegian Bokmål (Norway) | nb_NO +| Norwegian Bokmål (Norway) | nb-NO | Persian | fa | Polish | pl -| Portuguese (Brazil) | pt_BR -| Portuguese (Portugal) | pt_PT +| Portuguese (Brazil) | pt-BR +| Portuguese (Portugal) | pt-PT | Romanian | ro | Russian | ru | Slovak | sk -| Slovenian (Slovenia) | sl_SI +| Slovenian (Slovenia) | sl-SI | Spanish | es -| Swedish (Sweden) | sv_SE -| Thai (Thailand) | th_TH +| Swedish (Sweden) | sv-SE +| Thai (Thailand) | th-TH | Turkish | tr | Ukrainian | uk | Vietnamese | vi diff --git a/modules/ROOT/partials/plugins/spellchecker-content_langs.adoc b/modules/ROOT/partials/plugins/spellchecker-content_langs.adoc index f7d077b457..25de405a34 100644 --- a/modules/ROOT/partials/plugins/spellchecker-content_langs.adoc +++ b/modules/ROOT/partials/plugins/spellchecker-content_langs.adoc @@ -22,29 +22,29 @@ tinymce.init({ toolbar: 'language', plugins: 'tinymcespellchecker', content_langs: [ - { title: 'Afrikaans (South Africa)', code: 'af_ZA', customCode: 'af_ZA' }, - { title: 'English (Australia)', code: 'en_AU' }, - { title: 'English (Canada)', code: 'en_CA' }, - { title: 'English (United Kingdom)', code: 'en_GB' }, - { title: 'English (United States)', code: 'en_US' }, - { title: 'Medical English (US)', code: 'en_US', customCode: 'en_US-medical' }, - { title: 'Medical English (UK)', code: 'en_GB', customCode: 'en_GB-medical' }, + { title: 'Afrikaans (South Africa)', code: 'af-ZA', customCode: 'af-ZA' }, + { title: 'English (Australia)', code: 'en-AU' }, + { title: 'English (Canada)', code: 'en-CA' }, + { title: 'English (United Kingdom)', code: 'en-GB' }, + { title: 'English (United States)', code: 'en-US' }, + { title: 'Medical English (US)', code: 'en-US', customCode: 'en-US-medical' }, + { title: 'Medical English (UK)', code: 'en-GB', customCode: 'en-GB-medical' }, { title: 'Danish', code: 'da' }, - { title: 'Dutch', code: 'nl_NL' }, + { title: 'Dutch', code: 'nl-NL' }, { title: 'Finnish', code: 'fi' }, { title: 'French', code: 'fr' }, - { title: 'German', code: 'de_DE' }, + { title: 'German', code: 'de-DE' }, { title: 'Hungarian', code: 'hu' }, - { title: 'Italian', code: 'it_IT' }, - { title: 'Maori (New Zealand)', code: 'mi_NZ' }, - { title: 'Norwegian Bokmål', code: 'nb_NO' }, + { title: 'Italian', code: 'it-IT' }, + { title: 'Maori (New Zealand)', code: 'mi-NZ' }, + { title: 'Norwegian Bokmål', code: 'nb-NO' }, { title: 'Norwegian Nynorsk', code: 'nn' }, { title: 'Polish', code: 'pl' }, - { title: 'Portuguese (Brazil)', code: 'pt_BR' }, - { title: 'Portuguese (Portugal)', code: 'pt_PT' }, + { title: 'Portuguese (Brazil)', code: 'pt-BR' }, + { title: 'Portuguese (Portugal)', code: 'pt-PT' }, { title: 'Spanish', code: 'es' }, - { title: 'Swedish', code: 'sv_SE' }, - { title: 'Swedish (Finland)', code: 'sv_FI' } + { title: 'Swedish', code: 'sv-SE' }, + { title: 'Swedish (Finland)', code: 'sv-FI' } ], }); ---- \ No newline at end of file From e5ca8b712ea8c59b7f63a2c9e8a69bf866bff7b9 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 13:01:35 +1000 Subject: [PATCH 20/60] DOC-3147: Deprecated `editor.selection.setContent` API (#3789) * DOC-3147: Deprecated API. * Update modules/ROOT/pages/8.0-release-notes.adoc --- modules/ROOT/pages/8.0-release-notes.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 472dfbabd2..23da487de7 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -373,6 +373,13 @@ For information about setting up containerized server-side components using Dock // CCFR here. +=== Deprecated `editor.selection.setContent` API +// TINY-11692 + +The `editor.selection.setContent` method has been deprecated in {productname} {release-version}. This low-level API was never intended for external use and does not guarantee consistent behavior when inserting complex content structures, such as lists. Integrators are advised to use the supported `editor.insertContent` method for reliable content insertion. + +This deprecation helps reduce confusion and aligns content insertion with {productname}'s supported APIs. + [[known-issues]] == Known issues From 51bc9ae622ab14733af8b78906a6ff89e3cc8632 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 13:01:57 +1000 Subject: [PATCH 21/60] DOC-3147: New `allow_html_in_comments` option to allow HTML-like content inside comment data (#3791) * DOC-3147: New allow_html_in_comments option to allow HTML-like content inside comment data. * Update modules/ROOT/partials/configuration/allow_html_in_comments.adoc Co-authored-by: michalnieruchalski-tiugo * Update modules/ROOT/pages/8.0-release-notes.adoc Co-authored-by: michalnieruchalski-tiugo --------- Co-authored-by: michalnieruchalski-tiugo --- modules/ROOT/pages/8.0-release-notes.adoc | 8 ++-- modules/ROOT/pages/content-filtering.adoc | 2 + modules/ROOT/pages/security.adoc | 2 + .../configuration/allow_html_in_comments.adoc | 48 +++++++++++++++++++ 4 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 modules/ROOT/partials/configuration/allow_html_in_comments.adoc diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 23da487de7..5af99b20b7 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -227,10 +227,12 @@ Previously, menu items and tooltips containing three consecutive periods (`...`) {productname} {release-version} also includes the following addition: -// === -// #TINY-vwxyz1 +=== New `allow_html_in_comments` option to allow HTML-like content inside comment data +// #TINY-12220 -// CCFR here. +Comments containing HTML-like content are removed from the editor's content by default for security reasons. This is done during the sanitization process, which ensures that any HTML-like content in comments is stripped out. + +{productname} introduces a new configuration option, xref:content-filtering.adoc#allow_html_in_comments[allow_html_in_comments], to give users control over whether HTML-like content in comments should be retained or removed. By default, this content is removed for security, but setting the option to `true` allows HTML-like content in comments to be preserved when needed. [[changes]] diff --git a/modules/ROOT/pages/content-filtering.adoc b/modules/ROOT/pages/content-filtering.adoc index 2a5896970a..e65bc480a3 100644 --- a/modules/ROOT/pages/content-filtering.adoc +++ b/modules/ROOT/pages/content-filtering.adoc @@ -5,6 +5,8 @@ include::partial$configuration/allow_conditional_comments.adoc[] +include::partial$configuration/allow_html_in_comments.adoc[] + include::partial$configuration/allow_html_in_named_anchor.adoc[] include::partial$configuration/allow_mathml_annotation_encodings.adoc[] diff --git a/modules/ROOT/pages/security.adoc b/modules/ROOT/pages/security.adoc index 9a60891923..0bfe90b472 100644 --- a/modules/ROOT/pages/security.adoc +++ b/modules/ROOT/pages/security.adoc @@ -113,6 +113,8 @@ include::partial$configuration/sandbox_iframes.adoc[] include::partial$configuration/convert_unsafe_embeds.adoc[] +include::partial$configuration/allow_html_in_comments.adoc[] + [[insecure-transmission-and-storage-of-data]] === Insecure Transmission and Storage of data diff --git a/modules/ROOT/partials/configuration/allow_html_in_comments.adoc b/modules/ROOT/partials/configuration/allow_html_in_comments.adoc new file mode 100644 index 0000000000..b052e83dca --- /dev/null +++ b/modules/ROOT/partials/configuration/allow_html_in_comments.adoc @@ -0,0 +1,48 @@ +[[allow_html_in_comments]] +== `allow_html_in_comments` + +The `allow_html_in_comments` option allows HTML-like content to be retained in comments within the editor content. By default, {productname} removes comments containing HTML-like content as a security measure. + +*Type:* `+Boolean+` + +*Default value:* `+false+` + +[WARNING] +Setting this option to `true` may expose your application to XSS vulnerabilities. The DOMPurify maintainers have identified potential security risks when HTML-like content is allowed in comments. Only enable this option if you trust your content sources and understand the security implications. + +=== Example: using `allow_html_in_comments` + +The following example demonstrates how comments containing HTML are handled by default (removed) and how to configure {productname} to retain them: + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + allow_html_in_comments: true, // Enable HTML in comments +}); +---- + +ifeval::["{docname}" != "security"] +=== Comment behavior examples + +With `allow_html_in_comments: false` (default), the editor's content after initialization will be: +[source,html] +---- +
+

Some content

+

Some additional content

+
+---- + +With `allow_html_in_comments: true`, the editor's content after initialization will be: +[source,html] +---- +
+

Some content

+ +

Some additional content

+
+---- +endif::[] \ No newline at end of file From 7ad29fdfc1678bf87e8181f9a233a354f408aa65 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 13:11:25 +1000 Subject: [PATCH 22/60] DOC-3147: The default value of `pagebreak_split_block` is now `true` to match the new `pagebreak_separator` default. (#3795) * DOC-3147: The default value of pagebreak_split_block is now true to match the new pagebreak_separator default. * Update modules/ROOT/pages/8.0-release-notes.adoc Co-authored-by: shirqa <43625458+ShiridiGandham@users.noreply.github.com> * Update modules/ROOT/pages/8.0-release-notes.adoc Co-authored-by: shirqa <43625458+ShiridiGandham@users.noreply.github.com> * Update modules/ROOT/pages/8.0-release-notes.adoc Co-authored-by: Hamza Benkhaldoun * Update modules/ROOT/pages/8.0-release-notes.adoc Co-authored-by: Hamza Benkhaldoun --------- Co-authored-by: shirqa <43625458+ShiridiGandham@users.noreply.github.com> Co-authored-by: Hamza Benkhaldoun --- modules/ROOT/pages/8.0-release-notes.adoc | 28 +++++++++++++++++++ .../configuration/pagebreak_split_block.adoc | 7 +++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 5af99b20b7..6d6290756e 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -252,6 +252,34 @@ With the release of {productname} {release-version}, this issue has been resolve This change aligns better with modern standards and ensures that page breaks are now accurately rendered in exported documents. +=== The `pagebreak_split_block` option now defaults to `true`. When a page break is inserted, the resulting HTML output is: `
.` +// #TINY-12462 + +The default value for the `pagebreak_split_block` option has been changed from `false` to `true`. This change improves the user experience when inserting page breaks within block elements such as paragraphs, lists, or tables. When enabled: + +* Page breaks will automatically split the block element at the cursor position +* Content after the page break will be moved to a new block element of the same type +* The structure and formatting of the content is preserved on both sides of the page break + +For example, with this HTML content: + +[source,html] +---- +

First page

+---- + +When placing the cursor after the word "First" and inserting a page break, the result will be: + +[source,html] +---- +

First

+
+

page

+---- + +This behavior is now enabled by default, but can be disabled by setting `pagebreak_split_block: false` in the editor configuration. + +For more information on the `pagebreak_split_block` option, see xref:pagebreak.adoc#pagebreak_split_block[pagebreak_split_block]. [[removed]] == Removed diff --git a/modules/ROOT/partials/configuration/pagebreak_split_block.adoc b/modules/ROOT/partials/configuration/pagebreak_split_block.adoc index 574bfcd124..44bbcb2446 100644 --- a/modules/ROOT/partials/configuration/pagebreak_split_block.adoc +++ b/modules/ROOT/partials/configuration/pagebreak_split_block.adoc @@ -1,11 +1,11 @@ [[pagebreak_split_block]] == `+pagebreak_split_block+` -When enabled this option makes it easier to split block elements with a page break. +By default, page breaks automatically split block elements (such as paragraphs, lists, or tables) at the cursor position while preserving the structure and formatting of the content. This option can be used to disable this behavior by setting it to `false` if this is undesired. *Type:* `+Boolean+` -*Default value:* `+false+` +*Default value:* `+true+` *Possible values:* `+true+`, `+false+` @@ -13,10 +13,11 @@ When enabled this option makes it easier to split block elements with a page bre [source,js] ---- +// Disable the block splitting behavior tinymce.init({ selector: 'textarea', // change this value according to your HTML plugins: 'pagebreak', toolbar: 'pagebreak', - pagebreak_split_block: true + pagebreak_split_block: false }); ---- From 5b558b318744d91c0240a1faa8c20f572c90f7fc Mon Sep 17 00:00:00 2001 From: "CODE:AG" <57781325+abhinavgandham@users.noreply.github.com> Date: Tue, 15 Jul 2025 13:37:04 +1000 Subject: [PATCH 23/60] DOC-3147: Tooltips can now be closed by pressing the escape key. (#3785) Co-authored-by: Karl Kemister-Sheppard --- modules/ROOT/pages/8.0-release-notes.adoc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 6d6290756e..5a4a3609ee 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -203,6 +203,11 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a {productname} {release-version} also includes the following improvement: +=== Tooltips can now be closed by pressing the `escape` key. +// #TINY-12054 + +Prior to {release-version}, tooltips could not be dismissed using the keyboard, which posed an accessibility concern. As of {productname} {release-version}, tooltips can now be closed via the `escape` key, improving accessibility. + === Instructions on how to navigate the color swatch, image select and insert table widget are now announced by screen readers. // #TINY-12189 From 7bb1ac1eb9aa53b4cba78f75e9b0207439cb3269 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 13:38:21 +1000 Subject: [PATCH 24/60] DOC-3147: Long tooltips could overflow narrow browser windows. (#3769) --- modules/ROOT/pages/8.0-release-notes.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 5a4a3609ee..0d367424fe 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -371,6 +371,13 @@ Previously, there was an issue where combining strikethrough (`s` element) and f The fix ensures that the `s` element is now properly nested inside the font size element, improving visual consistency across browsers. +=== Long tooltips could overflow narrow browser windows +// #TINY-11884 + +Previously, long tooltips could overflow narrow browser windows, causing the tooltip text to be partially cut off and unreadable. This issue was most noticeable with the `...` ellipsis toolbar for the "reveal or hide additional toolbar options" button, where the tooltip text would not fit within the narrow viewport. + +In {productname} {release-version}, the tooltip behavior has been improved to ensure that long tooltips are properly positioned and wrapped within narrow browser windows. This prevents overflow and ensures that the full tooltip text is visible, even in smaller viewports. + [[security-fixes]] == Security fixes From bb8cc46e080f57cd43daf7d1df91853a1eaa79af Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 15:27:30 +1000 Subject: [PATCH 25/60] DOC-3147: Tab to create a new row in tables with a non-editable final row would freeze the editor. (#3768) * DOC-3147: Tab to create a new row in tables with a non-editable final row would freeze the editor. * Update modules/ROOT/pages/8.0-release-notes.adoc --- modules/ROOT/pages/8.0-release-notes.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 0d367424fe..84ae7f9112 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -378,6 +378,13 @@ Previously, long tooltips could overflow narrow browser windows, causing the too In {productname} {release-version}, the tooltip behavior has been improved to ensure that long tooltips are properly positioned and wrapped within narrow browser windows. This prevents overflow and ensures that the full tooltip text is visible, even in smaller viewports. +=== Tab to create a new row in tables with a non-editable final row would freeze the editor. +// #TINY-12018 + +Previously, when tabbing into a non-editable final row of a table, the editor failed to recognize that the row was read-only and instead duplicated it. This resulted in an attempt to place the cursor in the duplicated row, which again could not be edited. The process would repeat indefinitely, creating a loop that ultimately froze the editor. + +{productname} {release-version} resolves this issue by detecting when the final row of a table is read-only and preventing the insertion of a new row in such cases. This ensures stable behavior when navigating through tables using the Tab key. + [[security-fixes]] == Security fixes From 7c356cda2ceb76cf3ff5334e196154f9842b5686 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 15:29:56 +1000 Subject: [PATCH 26/60] DOC-3147: Nested font sizes no longer cause excessive line spacing. (#3761) * DOC-3147: Nested font sizes no longer cause excessive line spacing. * Update modules/ROOT/pages/8.0-release-notes.adoc --- modules/ROOT/pages/8.0-release-notes.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 84ae7f9112..4a485037af 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -385,6 +385,13 @@ Previously, when tabbing into a non-editable final row of a table, the editor fa {productname} {release-version} resolves this issue by detecting when the final row of a table is read-only and preventing the insertion of a new row in such cases. This ensures stable behavior when navigating through tables using the Tab key. +=== Nested font sizes no longer cause excessive line spacing +// #TINY-12073 + +Previously, applying different font sizes to nested elements could result in inconsistent and overly large line heights. This affected users by introducing visual clutter and making text blocks appear misaligned or difficult to read. + +{productname} {release-version} introduces a fix that ensures line heights are calculated based on the font size visible in the new line, rather than inheriting line-height from parent element. This means that when different font sizes are applied within the same content, the line heights will be consistent and proportional to the visible font size. + [[security-fixes]] == Security fixes From a541489dd0cb356a55766e2758cadbf979796cd9 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 15:34:22 +1000 Subject: [PATCH 27/60] DOC-3147: DomParser no longer tries to fix some nodes when parsed with a context, and Improved structure retention when inserting invalid HTML fragments. (#3779) --- modules/ROOT/pages/8.0-release-notes.adoc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 4a485037af..94a8aa547e 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -286,6 +286,14 @@ This behavior is now enabled by default, but can be disabled by setting `pagebre For more information on the `pagebreak_split_block` option, see xref:pagebreak.adoc#pagebreak_split_block[pagebreak_split_block]. +=== DomParser no longer tries to fix some nodes when parsed with a context +// #TINY-8205 + +Previously, the `DomParser` would attempt to fix invalid HTML structures when parsing with a context, such as when inserting content into a specific element. This behavior lead to unexpected results, especially when the structure was not valid in the context of the parent element. + +In {productname} {release-version}, the `DomParser` has been updated to no longer attempt to fix invalid nodes when parsing with a context. Instead, it will validate the nodes and only insert them if they are valid in the context of their parent element. If the nodes are invalid, they will not be inserted. + + [[removed]] == Removed @@ -392,6 +400,13 @@ Previously, applying different font sizes to nested elements could result in inc {productname} {release-version} introduces a fix that ensures line heights are calculated based on the font size visible in the new line, rather than inheriting line-height from parent element. This means that when different font sizes are applied within the same content, the line heights will be consistent and proportional to the visible font size. +=== Improved structure retention when inserting invalid HTML fragments +// #TINY-8205 + +Previously, when inserting HTML fragments through APIs or pasting, the parser would attempt to fix invalid structures, which could lead to the loss of valid structures like tables and lists. This behavior was inconsistent and could result in unexpected outcomes when handling complex HTML content. + +In {productname} {release-version}, the parser has been updated to improve the retention of structures when inserting HTML fragments. It now validates these fragments in the context of their parent structure, ensuring that valid structures are preserved even if the fragment contains invalid HTML resulting in more predictable and desirable outcomes when handling complex HTML content. + [[security-fixes]] == Security fixes From 38c93a6717e71a962bb2aac26c363fb1a26c2b21 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 15:45:55 +1000 Subject: [PATCH 28/60] DOC-3147: Input label for misspelled word was not announced by screen readers. (#3758) * DOC-3147: Input label for misspelled word was not announced by screen readers. * Update modules/ROOT/pages/8.0-release-notes.adoc --- modules/ROOT/pages/8.0-release-notes.adoc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 94a8aa547e..c812f70710 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -62,7 +62,12 @@ The following premium plugin updates were released alongside {productname} {rele The {productname} {release-version} includes an accompanying release of the **Spell Checker** premium plugin. -**Spell Checker** includes the following improvement. +**Spell Checker** includes the following improvements. + +==== Input label for misspelled word was not announced by screen readers. +// #TINY-12167 + +In previous versions, the Spell Checker dialog's misspelled word input field lacked proper accessibility labeling, preventing screen readers from announcing its purpose. {productname} {release-version} resolves this accessibility limitation by adding the appropriate label association between the "Misspelled Word" text and its input field. This enhancement allows screen readers to correctly identify and announce the input field's purpose, improving the spell checking experience for users who rely on assistive technologies. === Language code standardization to RFC5646/BCP47 format @@ -314,7 +319,6 @@ To improve API clarity and maintain a well-defined interface, the `documentBaseU [[bug-fixes]] == Bug fixes -{productname} {release-version} also includes the following bug fix: === Attempting to add a newline directly after a `block` element such as an image would cause an error. // #TINY-12045 From 9eb2bdc72b40cbbd8fa390bfcc011e62878ac268 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 21:18:51 +1000 Subject: [PATCH 29/60] DOC-3147: Content marked with lang attributes was sometimes not spellchecked correctly. (#3777) --- modules/ROOT/pages/8.0-release-notes.adoc | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index c812f70710..e59af27842 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -60,9 +60,18 @@ The following premium plugin updates were released alongside {productname} {rele === Spell Checker -The {productname} {release-version} includes an accompanying release of the **Spell Checker** premium plugin. +The {productname} {release-version} release includes an accompanying release of the **Spell Checker** premium plugin. -**Spell Checker** includes the following improvements. +**Spell Checker** Premium plugin includes the following fix and improvements. + +=== Content marked with `lang` attributes was sometimes not spellchecked correctly. +// #TINY-12101 + +Previously, the spellchecker did not consistently handle content marked with different `lang` attributes, particularly when the language codes used different formats. This inconsistency led to missed spellchecking for words in spans that used alternate casing or separator conventions (e.g., `en-GB` vs `en_GB`). + +This issue was introduced in {productname} 6.4, where documents containing a mix of language codes using different formats would not be reliably spellchecked. As a result, misspelled words in spans using alternate casing or separator conventions were not detected, even though they functioned as expected in version 6.3. + +In {release-version}, support for mixed-case and mixed-format language codes has been restored. The spellchecker now correctly identifies and handles variations in language attribute formatting, ensuring that content is reliably checked regardless of code style. This improvement enables accurate spellchecking for documents that include multiple languages and diverse regional conventions. ==== Input label for misspelled word was not announced by screen readers. // #TINY-12167 @@ -70,6 +79,7 @@ The {productname} {release-version} includes an accompanying release of the **Sp In previous versions, the Spell Checker dialog's misspelled word input field lacked proper accessibility labeling, preventing screen readers from announcing its purpose. {productname} {release-version} resolves this accessibility limitation by adding the appropriate label association between the "Misspelled Word" text and its input field. This enhancement allows screen readers to correctly identify and announce the input field's purpose, improving the spell checking experience for users who rely on assistive technologies. === Language code standardization to RFC5646/BCP47 format +// #TINY-12090 The {productname} {release-version} release introduces standardized support for language codes using the RFC5646 (also known as BCP47) format. This update applies to all language-related configurations, including: From 7ce213d3879c71fffcf08d8dfb086f1520de7bec Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 21:24:00 +1000 Subject: [PATCH 30/60] DOC-3147: Codesample dialog would not disable spellcheck as expected. (#3767) * DOC-3147: Codesample dialog would not disable spellcheck as expected. * Update modules/ROOT/pages/8.0-release-notes.adoc --- modules/ROOT/pages/8.0-release-notes.adoc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index e59af27842..dff80962e6 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -329,6 +329,14 @@ To improve API clarity and maintain a well-defined interface, the `documentBaseU [[bug-fixes]] == Bug fixes +{productname} {release-version} also includes the following bug fixes: + +=== Codesample dialog would not disable spellcheck as expected. +// #TINY-12120 + +Previously, the `browser_spellcheck` setting did not correctly disable spellchecking in the Codesample dialog's text area. This was because the setting was applied to the dialog’s text area rather than the main editor instance. + +In addition, the `advcode` and `code` plugin dialogs did not explicitly disable browser-based spellchecking. As a result, red underlines appeared unnecessarily in code content, regardless of the `browser_spellcheck` setting. === Attempting to add a newline directly after a `block` element such as an image would cause an error. // #TINY-12045 From c0f88ff6aa4f9e2d1ea1207fca5ec64f241295d2 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 21:28:00 +1000 Subject: [PATCH 31/60] DOC-3147: New list_max_depth option to limit list indentation. (#3766) * DOC-3147: New list_max_depth option to limit list indentation. * Update modules/ROOT/partials/configuration/list_max_depth.adoc * Update modules/ROOT/pages/8.0-release-notes.adoc --- modules/ROOT/pages/8.0-release-notes.adoc | 29 +++++++++++++++++++ .../ROOT/pages/user-formatting-options.adoc | 2 ++ .../configuration/list_max_depth.adoc | 24 +++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 modules/ROOT/partials/configuration/list_max_depth.adoc diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index dff80962e6..9d4b6944f1 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -237,6 +237,35 @@ In previous versions of {productname}, the editor's resize handle lacked a `role In {productname} {release-version}, the resize handle now includes a `role` seperator and an `aria-valuetext` attribute that dynamically reflects the current dimensions of the editor. These improvements enhance accessibility and ensure more accurate announcements by screen readers. +=== New `list_max_depth` option to limit list indentation +// #TINY-11937 + +{productname} {release-version} introduced a new `list_max_depth` option that allows configuration of the maximum indent depth for list items. This setting accepts a non-negative integer value, where `0` permits list creation without any indentation, and higher values set the maximum allowable indent depth. Negative values are invalid and will trigger an error. When the option is not set, list behavior remains unchanged. + +The setting applies only to list indentation and does not affect paragraph indentation. Existing content is not altered, and pasted lists that exceed the maximum indent depth will retain their structure but cannot be further indented. When multiple list items are selected, only items eligible for indentation will be indented individually—validation is applied per item, not across the full selection. + +Outdent functionality remains unaffected and always available. The state of indent and outdent controls reflects the current indentation capabilities based on this setting. + +==== Example configuration + +The following example shows a basic configuration for the `list_max_depth` option, which limits list indentation to a maximum of 2 levels: + +[source,js] +---- +tinymce.init({ + selector: "textarea", + plugins: [ + "advlist", "anchor", "autolink", "charmap", "code", "fullscreen", + "help", "image", "insertdatetime", "link", "lists", "media", + "preview", "searchreplace", "table", "visualblocks", + ], + list_max_depth: 2, + toolbar: "undo redo | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image", +}); +---- + +For more information, see: xref:user-formatting-options.adoc#list_max_depth[User formatting - List max depth]. + === The translate API now automatically replaces three dots in a row with an ellipsis character. // #TINY-12155 diff --git a/modules/ROOT/pages/user-formatting-options.adoc b/modules/ROOT/pages/user-formatting-options.adoc index f1cb37ecb5..14bfd0b74a 100644 --- a/modules/ROOT/pages/user-formatting-options.adoc +++ b/modules/ROOT/pages/user-formatting-options.adoc @@ -25,3 +25,5 @@ include::partial$configuration/style_formats_autohide.adoc[] include::partial$configuration/style_formats_merge.adoc[] include::partial$configuration/text_color.adoc[] + +include::partial$configuration/list_max_depth.adoc[] diff --git a/modules/ROOT/partials/configuration/list_max_depth.adoc b/modules/ROOT/partials/configuration/list_max_depth.adoc new file mode 100644 index 0000000000..3bb2ea916c --- /dev/null +++ b/modules/ROOT/partials/configuration/list_max_depth.adoc @@ -0,0 +1,24 @@ +[[list_max_depth]] +== `list_max_depth` + +The `list_max_depth` option sets the maximum nesting depth for lists (ordered and unordered). + +*Type:* `Number` + +*Default value:* No limit + +=== Required plugins + +This option requires the `lists` plugin to be enabled. + +=== Example + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'lists', + toolbar: 'bullist numlist', + list_max_depth: 2 // limits list nesting to maximum of 2 levels +}); +---- From 58bdbe2015f446195f33a564ffeb2aec205ee13f Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 21:28:17 +1000 Subject: [PATCH 32/60] DOC-12102: New list item was not inserted correctly when existing list item had a block element inside. (#3759) --- modules/ROOT/pages/8.0-release-notes.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 9d4b6944f1..6f1076ac3f 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -458,6 +458,13 @@ Previously, when inserting HTML fragments through APIs or pasting, the parser wo In {productname} {release-version}, the parser has been updated to improve the retention of structures when inserting HTML fragments. It now validates these fragments in the context of their parent structure, ensuring that valid structures are preserved even if the fragment contains invalid HTML resulting in more predictable and desirable outcomes when handling complex HTML content. +=== New list item was not inserted correctly when existing list item had a block element inside +// #TINY-12102 + +{productname} {release-version} resolves an issue affecting list management when parent list items contain block-level formatting. Previously, when a list item containing a sub-list was formatted as a block element (such as `

` or `

`), pressing Enter at the end of that item would incorrectly position the new list item alongside the sub-list items instead of as a sibling of the parent item. + +{productname} {release-version} addresses this by ensuring that when a user presses Enter at the end of a list item that contains block-level formatting, the new list item is correctly inserted as a sibling of the parent list item, rather than being placed incorrectly alongside the sub-list items. + [[security-fixes]] == Security fixes From 0a410d7a4b23a6ce487fdcea5c81e456d70b1e51 Mon Sep 17 00:00:00 2001 From: "CODE:AG" <57781325+abhinavgandham@users.noreply.github.com> Date: Tue, 15 Jul 2025 21:33:46 +1000 Subject: [PATCH 33/60] DOC-3147: Cutting a whole HTML element would add an empty paragraph. (#3756) Co-authored-by: Karl Kemister-Sheppard --- modules/ROOT/pages/8.0-release-notes.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 6f1076ac3f..3e93bc28b8 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -360,6 +360,13 @@ To improve API clarity and maintain a well-defined interface, the `documentBaseU {productname} {release-version} also includes the following bug fixes: +=== Cutting a whole HTML element would add an empty paragraph. +// #TINY-12171 + +Previously, an issue was identified where cutting an entire block element, such as a `div` or `p` HTML element, resulted in the block being replaced by an empty paragraph. This behavior only occurred for blocks not contained within tables and led to inconsistent outcomes where cutting content inside tables behaved differently from outside. Additionally, the behavior diverged from that of the backspace `delete` operation. + +{productname} {release-version} resolves this issue by unifying the behavior for content both inside and outside tables. The updated implementation aligns cutting behavior with that of the backspace `delete` operation, ensuring a more consistent and predictable editing experience. + === Codesample dialog would not disable spellcheck as expected. // #TINY-12120 From 5c4c0f052de14a5904b28ce2ae14b3fc594754fb Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 21:43:44 +1000 Subject: [PATCH 34/60] DOC-3147: Focus is now restored to a dialog after closing an alert, confirmation or another dialog (#3751) * DOC-3147: Focus is now restored to a dialog after closing an alert, confirmation or another dialog. * Update modules/ROOT/pages/8.0-release-notes.adoc Co-authored-by: Zuzanna Tomaszyk <91727075+ztomaszyk@users.noreply.github.com> --------- Co-authored-by: Zuzanna Tomaszyk <91727075+ztomaszyk@users.noreply.github.com> --- modules/ROOT/pages/8.0-release-notes.adoc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 3e93bc28b8..f1b9d0206f 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -237,6 +237,15 @@ In previous versions of {productname}, the editor's resize handle lacked a `role In {productname} {release-version}, the resize handle now includes a `role` seperator and an `aria-valuetext` attribute that dynamically reflects the current dimensions of the editor. These improvements enhance accessibility and ensure more accurate announcements by screen readers. +=== Focus is now restored to a dialog after closing an alert, confirmation or another dialog +// #TINY-12038 + +Previously, when a dialog was opened from within another dialog — such as a file picker triggered via a `file_picker_callback` the focus was not correctly restored to the original dialog after closing the secondary one. This issue also affected alert and confirmation dialogs opened from within a parent dialog. + +As a result, keyboard users experienced disrupted navigation and loss of focus context, impairing accessibility and usability in multi-dialog workflows. + +In {release-version}, {productname} now restores focus to the triggering button in the parent dialog once the nested dialog is closed. This improvement enhances keyboard navigation and accessibility in scenarios involving multiple overlapping dialogs. + === New `list_max_depth` option to limit list indentation // #TINY-11937 From cc54ef6e71d11ba8ac618d0c773a8ec585c03628 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 21:50:17 +1000 Subject: [PATCH 35/60] DOC-3147: The ToggleToolbarDrawer command's skipFocus option has been deprecated. (#3748) --- modules/ROOT/pages/8.0-release-notes.adoc | 34 +++++++++++++++++++ .../pages/editor-command-identifiers.adoc | 6 ++-- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index f1b9d0206f..e6fbac7603 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -275,6 +275,19 @@ tinymce.init({ For more information, see: xref:user-formatting-options.adoc#list_max_depth[User formatting - List max depth]. +=== Added support for `skip_focus` option in ToggleToolbarDrawer command +// #TINY-12044 + +The `ToggleToolbarDrawer` command now supports the standard `skip_focus` option, which allows opening the toolbar drawer without focusing the editor. This provides consistent behavior with other editor commands. + +.Updated new `skip_focus` option usage command +[source] +---- +editor.execCommand('ToggleToolbarDrawer', false, null, { skip_focus: true }); +---- + +For more information on the `ToggleToolbarDrawer` command, see: xref:editor-command-identifiers.adoc[Available Commands]. + === The translate API now automatically replaces three dots in a row with an ellipsis character. // #TINY-12155 @@ -518,6 +531,27 @@ For information about setting up containerized server-side components using Dock // CCFR here. +=== The `ToggleToolbarDrawer` command's `skipFocus` option has been deprecated +// #TINY-12044 + +The `ToggleToolbarDrawer` command previously accepted a non-standard `skipFocus` option to prevent the editor from receiving focus when the command was executed. This behavior differed from other editor commands, which use the generic `skip_focus` option for the same purpose. As a result, the inconsistency lead to confusion when implementing or maintaining command logic. + +To resolve this, support for the standard `skip_focus` option has been added to the `ToggleToolbarDrawer` command. The `skipFocus` option is now **deprecated** in {productname} {release-version} and will be removed in a future release. + +.Before deprecation using the `skipFocus` option +[source] +---- +editor.execCommand('ToggleToolbarDrawer', false, { skipFocus: true }); +---- + +.After deprecation using the `skip_focus` option +[source] +---- +editor.execCommand('ToggleToolbarDrawer', false, null, { skip_focus: true }); +---- + +This change improves consistency across commands and aligns with expected usage patterns in {productname} {release-version}. + === Deprecated `editor.selection.setContent` API // TINY-11692 diff --git a/modules/ROOT/pages/editor-command-identifiers.adoc b/modules/ROOT/pages/editor-command-identifiers.adoc index c304ab5bb1..134b326630 100644 --- a/modules/ROOT/pages/editor-command-identifiers.adoc +++ b/modules/ROOT/pages/editor-command-identifiers.adoc @@ -155,7 +155,7 @@ The commands in the following table are provided by the {productname} editor and |mceTogglePlainTextPaste |Toggles paste as plain text. |mceToggleVisualAid |Toggles the visual aids for: tables without borders and anchors. |ToggleSidebar |Closes the current sidebar, or toggles the sidebar if the sidebar name is provided as a value (`__`). -|ToggleToolbarDrawer |Toggles the Toolbar Drawer. For information on toolbars, see: xref:toolbar-configuration-options.adoc#toolbar[User interface options - Toolbar]. +|ToggleToolbarDrawer |Toggles the Toolbar Drawer. Can be used with the `skip_focus` option to prevent focusing the editor. For information on toolbars, see: xref:toolbar-configuration-options.adoc#toolbar[User interface options - Toolbar]. |=== .Examples @@ -199,7 +199,7 @@ tinymce.activeEditor.execCommand('mceTogglePlainTextPaste'); tinymce.activeEditor.execCommand('mceToggleVisualAid'); tinymce.activeEditor.execCommand('ToggleSidebar'); /* OR */ tinymce.activeEditor.execCommand('ToggleSidebar', false, ''); -tinymce.activeEditor.execCommand('ToggleToolbarDrawer'); +tinymce.activeEditor.execCommand('ToggleToolbarDrawer', false, null, { skip_focus: true }); ---- [[core-table-commands]] @@ -614,7 +614,7 @@ The following command states can be queried using the xref:apis/tinymce.editor.a |Strikethrough |Returns `+true+` if the content is formatted using the same markup as the {productname} `+Strikethrough+` command. |Subscript |Returns `+true+` if the content is formatted using the same markup as the {productname} `+Subscript+` command. |Superscript |Returns `+true+` if the content is formatted using the same markup as the {productname} `+Superscript+` command. -|ToggleToolbarDrawer |Returns `+true+` if the Toolbar Drawer is open. The state can be controlled by the {productname} `+ToggleToolbarDrawer+` command. +|ToggleToolbarDrawer |Returns `+true+` if the Toolbar Drawer is open. The state can be controlled by the {productname} `+ToggleToolbarDrawer+` command. When controlling the state, use the `skip_focus` option (recommended) instead of the deprecated `skipFocus` option. |Underline |Returns `+true+` if the content is formatted using the same markup as the {productname} `+Underline+` command. |=== From 1523ad60a6c20580f94286952078ead570f1aadb Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 21:53:10 +1000 Subject: [PATCH 36/60] DOC-3147: Removed unused Mentions plugin stylesheet. (#3747) --- modules/ROOT/pages/8.0-release-notes.adoc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index e6fbac7603..d19e002174 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -58,6 +58,21 @@ The following premium plugin updates were released alongside {productname} {rele // For information on the **** plugin, see: xref:.adoc[]. +=== Mentions + +The {productname} {release-version} release includes an accompanying release of the **Mentions** premium plugin. + +**Mentions** Premium plugin includes the following removal. + +=== Removed unused Mentions plugin stylesheet + +In {release-version}, the unused `mentions.css` file was removed from the **Mentions** plugin. In earlier versions (such as 7.9), this empty CSS file was still being loaded, despite its contents having been moved to the Oxide theme in a prior update. This change ensures cleaner resource loading and avoids unnecessary network requests. + +[NOTE] +The removal does not impact plugin functionality and applies to all editor modes. + +For information on the **Mentions** plugin, see: xref:mentions.adoc[Mentions]. + === Spell Checker The {productname} {release-version} release includes an accompanying release of the **Spell Checker** premium plugin. From 14ad4abac07204a95cc03f2fea31b17d91471a1c Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 21:56:48 +1000 Subject: [PATCH 37/60] DOC-3147: Mentions username not updating with skin changes in dark mode. (#3746) --- modules/ROOT/pages/8.0-release-notes.adoc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index d19e002174..90f36be543 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -62,7 +62,13 @@ The following premium plugin updates were released alongside {productname} {rele The {productname} {release-version} release includes an accompanying release of the **Mentions** premium plugin. -**Mentions** Premium plugin includes the following removal. +**Mentions** Premium plugin includes the following fix and removal. + +=== Mentions username not updating with skin changes in dark mode + +Previously, the username displayed on the mentions card did not update correctly when switching between skins, particularly in dark mode. This issue caused the username to become invisible against the dark background, making it difficult for users to read. + +To resolve this, the styling for the username has been updated. The class now uses the `@text-color` variable for its default styling, ensuring that it inherits the correct color from its parent element when the item is active. This change guarantees that the username remains visible and readable in both light and dark themes. === Removed unused Mentions plugin stylesheet From 653adef8c045d5c4db7760d9e294ce3eee855405 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 15 Jul 2025 22:02:23 +1000 Subject: [PATCH 38/60] DOC-3147: Removed unused `css/tinycomments.css` and `css/tinycomments.js` files. (#3745) * DOC-3147: Removed unused css/tinycomments.css and css/tinycomments.js files. * minor copy edits. * Update modules/ROOT/pages/8.0-release-notes.adoc --- modules/ROOT/pages/8.0-release-notes.adoc | 13 +++++++++++++ modules/ROOT/pages/tiny-docs-ai.adoc | 0 2 files changed, 13 insertions(+) create mode 100644 modules/ROOT/pages/tiny-docs-ai.adoc diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 90f36be543..2df68fc5f9 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -199,6 +199,19 @@ When users pasted content from Microsoft Word documents containing lists styled For information on the **PowerPaste** plugin, see: xref:introduction-to-powerpaste.adoc[PowerPaste]. +=== Comments + +The {productname} {release-version} release includes an accompanying release of the **Comments** premium plugin. + +**Comments** Premium plugin includes the following removal. + +==== Removed unused Comments stylesheet +// #TINY-11287 + +In {release-version}, the unused `tinycomments.css` file was removed from the **Comments** plugin. In earlier versions (such as 7.9), this empty CSS file was still being loaded, despite its contents having been moved to the Oxide theme in a prior update. This change ensures cleaner resource loading and avoids unnecessary network requests. + +For information on the **Comments** plugin, see: xref:introduction-to-tiny-comments.adoc[Introduction to Tiny Comments]. + [[accompanying-premium-plugin-end-of-life-announcement]] == Accompanying Premium plugin end-of-life announcement diff --git a/modules/ROOT/pages/tiny-docs-ai.adoc b/modules/ROOT/pages/tiny-docs-ai.adoc new file mode 100644 index 0000000000..e69de29bb2 From 0702ff627b0d49a1ae0185ffe29b9e49137adb84 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Wed, 16 Jul 2025 10:34:36 +1000 Subject: [PATCH 39/60] DOC-3147: Discontinue advertised support for Medical English (UK) in TinyMCE features. (#3742) --- modules/ROOT/examples/live-demos/spellchecker/index.js | 1 - .../ROOT/partials/configuration/spellchecker_languages.adoc | 4 ++-- modules/ROOT/partials/misc/spellchecker-languages.adoc | 1 - modules/ROOT/partials/plugins/spellchecker-content_langs.adoc | 1 - 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/ROOT/examples/live-demos/spellchecker/index.js b/modules/ROOT/examples/live-demos/spellchecker/index.js index 7769778230..b3b3d0f3cb 100644 --- a/modules/ROOT/examples/live-demos/spellchecker/index.js +++ b/modules/ROOT/examples/live-demos/spellchecker/index.js @@ -11,7 +11,6 @@ tinymce.init({ { title: 'English (United Kingdom)', code: 'en-GB' }, { title: 'English (United States)', code: 'en-US' }, { title: 'Medical English (US)', code: 'en-US', customCode: 'en-US-medical' }, - { title: 'Medical English (UK)', code: 'en-GB', customCode: 'en-GB-medical' }, { title: 'Danish', code: 'da' }, { title: 'Dutch', code: 'nl-NL' }, { title: 'Finnish', code: 'fi' }, diff --git a/modules/ROOT/partials/configuration/spellchecker_languages.adoc b/modules/ROOT/partials/configuration/spellchecker_languages.adoc index c99335297c..d366506b6d 100644 --- a/modules/ROOT/partials/configuration/spellchecker_languages.adoc +++ b/modules/ROOT/partials/configuration/spellchecker_languages.adoc @@ -8,7 +8,7 @@ This option specifies the spellchecker languages that are available to the user, *Default value:* [source,js] ---- -'English (United States)=en-US,English (United Kingdom)=en-GB,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Norwegian Bokmål=nb-NO,Norwegian Nynorsk=nn,Brazilian Portuguese=pt-BR,Portuguese=pt,Portuguese (Portugal)=pt-PT,Spanish=es,Swedish=sv,Swedish (Finland)=sv-FI,Afrikaans (South Africa)=af-ZA,English (Australia)=en-AU,English (Canada)=en-CA,English (United Kingdom)=en-GB,English (United States)=en-US,Medical English (US)=en-US-medical,Medical English (UK)=en-GB-medical,Maori (New Zealand)=mi-NZ' +'English (United States)=en-US,English (United Kingdom)=en-GB,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Norwegian Bokmål=nb-NO,Norwegian Nynorsk=nn,Brazilian Portuguese=pt-BR,Portuguese=pt,Portuguese (Portugal)=pt-PT,Spanish=es,Swedish=sv,Swedish (Finland)=sv-FI,Afrikaans (South Africa)=af-ZA,English (Australia)=en-AU,English (Canada)=en-CA,English (United Kingdom)=en-GB,English (United States)=en-US,Medical English (US)=en-US-medical,Maori (New Zealand)=mi-NZ' ---- @@ -19,6 +19,6 @@ This option specifies the spellchecker languages that are available to the user, tinymce.init({ selector: 'textarea', plugins: 'tinymcespellchecker', - spellchecker_languages: 'US English=en-US,UK English=en-GB,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Norwegian Bokmål=nb-NO,Norwegian Nynorsk=nn,Brazilian Portuguese=pt-BR,Portuguese=pt,Portuguese (Portugal)=pt-PT,Spanish=es,Swedish=sv,Swedish (Finland)=sv-FI,Afrikaans (South Africa)=af-ZA,English (Australia)=en-AU,English (Canada)=en-CA,English (United Kingdom)=en-GB,English (United States)=en-US,Medical English (US)=en-US-medical,Medical English (UK)=en-GB-medical,Maori (New Zealand)=mi-NZ' + spellchecker_languages: 'US English=en-US,UK English=en-GB,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Norwegian Bokmål=nb-NO,Norwegian Nynorsk=nn,Brazilian Portuguese=pt-BR,Portuguese=pt,Portuguese (Portugal)=pt-PT,Spanish=es,Swedish=sv,Swedish (Finland)=sv-FI,Afrikaans (South Africa)=af-ZA,English (Australia)=en-AU,English (Canada)=en-CA,English (United Kingdom)=en-GB,English (United States)=en-US,Medical English (US)=en-US-medical,Maori (New Zealand)=mi-NZ' }); ---- \ No newline at end of file diff --git a/modules/ROOT/partials/misc/spellchecker-languages.adoc b/modules/ROOT/partials/misc/spellchecker-languages.adoc index 9646c60be1..707b30d592 100644 --- a/modules/ROOT/partials/misc/spellchecker-languages.adoc +++ b/modules/ROOT/partials/misc/spellchecker-languages.adoc @@ -12,7 +12,6 @@ The following languages are supported for the Spell Checker plugin. All of the l |English (United Kingdom) |en-GB, en-UK, en-BR |{tick} |{tick} |English (United States) |en, en-US |{tick} |{tick} |Medical English (US) |en-medical, en-US-medical |{tick} |{tick} -|Medical English (UK) |en-GB-medical |{tick} |{cross} |Danish |da |{tick} |{tick} |Dutch |nl, nl-NL |{tick} |{tick} |Finnish |fi |{tick} |{cross} diff --git a/modules/ROOT/partials/plugins/spellchecker-content_langs.adoc b/modules/ROOT/partials/plugins/spellchecker-content_langs.adoc index 25de405a34..8109297d3d 100644 --- a/modules/ROOT/partials/plugins/spellchecker-content_langs.adoc +++ b/modules/ROOT/partials/plugins/spellchecker-content_langs.adoc @@ -28,7 +28,6 @@ tinymce.init({ { title: 'English (United Kingdom)', code: 'en-GB' }, { title: 'English (United States)', code: 'en-US' }, { title: 'Medical English (US)', code: 'en-US', customCode: 'en-US-medical' }, - { title: 'Medical English (UK)', code: 'en-GB', customCode: 'en-GB-medical' }, { title: 'Danish', code: 'da' }, { title: 'Dutch', code: 'nl-NL' }, { title: 'Finnish', code: 'fi' }, From b8b510a560368344ea790d2c7a09a32490871aa8 Mon Sep 17 00:00:00 2001 From: "CODE:AG" <57781325+abhinavgandham@users.noreply.github.com> Date: Wed, 16 Jul 2025 10:42:33 +1000 Subject: [PATCH 40/60] DOC-3147: Tabbing when a was selected didn't move the selection on the `figcaption` correctly. (#3776) * DOC-3147: Tabbing when a was selected didn't move the selection on the correctly. * Update modules/ROOT/pages/8.0-release-notes.adoc * Update modules/ROOT/pages/8.0-release-notes.adoc --------- Co-authored-by: Karl Kemister-Sheppard --- modules/ROOT/pages/8.0-release-notes.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 2df68fc5f9..5b5a2e0c5d 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -416,6 +416,13 @@ To improve API clarity and maintain a well-defined interface, the `documentBaseU {productname} {release-version} also includes the following bug fixes: +=== Tabbing when a `figure` was selected didn't move the selection to the `figcaption` correctly. +// #TINY-11753 + +Previously, the `tab` key did not correctly handle nested components. Specifically, when a `CET` (Content Editable True) element was placed inside a `CEF` (Content Editable False) element such as a `figcaption`, focus behavior was unintuitive. This led to inconsistent and confusing keyboard navigation when interacting with editable nested elements like a `figcaption`. + +{productname} {release-version} addresses this issue by ensuring that pressing the `tab` key correctly moves focus to the `CET` element when it is nested within a `CEF` element. This ensures smooth and predictable keyboard navigation for nested editable elements such as a `figcaption`. + === Cutting a whole HTML element would add an empty paragraph. // #TINY-12171 From e208e3aa1c6ff155e828c1fa5ed563f958b27f11 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Thu, 17 Jul 2025 11:00:23 +1000 Subject: [PATCH 41/60] Revert "DOC-3147: Default value for `pagebreak_separator` option to better suit modern standards. (#3780)" This reverts commit b2a8207afe7b708315ff2114dffb1231995b8e34. --- modules/ROOT/pages/8.0-release-notes.adoc | 13 +++---------- .../partials/configuration/pagebreak_separator.adoc | 4 ++-- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 5b5a2e0c5d..add7f14f05 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -345,17 +345,10 @@ Comments containing HTML-like content are removed from the editor's content by d {productname} {release-version} also includes the following change: -=== Changed the default value for the `pagebreak_separator` option. -// #TINY-12013 - -In previous versions of {productname}, inserting a page break in the editor did not translate correctly when exporting using the xref:exportpdf.adoc[Export to PDF] plugin. Similarly, the xref:exportword.adoc[Export to Word] plugin also failed to preserve page breaks in the exported documents. As a result, exported files lacked the intended page breaks, leading to confusing output for users. - -With the release of {productname} {release-version}, this issue has been resolved by updating the default HTML value of the `pagebreak_separator` option: - -* **Old value** – `''` -* **New value** – `'
'` +// === +// #TINY-vwxyz1 -This change aligns better with modern standards and ensures that page breaks are now accurately rendered in exported documents. +// CCFR here. === The `pagebreak_split_block` option now defaults to `true`. When a page break is inserted, the resulting HTML output is: `
.` // #TINY-12462 diff --git a/modules/ROOT/partials/configuration/pagebreak_separator.adoc b/modules/ROOT/partials/configuration/pagebreak_separator.adoc index 5ba3a93393..e5624ca5cf 100644 --- a/modules/ROOT/partials/configuration/pagebreak_separator.adoc +++ b/modules/ROOT/partials/configuration/pagebreak_separator.adoc @@ -3,7 +3,7 @@ *Type:* `+String+` -*Default value:* `+'
'+` +*Default value:* `+''+` === Example: using `+pagebreak_separator+` @@ -13,6 +13,6 @@ tinymce.init({ selector: 'textarea', // change this value according to your HTML plugins: 'pagebreak', toolbar: 'pagebreak', - pagebreak_separator: '
My page break
' + pagebreak_separator: '' }); ---- From 85fff296151bc091a40d5bb6ba4dfb6fbaa32728 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Thu, 17 Jul 2025 11:00:52 +1000 Subject: [PATCH 42/60] Revert "DOC-3147: The default value of `pagebreak_split_block` is now `true` to match the new `pagebreak_separator` default. (#3795)" This reverts commit 7ad29fdfc1678bf87e8181f9a233a354f408aa65. --- modules/ROOT/pages/8.0-release-notes.adoc | 28 ------------------- .../configuration/pagebreak_split_block.adoc | 7 ++--- 2 files changed, 3 insertions(+), 32 deletions(-) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index add7f14f05..f2474dd9b6 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -350,34 +350,6 @@ Comments containing HTML-like content are removed from the editor's content by d // CCFR here. -=== The `pagebreak_split_block` option now defaults to `true`. When a page break is inserted, the resulting HTML output is: `
.` -// #TINY-12462 - -The default value for the `pagebreak_split_block` option has been changed from `false` to `true`. This change improves the user experience when inserting page breaks within block elements such as paragraphs, lists, or tables. When enabled: - -* Page breaks will automatically split the block element at the cursor position -* Content after the page break will be moved to a new block element of the same type -* The structure and formatting of the content is preserved on both sides of the page break - -For example, with this HTML content: - -[source,html] ----- -

First page

----- - -When placing the cursor after the word "First" and inserting a page break, the result will be: - -[source,html] ----- -

First

-
-

page

----- - -This behavior is now enabled by default, but can be disabled by setting `pagebreak_split_block: false` in the editor configuration. - -For more information on the `pagebreak_split_block` option, see xref:pagebreak.adoc#pagebreak_split_block[pagebreak_split_block]. === DomParser no longer tries to fix some nodes when parsed with a context // #TINY-8205 diff --git a/modules/ROOT/partials/configuration/pagebreak_split_block.adoc b/modules/ROOT/partials/configuration/pagebreak_split_block.adoc index 44bbcb2446..574bfcd124 100644 --- a/modules/ROOT/partials/configuration/pagebreak_split_block.adoc +++ b/modules/ROOT/partials/configuration/pagebreak_split_block.adoc @@ -1,11 +1,11 @@ [[pagebreak_split_block]] == `+pagebreak_split_block+` -By default, page breaks automatically split block elements (such as paragraphs, lists, or tables) at the cursor position while preserving the structure and formatting of the content. This option can be used to disable this behavior by setting it to `false` if this is undesired. +When enabled this option makes it easier to split block elements with a page break. *Type:* `+Boolean+` -*Default value:* `+true+` +*Default value:* `+false+` *Possible values:* `+true+`, `+false+` @@ -13,11 +13,10 @@ By default, page breaks automatically split block elements (such as paragraphs, [source,js] ---- -// Disable the block splitting behavior tinymce.init({ selector: 'textarea', // change this value according to your HTML plugins: 'pagebreak', toolbar: 'pagebreak', - pagebreak_split_block: false + pagebreak_split_block: true }); ---- From b60934cf9bc9222c55c99239147d0a801c010aa0 Mon Sep 17 00:00:00 2001 From: "Arvin(Jintao) Han" <20640097+ArvinJ-H@users.noreply.github.com> Date: Fri, 18 Jul 2025 15:51:02 +1000 Subject: [PATCH 43/60] DOC-3147: Updated documentation related to a11y (#3799) * DOC-3147: Add I1 url * DOC-3147: Update accessibility documentation: Adjust alt text length limit to 150 characters, enhance descriptions for decorative images, and clarify filtering behavior for empty alt attributes. * Update modules/ROOT/partials/a11y-rules/i1.adoc Co-authored-by: Karl Kemister-Sheppard * Update modules/ROOT/partials/a11y-rules/i3.adoc * Apply suggestion from @ArvinJ-H --------- Co-authored-by: Karl Kemister-Sheppard --- modules/ROOT/pages/8.0-release-notes.adoc | 2 +- modules/ROOT/partials/a11y-rules/i1.adoc | 4 ++- modules/ROOT/partials/a11y-rules/i3.adoc | 4 ++- .../configuration/a11y_advanced_options.adoc | 2 +- .../a11ychecker_allow_decorative_images.adoc | 31 ++++++++++++------- .../a11ychecker_filter_issue.adoc | 2 +- 6 files changed, 29 insertions(+), 16 deletions(-) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index f2474dd9b6..c2264569bb 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -169,7 +169,7 @@ The {productname} {release-version} introduces four new image accessibility rule * *xref:a11ychecker.adoc#I1[I1: Mixed Signals & Decorative Policy]*: Flags images with conflicting accessibility indicators (e.g., `alt` with `role="presentation"`) and ensures decorative images comply with best practices. * *xref:a11ychecker.adoc#I2[I2: Alt Attribute Requirement]*: Enforces the presence of the `alt` attribute on all `` elements, regardless of other labeling mechanisms like `aria-label`, `aria-labelledby`, or `title`. * *xref:a11ychecker.adoc#I3[I3: Filename Detection]*: Warns when `alt` text appears to be a filename (e.g., `image123.jpg`), including cases with URL encoding. -* *xref:a11ychecker.adoc#I4[I4: Alt Text Length]*: Detects `alt` text that exceeds a configurable maximum length, promoting concise descriptions. The default limit is 100 characters and can be adjusted using the new xref:a11ychecker.adoc#a11ychecker_alt_text_max_length[`a11ychecker_alt_text_max_length`] setting. +* *xref:a11ychecker.adoc#I4[I4: Alt Text Length]*: Detects `alt` text that exceeds a configurable maximum length, promoting concise descriptions. The default limit is 150 characters and can be adjusted using the new xref:a11ychecker.adoc#a11ychecker_alt_text_max_length[`a11ychecker_alt_text_max_length`] setting. Additional improvements include a rule precedence system to avoid duplicate violations, centralized image intent detection (e.g., decorative, informative, mixed signals, incomplete), and more readable user-facing messages. Technical terminology such as "alternative text" has been replaced with "text description," and repair instructions are now more contextual and user-friendly. diff --git a/modules/ROOT/partials/a11y-rules/i1.adoc b/modules/ROOT/partials/a11y-rules/i1.adoc index 18b4a7242a..5e30c264db 100644 --- a/modules/ROOT/partials/a11y-rules/i1.adoc +++ b/modules/ROOT/partials/a11y-rules/i1.adoc @@ -11,7 +11,9 @@ https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Lev xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/general/G95.html[G95 - Providing short text alternatives that provide a brief description of the non-text content]. +WCAG 2.1 specification:: +* link:https://www.w3.org/WAI/WCAG21/Techniques/general/G95.html[G95 - Providing short text alternatives that provide a brief description of the non-text content]. +* link:https://www.w3.org/WAI/WCAG21/Techniques/failures/F38.html[F38 - Using an empty alt attribute on an image that has a text alternative in another attribute]. include::partial$misc/admon-accessibility-rule-i3-can-also-be-applied.adoc[] diff --git a/modules/ROOT/partials/a11y-rules/i3.adoc b/modules/ROOT/partials/a11y-rules/i3.adoc index b7bb2b1446..d6ede8882e 100644 --- a/modules/ROOT/partials/a11y-rules/i3.adoc +++ b/modules/ROOT/partials/a11y-rules/i3.adoc @@ -11,7 +11,9 @@ https://www.w3.org/TR/WCAG21/#conformance[WCAG level]:: Level A ; Level AA ; Lev xref:a11ychecker_html_version[HTML version]:: HTML4 and HTML5 -WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/general/G95.html[G95 - Providing short text alternatives that provide a brief description of the non-text content]. +WCAG 2.1 specification:: +* link:https://www.w3.org/WAI/WCAG21/Techniques/general/G95.html[G95 - Providing short text alternatives that provide a brief description of the non-text content]. +* link:https://www.w3.org/WAI/WCAG21/Techniques/failures/F38.html[F38 - Using an empty alt attribute on an image that has a text alternative in another attribute]. include::partial$misc/admon-accessibility-rule-i3-can-also-be-applied.adoc[] diff --git a/modules/ROOT/partials/configuration/a11y_advanced_options.adoc b/modules/ROOT/partials/configuration/a11y_advanced_options.adoc index de6765c7f7..ca40b0f747 100644 --- a/modules/ROOT/partials/configuration/a11y_advanced_options.adoc +++ b/modules/ROOT/partials/configuration/a11y_advanced_options.adoc @@ -11,7 +11,7 @@ Setting `+a11y_advanced_options+` to `+true+`: * Adds the *Image is decorative* option to the _Insert/Edit Image_ dialog, allowing users to specify that an image is decorative and does not require alternative text for accessibility purposes. * Adds the *Decorative image* button to Image Optimizer's _Alt text_ context toolbar, allowing users to specify that an image is decorative and does not require alternative text for accessibility purposes. -* Adds the *Image is decorative* option to the _Accessibility Checker error_ dialog for images without alternative text or the `+role="presentation"+` attribute. +* Adds the *Image is decorative* option to the _Accessibility Checker error_ dialog for images that need to be marked as decorative. [IMPORTANT] ==== diff --git a/modules/ROOT/partials/configuration/a11ychecker_allow_decorative_images.adoc b/modules/ROOT/partials/configuration/a11ychecker_allow_decorative_images.adoc index c669276576..4ad544ed0a 100644 --- a/modules/ROOT/partials/configuration/a11ychecker_allow_decorative_images.adoc +++ b/modules/ROOT/partials/configuration/a11ychecker_allow_decorative_images.adoc @@ -3,12 +3,13 @@ This option determines whether the Accessibility Checker should allow decorative images. Decorative images are those that are used purely for visual enhancement and do not convey meaningful content or serve a specific function. -When this option is set to `+true+`, decorative images must have *both*: +When this option is set to `+true+`, decorative images must be marked using one or both of these methods: -* An empty alternative text attribute (`+alt=""+`). -* and the `+role="presentation"+` attribute. +* An empty alternative text attribute (`+alt=""+`), OR +* The `+role="presentation"+` or `+role="none"+` attribute, OR +* Both methods together -This combination explicitly tells assistive technologies to ignore these images, improving the browsing experience for users of screen readers. +Any of these approaches explicitly tells assistive technologies to ignore these images, improving the browsing experience for users of screen readers. === Common Use Cases for Decorative Images @@ -18,11 +19,21 @@ This combination explicitly tells assistive technologies to ignore these images, * Images that are described by adjacent text content * Spacer images used for layout purposes -=== Example of a Decorative Image: +=== Examples of Decorative Images: [source,html] ---- - + + + + + + + + + + + ---- === Example of an Informative Image (non-decorative): @@ -36,10 +47,8 @@ This combination explicitly tells assistive technologies to ignore these images, If `+a11ychecker_allow_decorative_images+` is set to `+true+`, the Accessibility Checker will present an error when: -* An image does not have the alternative text attribute (`+alt+`). -* An image has an empty alternative text attribute but is missing the `+role="presentation"+` attribute. -* An image has alternative text and a conflicting `+role="presentation"+` attribute. -* A potentially meaningful image (like a logo or chart) is marked as decorative. +* An image has conflicting accessibility information (e.g., both meaningful alt text and `+role="presentation"+`). +* An image has incomplete accessibility information (no clear decorative or informative intent). If `+a11ychecker_allow_decorative_images+` is set to `+false+`, the Accessibility Checker will present an error when: @@ -54,7 +63,7 @@ If `+a11ychecker_allow_decorative_images+` is not explicitly set, the value defi *Type:* `+Boolean+` -*Default value:* `+true+` +*Default value:* `+false+` *Possible values:* `+true+`, `+false+` diff --git a/modules/ROOT/partials/configuration/a11ychecker_filter_issue.adoc b/modules/ROOT/partials/configuration/a11ychecker_filter_issue.adoc index b901d701ea..d66f42894b 100644 --- a/modules/ROOT/partials/configuration/a11ychecker_filter_issue.adoc +++ b/modules/ROOT/partials/configuration/a11ychecker_filter_issue.adoc @@ -47,7 +47,7 @@ tinymce.init({ === Example: using `+a11ychecker_filter_issue+` to filter images with empty alternative text from the Accessibility Checker I1 rule -The callback function in the following example will only return `false` for any issues with `'I1'` as the `+'id'+` image elements with an empty `+'alt+'` attribute, otherwise the issue won’t be filtered out. This implementation can be useful as allowing images to have empty alternative text can be another method of applying the `+role="presentation"+` attribute to mark an image as `+decorative+`. +The callback function in the following example will only return `false` for any issues with `'I1'` as the `+'id'+` for image elements with an empty `+'alt+'` attribute, otherwise the issue won't be filtered out. This implementation can be useful when you want to allow images with empty alternative text to be treated as decorative. [source,js] ---- From 2eff5c1c5804e5f7898bed2bcb4e628c74515d61 Mon Sep 17 00:00:00 2001 From: "Arvin(Jintao) Han" <20640097+ArvinJ-H@users.noreply.github.com> Date: Fri, 18 Jul 2025 16:06:25 +1000 Subject: [PATCH 44/60] DOC-3147: Update split button documentation (#3793) * DOC-3147: Update split button tooltips and documentation * Update modules/ROOT/pages/8.0-release-notes.adoc Co-authored-by: Karl Kemister-Sheppard * Update modules/ROOT/pages/8.0-release-notes.adoc Co-authored-by: Karl Kemister-Sheppard * Update modules/ROOT/pages/8.0-release-notes.adoc Co-authored-by: Karl Kemister-Sheppard * Update modules/ROOT/pages/8.0-release-notes.adoc Co-authored-by: tiny-ben-tran * Update modules/ROOT/pages/custom-split-toolbar-button.adoc Co-authored-by: tiny-ben-tran * Update modules/ROOT/pages/custom-split-toolbar-button.adoc Co-authored-by: tiny-ben-tran * Update modules/ROOT/pages/custom-split-toolbar-button.adoc Co-authored-by: tiny-ben-tran * DOC-3147: Refactor split button documentation and CSS classes for clarity and consistency * DOC-3147: Update split button notes to reflect structural changes. * DOC-3147: Remove CSS classes section and related file for split buttons * Update modules/ROOT/pages/creating-a-skin.adoc * Update modules/ROOT/pages/8.0-release-notes.adoc * Update modules/ROOT/pages/8.0-release-notes.adoc --------- Co-authored-by: Karl Kemister-Sheppard Co-authored-by: tiny-ben-tran --- .../live-demos/custom-toolbar-split-button/index.js | 3 ++- modules/ROOT/pages/8.0-release-notes.adoc | 12 +++++++++++- modules/ROOT/pages/creating-a-skin.adoc | 2 ++ modules/ROOT/pages/custom-split-toolbar-button.adoc | 3 +++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/examples/live-demos/custom-toolbar-split-button/index.js b/modules/ROOT/examples/live-demos/custom-toolbar-split-button/index.js index 256c3488f5..f60882e3e6 100644 --- a/modules/ROOT/examples/live-demos/custom-toolbar-split-button/index.js +++ b/modules/ROOT/examples/live-demos/custom-toolbar-split-button/index.js @@ -6,7 +6,8 @@ tinymce.init({ editor.ui.registry.addSplitButton('myButton', { text: 'My Button', icon: 'info', - tooltip: 'This is an example split-button', + tooltip: 'Execute my action', + chevronTooltip: 'My Button menu options', onAction: () => editor.insertContent('

You clicked the main button

'), onItemAction: (api, value) => editor.insertContent(value), fetch: (callback) => { diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index c2264569bb..95c43d0363 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -322,6 +322,11 @@ editor.execCommand('ToggleToolbarDrawer', false, null, { skip_focus: true }); For more information on the `ToggleToolbarDrawer` command, see: xref:editor-command-identifiers.adoc[Available Commands]. +=== Split buttons are now rendered as separate action and chevron buttons. +// #TINY-8665 + +Split buttons in {productname} {release-version} now render as two independent, focusable components instead of a single composite element. The main button performs the primary action, while the chevron button controls the dropdown menu. This design improvement enhances accessibility by allowing separate focus targets and ARIA labels for each button. + === The translate API now automatically replaces three dots in a row with an ellipsis character. // #TINY-12155 @@ -339,6 +344,12 @@ Comments containing HTML-like content are removed from the editor's content by d {productname} introduces a new configuration option, xref:content-filtering.adoc#allow_html_in_comments[allow_html_in_comments], to give users control over whether HTML-like content in comments should be retained or removed. By default, this content is removed for security, but setting the option to `true` allows HTML-like content in comments to be preserved when needed. +=== Split button tooltip configuration +// #TINY-8665 + +The `+chevronTooltip+` property provides custom tooltip text for the chevron button portion of split buttons. When `+chevronTooltip+` is not specified, {productname} automatically generates tooltip text using the pattern `+"{tooltip} menu"+`. The `+setTooltip+` method updates both main and chevron tooltips to maintain consistency. + +For more information, see xref:custom-split-toolbar-button.adoc[Split toolbar buttons]. [[changes]] == Changes @@ -350,7 +361,6 @@ Comments containing HTML-like content are removed from the editor's content by d // CCFR here. - === DomParser no longer tries to fix some nodes when parsed with a context // #TINY-8205 diff --git a/modules/ROOT/pages/creating-a-skin.adoc b/modules/ROOT/pages/creating-a-skin.adoc index 5ff800439f..19f20e2fbe 100644 --- a/modules/ROOT/pages/creating-a-skin.adoc +++ b/modules/ROOT/pages/creating-a-skin.adoc @@ -67,6 +67,8 @@ _Do not edit these files directly_. Instead, use them as references when creatin * `+modules/oxide/src/less/theme/components/toolbar-button/toolbar-button.less+` The typical workflow involves copying variables from the theme folder into the skins `skin.less` file and modifying them as needed. + +NOTE: Split buttons have undergone structural changes in {productname} {productmajorversion}. Previously they used a single component structure, but now use separate components for the main button and chevron areas. See xref:migration-from-7x.adoc#split-button-css-breaking-change[split button css breaking change] ==== [NOTE] diff --git a/modules/ROOT/pages/custom-split-toolbar-button.adoc b/modules/ROOT/pages/custom-split-toolbar-button.adoc index 63fafd4f00..c379abd2ba 100644 --- a/modules/ROOT/pages/custom-split-toolbar-button.adoc +++ b/modules/ROOT/pages/custom-split-toolbar-button.adoc @@ -13,6 +13,8 @@ A split button contains a basic button and a menu button, wrapped up into one to |text |string |Primary button |optional |Text displayed if no icon is found. |icon |string |Primary button |optional | include::partial$misc/admon-predefined-icons-only.adoc[] +|tooltip |string |Primary button |optional |Text displayed when hovering over the main button. +|chevronTooltip |string |Chevron button |optional |Text displayed when hovering over the chevron button. If not provided, it will be generated using the tooltip of the main button. ie: `+"{tooltip} menu"+`. |onAction |`+(api) => void+` |Primary button |required |Function invoked when the basic button section is clicked. |select |`+(value: string) => boolean+` |Choice menu items |optional |default: `false` - Function run on each option when the menu is opened to determine if it should be highlighted as active. |columns |number or `+'auto'+` |Drop-down menu |optional |default: `1` - Number of columns for the list of options. When set to more than 1 column, only the icon for each item will be shown. @@ -35,6 +37,7 @@ include::partial$misc/admon-predefined-icons-only.adoc[] 3+| |setText |`+(text: string) => void+` |Sets the text label to display. |setIcon |`+(icon: string) => void+` |Sets the icon of the button. +|setTooltip |`+(tooltip: string) => void+` |Sets the main button tooltip. |=== [[split-button-example-and-explanation]] From 1da3634dca7dc7fdda08bc714adde9268ec146fa Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Mon, 21 Jul 2025 14:22:23 +1000 Subject: [PATCH 45/60] DOC-3147: draft changelog. --- modules/ROOT/pages/changelog.adoc | 100 +++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/pages/changelog.adoc b/modules/ROOT/pages/changelog.adoc index 5218882f0c..bcd62d9d27 100644 --- a/modules/ROOT/pages/changelog.adoc +++ b/modules/ROOT/pages/changelog.adoc @@ -4,6 +4,102 @@ NOTE: This is the {productname} Community version changelog. For information about the latest {cloudname} or {enterpriseversion} Release, see: xref:release-notes.adoc[{productname} Release Notes]. -== xref:8.0-release-notes.adoc[8.0.0 - 2025-TBA-TBA] +== xref:8.0-release-notes.adoc[8.0.0 - 2025-07-23] -// TODO \ No newline at end of file +### Added +* New `pageUid` and `editorUid` properties to tinymce global and editor instance respectively. +// #TINY-12021 //suggest-remove// +* New `UserLookup` API to provide consistent user management and fetching/caching user information across TinyMCE plugins. +// #TINY-11974 //TODO// +* New toolbar icons for suggested edits plugin. +// #TINY-12070 //suggest-remove// +* New `crossorigin` option that sets the `crossorigin` attribute on scripts loaded by the editor. +// #TINY-12228 +* New `allow_html_in_comments` option to allow HTML like contents inside comment data. +// #TINY-12220 +* Support for TinyMCE 8 license keys and license key manager. +// #TINY-12001 + +### Improved +* Focus is now restored to a dialog after closing an alert, confirmation or another dialog. +// #TINY-12038 +* Resize handles are more accessible with `role` and `aria-valuetext` attributes. +// #TINY-11421 +* Toolbar drawer now closes when the editor loses focus. +// #TINY-12125 +* The `translate` API now automatically replaces three dots in a row with an ellipsis character. +// #TINY-12155 +* Tooltips can now be closed by pressing the escape key. +// #TINY-12054 +* Instructions on how to navigate the color swatch, image select and insert table widget are now announced by the screen readers. +// #TINY-12189 +* When `editor.resetContent()` is used, the resulting `SetContent` event now has the `initial` flag set in the event arguments. +// #TINY-12146 +* Updated Image plugin decorative image check to align with accessbility standard +// #TINY-12545 + +### Changed +* New `list_max_depth` option that limits the maximum list indent depth. +// #TINY-11937 +* DomParser no longer tries to fix some nodes when parsed with a context. +// #TINY-11927 +* Split buttons are now rendered as separate action and chevron buttons. +// #TINY-8665 +* Moved essential parts of the `lists` plugin into core. +// #TINY-12121 //TODO// Was set to Task +* Cut action no longer uses `execCommand('Delete')` function. +// #TINY-12171 +* Comments with HTML like content, attributes with HTML like values, elements with HTML Comment like textContent are no longer retained while content sanitization is active. +// #TINY-12056 //TODO// +* Added space to promotion message for ease of reading. +// #TINY-12271 + +### Deprecated +* Deprecated `skipFocus` option for ToggleToolbarDrawer command. To skip focus use `skip_focus` option. +// #TINY-12044 +* Deprecated 'editor.selection.setContent' method. +// #TINY-11692 + +### Removed +* Removed undocumented `documentBaseUrl` property from `Editor` instances. `documentBaseURI` is the supported property. +// #TINY-12182 + +### Fixed +* Long tooltips could overflow narrow browser windows. +// #TINY-11884 +* Tab to create a new row in tables with a non-editable final row would freeze the editor. +// #TINY-12018 +* Fixed an issue where the context form API `onSetup` was referencing the incorrect element. +// #TINY-11912 +* Attempting to add a newline directly after a block element such as an image would cause an error. +// #TINY-12045 +* It wasn't possible to navigate out of a `figcaption` using the left and right arrow keys in Firefox. +// #TINY-11982 +* Nested font sizes were causing too much spacing between lines. +// #TINY-12073 +* New list item was not inserted correctly when existing list item had a block element inside. +// #TINY-12102 +* Deleting a whole element would sometimes modify nearby content. +// #TINY-11868 +* HTML schema did not treat `colgroup` or `col` elements as block elements. +// #TINY-12092 +* Inserting HTML fragments with invalid contents now retains more of the structure. +// #TINY-11927 +* The `contextform` subtoolbar is no longer dismissed when using the back button in inline editors. +// #TINY-12118 +* Tabbing when a `figure` was selected didn't move the selection on the `figcaption` correctly. +// #TINY-11753 +* Strikethrough format could be added outside font size format, which renders incorrectly in some browsers. +// #TINY-12004 +* Using arrow navigation between buttons when a button had the mouse over could stop the navigation. +// #TINY-12163 +* Codesample dialog would not disable spellcheck as expected. +// #TINY-12120 +* Cutting a whole HTML element would add an empty paragraph. +// #TINY-12171 +* Added better support for template elements. +// #TINY-12157 // incorrect tagging in JIRA- docs_required// +* Tooltips no longer show above editor views #TINY-12289 +// //need to know if this is specific to suggestededits only// +* `onboarding` plugin overlay now shows above popups. +// #TINY-12522 //suggest-remove// \ No newline at end of file From 3afd21196ddc1b1d4377845d746d0e6259dee159 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Mon, 21 Jul 2025 16:17:07 +1000 Subject: [PATCH 46/60] DOC-3147: New User Lookup API for retrieving and caching user details. (#3801) * DOC-3147: New User Lookup API for retrieving and caching user details. * Update modules/ROOT/pages/8.0-release-notes.adoc --- modules/ROOT/pages/8.0-release-notes.adoc | 62 +++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 95c43d0363..d60aeccef0 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -351,6 +351,68 @@ The `+chevronTooltip+` property provides custom tooltip text for the chevron but For more information, see xref:custom-split-toolbar-button.adoc[Split toolbar buttons]. +=== New User Lookup API for retrieving and caching user details +// #TINY-11974 + +{productname} {release-version} introduces a new xref:userlookup.adoc[User Lookup API] that enables integrations to retrieve and cache user details (such as names and avatars) and identify the current user within the editor. This API is particularly useful when building features that rely on user context, such as commenting systems or displaying lists of elements containing user information. + +The User Lookup API provides efficient user data management with built-in caching, reducing redundant network requests and improving performance. It can be used as a universal solution for `+_author+` and `+_author_avatar+` configurations across various plugins, including currently supported plugins such as **Suggested Edits**, **Comments**, and **Revision History**. + +Key features include: + +* **Current user identification**: Set and retrieve the active user's ID using the new xref:userlookup.adoc#user_id[`user_id`] configuration option +* **Flexible user fetching**: Configure custom user data retrieval through the xref:userlookup.adoc#fetch_users[`fetch_users`] callback function +* **Built-in caching**: Automatic caching of user data to minimize API calls +* **Fallback handling**: Automatic generation of default user information when custom fetch functions are not provided +* **Extensible user objects**: Support for custom metadata through the `custom` property + +==== Basic configuration + +The API requires two main configuration options: + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + user_id: 'alextaylor', // Set the current user's unique identifier + fetch_users: (userIds) => { + // Return a Promise that resolves to an array of user objects + return Promise.all( + userIds.map(userId => + fetch(`/users/${userId}`) + .then(response => response.json()) + .catch(() => ({ id: userId })) // Fallback for failed requests + ) + ); + } +}); +---- + +==== API usage + +Once configured, the API provides two main methods: + +* `editor.userLookup.userId` - Returns the current user's ID +* `editor.userLookup.fetchUsers(userIds)` - Fetches and caches user information + +[source,js] +---- +editor.on('init', () => { + // Get current user ID + console.log('Current user:', editor.userLookup.userId); + + // Fetch multiple users + const users = editor.userLookup.fetchUsers(['user-1', 'user-2']); + + // Handle individual user promises + users['user-1'].then(user => { + console.log('User 1 name:', user.name); + }); +}); +---- + +For comprehensive documentation and examples, see: xref:userlookup.adoc[User Lookup API]. + [[changes]] == Changes From f1adf74cb9a712b7f28d3d56a8033402c854e29a Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Mon, 21 Jul 2025 19:10:11 +1000 Subject: [PATCH 47/60] DOC-3226: Update licensing information and examples for TinyMCE 8 (#3753) * DOC-3226: Update licensing information and examples for TinyMCE 8, including T8LK: prefix requirements for self-hosted deployments across various integrations and documentation. * Enhance license key documentation for TinyMCE 8, clarifying T8LK prefix usage and client-side JWT validation across various integration references and examples. * DOC-3226: Update license key format across documentation and examples to include T8LK prefix for TinyMCE 8 compatibility and included release notes entry. * Update Blazor integration example to include T8LK prefix in LicenseKey for compliance with TinyMCE 8. * Update Blazor integration example to include T8LK prefix in LicenseKey for TinyMCE 8 compliance. * DOC-3226: Technical and readabilty adjustments * DOC-3226: Enhance license key documentation for TinyMCE 8, clarifying T8LK prefix requirements and updating integration references across various frameworks. * DOC-3226: Update license key documentation for TinyMCE 8, clarifying API key usage, T8LK prefix requirements, and adding common error messages with solutions. * Update modules/ROOT/pages/8.0-release-notes.adoc * Update modules/ROOT/partials/integrations/webcomponent-tech-ref.adoc * Update modules/ROOT/partials/integrations/webcomponent-quick-start.adoc Co-authored-by: tiny-ben-tran * Update modules/ROOT/partials/integrations/webcomponent-tech-ref.adoc Co-authored-by: tiny-ben-tran * Update modules/ROOT/partials/integrations/webcomponent-tech-ref.adoc Co-authored-by: tiny-ben-tran * Update modules/ROOT/partials/integrations/webcomponent-tech-ref.adoc Co-authored-by: tiny-ben-tran * DOC-3226: Change readonly to disabled. Add new messages. * Update modules/ROOT/partials/integrations/common/license-key-property.adoc * Update modules/ROOT/partials/integrations/vue-quick-start.adoc Co-authored-by: Tim Dettrick * Update modules/ROOT/partials/integrations/vue-quick-start.adoc Co-authored-by: Tim Dettrick * Update modules/ROOT/partials/integrations/blazor-postinstall.adoc * Update modules/ROOT/partials/integrations/blazor-tech-ref.adoc Co-authored-by: Tim Dettrick * Update modules/ROOT/partials/integrations/react-bundling.adoc * Update modules/ROOT/partials/integrations/svelte-quick-start.adoc Co-authored-by: tiny-ben-tran * Update modules/ROOT/partials/module-loading/bundling-vite-es6-npm_editor.adoc * Update modules/ROOT/partials/integrations/react-quick-start.adoc * Apply suggestions from code review * DOC-3147: Update key information for self-hosted for licensekeymanager addon. --------- Co-authored-by: ltrouton Co-authored-by: tiny-ben-tran Co-authored-by: Tim Dettrick --- modules/ROOT/pages/8.0-release-notes.adoc | 65 +++- modules/ROOT/pages/license-key.adoc | 333 +++++++++++++++++- modules/ROOT/pages/vite-es6-npm.adoc | 12 + .../install/basic-quickstart-base.adoc | 2 +- .../integrations/angular-tech-ref.adoc | 21 +- .../integrations/blazor-postinstall.adoc | 24 +- .../integrations/blazor-tech-ref.adoc | 20 +- .../common/license-key-property.adoc | 20 ++ .../integrations/jquery-quick-start.adoc | 6 +- .../partials/integrations/react-bundling.adoc | 4 +- .../integrations/react-quick-start.adoc | 8 +- .../partials/integrations/react-tech-ref.adoc | 22 +- .../integrations/svelte-quick-start.adoc | 13 +- .../integrations/svelte-tech-ref.adoc | 22 +- .../partials/integrations/vue-tech-ref.adoc | 22 +- .../webcomponent-quick-start.adoc | 7 +- .../integrations/webcomponent-tech-ref.adoc | 37 ++ .../partials/misc/setting-the-license.adoc | 22 +- .../bundling-vite-es6-npm_editor.adoc | 3 +- 19 files changed, 563 insertions(+), 100 deletions(-) create mode 100644 modules/ROOT/partials/integrations/common/license-key-property.adoc diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index d60aeccef0..374e3d695e 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -26,8 +26,10 @@ include::partial$misc/admon-releasenotes-for-stable.adoc[] * xref:deprecated[Deprecated] * xref:known-issues[Known issues] -[NOTE] -For additional details on {productname} {release-version} breaking changes when considering upgrading, see xref:migration-from-7x.adoc[Migrating from {productname} 7 to {productname} {release-version}]. +[IMPORTANT] +==== +This release includes breaking changes to the license key system. All commercial self-hosted deployments must update their license keys to use the new `T8LK:` prefix format. For details on this and other breaking changes when considering upgrading, see xref:migration-from-7x.adoc[Migrating from {productname} 7 to {productname} {release-version}]. +==== [[new-premium-plugin]] New Premium plugin @@ -416,7 +418,62 @@ For comprehensive documentation and examples, see: xref:userlookup.adoc[User Loo [[changes]] == Changes -{productname} {release-version} also includes the following change: +{productname} {release-version} includes the following changes: + +=== Enhanced license key system with T8LK prefix + +The license key system in {productname} 8 has been enhanced to provide improved subscription access control and streamlined renewal processes. This change primarily affects self-hosted deployments, as cloud users ({cloudname}) do not require a license key. + +[IMPORTANT] +==== +* If you use {cloudname}, no license key is required - your cloud subscription automatically includes the commercial license. +* For self-hosted deployments, all commercial license keys must use the new `T8LK:` prefix format. +* Existing TinyMCE 7 license keys cannot be made compatible with TinyMCE 8 by adding the T8LK prefix. +==== + +Key changes for self-hosted deployments: + +* New `T8LK:` prefix requirement for all commercial license keys. +* No server communication or "phone home" checks required +* Support for both date-based and version-locked keys +* Streamlined hybrid deployment configuration +* Improved support for air-gapped and offline environments + +[IMPORTANT] +==== +*Cloud Deployments:* + +* When using {cloudname}, only an API key is required - no license key needed +* Your cloud subscription automatically includes the commercial license + +*Self-hosted Deployments:* + +* Commercial use: Contact your account manager or visit link:https://www.tiny.cloud/my-account[Tiny Cloud Account] to obtain a T8LK-prefixed license key +* GPL use: Set `license_key: 'gpl'` (case insensitive) +* Open source projects using premium features: Use the combined format `license_key: 'GPL+T8LK:...'` + +*Required License Key Manager Setup for Self-hosted Commercial Deployments:* + +For commercial license keys to function, the license key manager must be properly configured. **The editor will not work without this setup.** + +* **Standalone hosting** (e.g., in a `/public` folder): The `+licensekeymanager+` folder is **required** to be located within the `+plugins+` folder alongside all other plugins. +* **Bundled applications**: The `+licensekeymanager/index.js+` file is **required** to be imported, otherwise the editor will result in a disabled state. + +.Example: Importing the License Key Manager in a bundled application +[source,javascript] +---- +import 'tinymce/plugins/licensekeymanager'; +---- + +==== + +=== Upgrading from TinyMCE 7 + +* *Cloud Users ({cloudname})*: No license key changes needed - simply update your {productname} version. +* *Self-hosted Users*: Contact your account manager to obtain a new T8LK-prefixed license key. + +For more information on the new license key system, see: xref:license-key.adoc[License Key]. + // === // #TINY-vwxyz1 @@ -649,4 +706,4 @@ There known issue in {productname} {release-version}. // #TINY-vwxyz1 // CCFR here. -// **Status**: This issue is currently being investigated. \ No newline at end of file +// **Status**: This issue is currently being investigated. diff --git a/modules/ROOT/pages/license-key.adoc b/modules/ROOT/pages/license-key.adoc index 7cd007e07e..58c4874066 100644 --- a/modules/ROOT/pages/license-key.adoc +++ b/modules/ROOT/pages/license-key.adoc @@ -1,55 +1,362 @@ = License key :description_short: {productname} License Configuration Guide | {productname} -:description: Learn how to configure license key and stop {productname} from running in the evaluation mode. +:description: Learn how to configure a license key in {productname}. :keywords: {productname}, cloud, script, textarea, apiKey, faq, license key, frequently asked questions, +== Overview +{productname} 8 uses an enhanced license key system to ensure compliance with {productname} licensing terms. + [IMPORTANT] ==== -{productname} 7 is licensed under the GNU General Public License Version 2 or later. A new configuration option called 'license_key' requires developers to make a conscious decision to use {productname} with the GPLv2+ license or with a commercial license. +{productname} is licensed under the GNU General Public License Version 2 or later. A configuration option called `+'license_key'+` introduced in {productname} 7 requires developers to make a conscious decision to use {productname} with the GPLv2+ license or with a commercial license. -If you are using {productname} in a self-hosted environment, a console log warning message will display if the license key config option is missing or invalid. This message aims to ensure compliance with licensing requirements and provide transparency during the evaluation period. +When using {productname} 8 in a self-hosted environment, a license key must be provided and it must be valid. Otherwise, the editor will be disabled. A license key is not required when loading {productname} from {cloudname}, as it is already under a commercial license. -This message will not be shown when loading {productname} from {cloudname}, as it is already under a commercial license. +In addition, when using {productname} 8 in a self-hosted environment for commercial use, a commercial license key manager addon is required in order for the editor to operate. ==== include::partial$misc/setting-the-license.adoc[] +== Setting up the Commercial License Key Manager + +[NOTE] +==== +`+'licensekeymanager'+` does not need to be added to the `+plugins+` configuration option. +==== + +A commercial license key manager (`+licensekeymanager+`) is required to be loaded by the editor when using a commercial license key. The commercial license key manager can be set up like any other plugin for self-hosted installations. However, it does not need to be specified in the `+plugins+` configuration option as the editor will attempt to automatically load the license key manager when required. + +The commercial license key manager is available: + +* in a purchased self-hosted plan - a `licensekeymanager` folder will be present in the `plugins` folder of the {productname} `+.zip+`. +* in a purchased self-hosted addon - a `licensekeymanager` folder will be present in addition to the purchased addon. +* as a standalone addon - a `licensekeymanager` folder will be present. + +[IMPORTANT] +==== +The following setup steps are **required** for the editor to function with commercial license keys. The editor will not work without proper license key manager configuration. +==== + +If hosting {productname} standalone, for example, in a `/public` folder, **ensure** the `+licensekeymanager+` folder is included in the `+plugins+` folder with all of the other plugins. The editor will not function without this. + +If bundling {productname} as part of an application **ensure** the `+licensekeymanager/index.js+` file is imported, otherwise the editor will not function without this. + +.Example importing the License Key Manager in a bundled application +[source,javascript] +---- +import 'tinymce/plugins/licensekeymanager'; +---- + +== License Types and Deployment Options + +=== License Key Types + +There are two different license types: + +. **GPL license** +. **Commercial license** + +A commercial license can be broken down into sub-types: + +[cols="1,2,2", options="header"] +|=== +| **Type** | **Key Features** | **Best For** + +| Time-based Keys +a| +* Expiry date +* Optional grace period +* Premium plugin access +* No patch version locking +a| + ** Developers that can perform regular license rotation. + ** Developers that want a license key to work across patch versions. +| Version-locked Keys +a| +* Specific patch version only +* No expiration date +* Premium plugin access +a| +* Environments where regular license key rotation cannot be performed. +|=== + +=== Deployment Types + +[cols="1,2,2", options="header"] +|=== +| **Type** | **Key Configuration** | **Capabilities** + +| Cloud-only +a| +* API key required for: + ** Cloud services access + ** Premium plugin access + ** Automatic updates +* No license key required as its automatically issued. (defaults to a commercial license) +a| +* Fully managed service: + ** No local deployment needed + ** Automatic updates and CDN delivery + +| Self-hosted +a| +* A GPL or commercial license key is required +* No API key required +a| +* Complete local control: + ** Self-hosted editor and premium plugins + ** Custom deployment options + ** No cloud dependencies + ** No internet connectivity needed + +| Hybrid +a| +* Both keys required: + ** API key for cloud features + ** License key for self-hosted editor and self-hosted premium plugins +a| +* Best of both worlds: + ** Access to cloud features + ** Custom deployment options +|=== + +== License States + +[cols="1,2,1", options="header"] +|=== +| State | Features & Behavior | Applicable To + +| Active +a| +* Full editor and premium plugin functionality +* No restrictions on features +| All license types + +| Grace Period +a| +* All features remain functional +* Warnings that the license key is in grace period and will be not work in the future +| Time-based keys only + +| Expired +a| +* Editor is disabled +* Must obtain a new license key to continue using {productname} +| Time-based keys only +| Invalid +a| +* Editor is disabled +* Editor notifications notifying that the license key is not valid +| All license types +|=== + == FAQ === What does the GPL license mean? -{productname} 7 is licensed under the GNU General Public License Version 2 or later, often abbreviated to GPLv2+. https://www.gnu.org/licenses/old-licenses/gpl-2.0.html[Read more about the license terms here.^] +{productname} 8 is licensed under the GNU General Public License Version 2 or later, often abbreviated to GPLv2+. https://www.gnu.org/licenses/old-licenses/gpl-2.0.html[Read more about the license terms here.^] The GPLv2+ license was chosen to provide the best compatibility with existing GPL licensed open source projects. === What is the difference between a license key and the API key? -The **API key** is used when loading {productname} from the {cloudname}. The **license key** is used to declare the license terms when self-hosting {productname}. +The **API key** is used when loading {productname} from the {cloudname}. The license key is used to declare the license terms when self-hosting {productname}. === Who needs to get a license key? -Anyone who intends to self-host {productname} will need to provide a valid commercial license key or declare their intention to use {productname} under the GPLv2+ license. +Anyone who intends to self-host {productname} will need to obtain a T8LK-prefixed commercial license key or use GPL mode === How will I know if this change affects me? -If {productname} detects that the `license_key` configuration is missing or invalid, it will display a console log warning. If you have actively suppressed or hidden this message, please remove those overrides. If no notification appears, you are not affected. +If {productname} detects that the `license_key` configuration is missing or invalid, it will display a console log warning message and/or editor notification and set the editor to disabled. These warnings and restrictions are designed to ensure compliance and provide transparency during evaluation periods. + +[TIP] +If you have actively suppressed or hidden these messages, please remove those overrides to maintain proper license validation. If no notification appears, you are not affected. === Should I be using both an API key and a license key? -No, an API key and a license key should not be used simultaneously. The API key should only be used if {productname} is loaded from the {cloudname}. If {productname} is being self-hosted, the license key option should be used instead. +See the <> section above for more information. + +[IMPORTANT] +==== +Only use both keys in properly configured hybrid deployments. Using both keys without proper hybrid deployment configuration **may cause** validation conflicts and unexpected behavior. +==== + +=== Will {productname} "phone home" to check the license key? -=== Will {productname} “phone home” to check the license key? +No, {productname} does not contact any server to validate the license key for self-hosted deployments. -No. {productname} does not contact any server to validate the license key. +If using a cloud or hybrid deployment configuration, the license key may be checked by {cloudname}. === What happens if I don't provide a valid license key? -The console log message or notification will persist until a valid license key or 'gpl' is provided. +In addition to the editor being disabled, a console log warning message and/or editor notification will persist until a valid license key or 'gpl' is provided. === Why is a license key required? The license key ensures compliance with {productname} licensing terms. It's part of our efforts to refine the license key system and may have additional functionalities in the future. +=== How do I obtain a {productname} 8 license key? + +To obtain a new {productname} 8 license key (T8LK-prefixed): + +* *Existing customers*: Contact your account manager or visit link:https://www.tiny.cloud/my-account[Tiny Cloud Account] to upgrade your subscription. +* *New customers*: Visit link:https://www.tiny.cloud/pricing[Tiny Cloud Pricing] to purchase a new license. + +[IMPORTANT] +==== +Existing {productname} 7 license keys cannot be modified to work with {productname} 8 by adding the T8LK prefix. A new {productname} 8 license must be obtained through the proper channels listed above. +==== + +=== If im upgrading from TinyMCE 7 how do I get a TinyMCE 8 license key? + +If you are using {cloudname} (cloud-hosted): + +* No license key is required - simply update your {productname} version as your cloud subscription includes the commercial license. + +If you are an existing {productname} 7 self-hosted customer upgrading to {productname} 8: + +. *Active Subscription*: +* Contact your account manager or visit link:https://www.tiny.cloud/my-account[Tiny Cloud Account] to obtain a new T8LK-prefixed license key. +. *Expired Subscription*: +* Contact your account manager or visit link:https://www.tiny.cloud/pricing[Tiny Cloud Pricing] to renew your subscription. +* A new T8LK-prefixed license key will be provided as part of the renewal process. + +[NOTE] +==== +Your existing {productname} 7 license key will continue to work with {productname} 7 self-hosted installations. But, you will require a separate T8LK-prefixed license key for {productname} 8 editor instances for self-hosted installations. +==== + === How can I get further assistance? -For any licensing or technical support questions, see our available options on the https://www.tiny.cloud/docs/tinymce/latest/support/[support page.] \ No newline at end of file +For any licensing or technical support questions, see our available options on the https://www.tiny.cloud/docs/tinymce/latest/support/[support page.] + +=== Technical Support + +For licensing or technical support: +* API key issues: Visit link:https://www.tiny.cloud/my-account[Tiny Cloud Account] +* License key issues: Visit link:https://www.tiny.cloud/my-account[Tiny Cloud Account] or contact your account manager +* Technical support: Visit link:https://support.tiny.cloud[Support Portal] +* Documentation: See link:https://www.tiny.cloud/docs/tinymce/latest/[{productname} Docs] + +== License Key Error Messages + +The following table lists common license key error messages that may appear in the console or editor, along with their descriptions and solutions: + +[cols="1,2,2,2", options="header"] +|=== +| Error Type | Console Message | Editor Notifications | Solution + +| xref:invalid-license-key[Invalid license key (General)] +| The editor is disabled because the license key provided is invalid [+${errorType}+] +| The editor is disabled because the license key provided is invalid. +a| * Verify that the license key is correctly copied from your link:https://www.tiny.cloud/my-account[Tiny Cloud Account] +* Ensure there are no extra spaces or characters in the key +* Check if the key matches your deployment type (Cloud vs Self-hosted) + +| xref:load-error[Load error (Cloud)] +| The editor is disabled because the TinyMCE API key could not be validated. The TinyMCE Commercial License Key Manager plugin is required for the provided API key to be validated but could not be loaded. +| The editor is disabled because the TinyMCE API key could not be validated. +a| * Verify that your API key is valid +* Check if your subscription is active +* Visit the link:https://support.tiny.cloud[Support Portal] if the issue persists + +| xref:load-error[Load error (Self-Hosted)] +| The editor is disabled because the license key provided is invalid. The TinyMCE Commercial License Key Manager plugin is required for the provided license key to be validated but could not be loaded. +| The editor is disabled because the TinyMCE license key could not be validated. +a| * Check if the license key matches your deployment type: GPL or commercial, Cloud or Self-hosted +* Ensure the license key manager is set up correctly: <> + +| xref:expired[Expired] +| The editor is disabled because the license key has expired and is no longer valid +| The editor is disabled because the license key has expired and is no longer valid. +a| * Visit link:https://www.tiny.cloud/my-account[Tiny Cloud Account] to obtain a new license key +* Update your configuration with the new key +* Visit the link:https://support.tiny.cloud[Support Portal] if you believe your license should still be valid + +| xref:grace-period[Grace period] +| The editor will be disabled in the near future because the license key has expired +| The editor will be disabled in the near future because the license key has expired. +a| * Visit link:https://www.tiny.cloud/my-account[Tiny Cloud Account] to obtain a new license key +* Update your configuration before the grace period ends +* Visit the link:https://support.tiny.cloud[Support Portal] if you need assistance with license renewal + +| xref:invalid-editor-version[Invalid editor version] +| The editor is disabled because the license key is not valid with this version of {productname} +| The editor is disabled because the license key is not valid with this version of {productname}. +a| * Verify that your {productname} version matches the license key version +* Update either your {productname} version or obtain a new license key +* For version-locked keys, ensure you're using the correct patch version + +| xref:no-license-key[No license key] +| The editor is disabled because a {productname} license key has not been provided. Make sure to provide a valid license key or add license_key: 'gpl' to the init config to agree to the open source license terms. +| The editor is disabled because a {productname} license key has not been provided. +a| * Add the `license_key` parameter to your {productname} configuration +* For GPL usage, set `license_key: 'gpl'` +* For commercial usage, enter your valid commercial license key + +| xref:invalid-plugin[Invalid plugin] +| The "+${pluginCode}+" plugin requires a valid {productname} license key +| _No editor message_ +a| * Verify that your license includes access to the premium plugin +* Check if your license key is valid and not expired +* Visit the link:https://support.tiny.cloud[Support Portal] if you believe you should have access to this plugin + +| xref:online-api-key-error-fallback[Online API Key Error (5xx - Fallback)] +| The API key could not be validated by the API key validation server [type: +${errorType}${statusMsg}+]. Attempting fallback to provided license key. +| +a| * Check your internet connection +* Verify your firewall settings allow access to the validation server +* The editor will attempt to use the provided license key as fallback + +| xref:online-api-key-error-disable[Online API Key Error (4xx - Disable)] +| The editor is disabled because the API key could not be validated by the API key validation server [type: +${errorType}${statusMsg}+] +| The editor is disabled because the API key could not be validated by the API key validation server. +a| * Verify that your API key is valid +* Check if your subscription is active +* Visit the link:https://support.tiny.cloud[Support Portal] if the issue persists +|=== + +=== Detailed Error Descriptions + +[[invalid-license-key]] +==== Invalid license key (General) +The provided license key is not recognized as a valid {productname} license key. This can occur if the key is malformed, expired, or doesn't match your deployment type. For self-hosted installations, ensure you're using a valid T8LK-prefixed license key. Visit the link:https://www.tiny.cloud/my-account[Tiny Cloud Account] to verify your license key. + +[[load-error-cloud]] +==== Load error (Cloud) +The TinyMCE Commercial License Key Manager plugin is automatically loaded from the Tiny Cloud CDN for cloud deployments. If it cannot be loaded, the editor will be disabled. Review your subscription details in your link:https://www.tiny.cloud/my-account[Tiny Cloud Account] to check its status. + +[[load-error-selfhosted]] +==== Load error (Self-hosted) +For self-hosted installations, the TinyMCE Commercial License Key Manager plugin is required for commercial license keys otherwise the editor will be disabled. If it cannot be loaded, see the <> section for implementation details + +[[expired]] +==== Expired +The license key has reached its expiration date and is no longer valid for use. The editor will be disabled until a new valid license key is provided. For time-based keys, refer to the <> section. To renew your license, visit link:https://www.tiny.cloud/pricing[Tiny Cloud Pricing] or contact your account manager. + +[[grace-period]] +==== Grace period +The license key has reached its initial expiration date but is still within the grace period. The editor will continue to function but will be disabled when the grace period ends. See the <> section for more information about grace periods. Contact your account manager or visit link:https://www.tiny.cloud/my-account[Tiny Cloud Account] to renew your license before the grace period expires. + +[[invalid-editor-version]] +==== Invalid editor version +The license key is not compatible with the current version of {productname}. This typically occurs with version-locked keys when using a different patch version. Visit link:https://www.tiny.cloud/docs/tinymce/latest/[TinyMCE Documentation] to check your editor version. Review the <> section about version-locked keys. If you're upgrading from {productname} 7, visit link:https://www.tiny.cloud/my-account[Tiny Cloud Account] to obtain a new license key or see <> for guidance. For new licenses, visit link:https://www.tiny.cloud/pricing[Tiny Cloud Pricing]. + +[[no-license-key]] +==== No license key +No license key has been provided in the {productname} configuration. For self-hosted installations, you must either provide a valid commercial license key or explicitly opt into GPL usage. See the <> section for implementation details and the "<>" section for GPL licensing information. + +[[invalid-plugin]] +==== Invalid plugin +The attempted use of a premium plugin without a valid commercial license key. This occurs when trying to use premium features with a GPL license or an invalid commercial license. Review your subscription details in your link:https://www.tiny.cloud/my-account[Tiny Cloud Account] to verify plugin access. See the <> section for more information about license types and plugin access. + +[[online-api-key-error-fallback]] +==== Online API Key Error (5xx - Fallback) +A server-side error occurred while validating the API key. The editor will attempt to use the provided license key as a fallback mechanism. This typically occurs in hybrid deployments - see the <> section for proper configuration. If the issue persists, visit link:https://support.tiny.cloud[Support Portal] for assistance. + +[[online-api-key-error-disable]] +==== Online API Key Error (4xx - Disable) +The API key validation failed due to an invalid key or inactive subscription. The editor will be disabled until a valid API key is provided. For API key issues, visit link:https://www.tiny.cloud/my-account[Tiny Cloud Account] or see the "<>" section for clarification. + +For additional assistance, visit our link:https://support.tiny.cloud[Support Portal] or contact your link:https://www.tiny.cloud/my-account[Tiny Cloud Account] manager. diff --git a/modules/ROOT/pages/vite-es6-npm.adoc b/modules/ROOT/pages/vite-es6-npm.adoc index 2d8c93d9e7..eb2cf0f801 100644 --- a/modules/ROOT/pages/vite-es6-npm.adoc +++ b/modules/ROOT/pages/vite-es6-npm.adoc @@ -15,8 +15,18 @@ This guide requires the following: * Node.js and npm. * Basic knowledge of how to use https://vitejs.dev[Vite]. +* For self-hosted deployments: A valid license key starting with `T8LK:` from your link:{accountpageurl}/[{accountpage}] * (Optional: For premium features) The latest premium .zip bundle of TinyMCE that includes premium plugins. +[IMPORTANT] +==== +When self-hosting TinyMCE 8: + +* A license key is required for commercial deployments +* Keys must start with the `T8LK:` prefix +* For hybrid deployments that need both cloud features and local fallback, you can use both `license_key` and `api_key` +==== + == Procedures :is_zip_install: vite @@ -72,4 +82,6 @@ npx vite preview ---- :!is_zip_install: + + include::partial$module-loading/bundling-next-steps.adoc[] diff --git a/modules/ROOT/partials/install/basic-quickstart-base.adoc b/modules/ROOT/partials/install/basic-quickstart-base.adoc index 4138ee9009..4ef25386f9 100644 --- a/modules/ROOT/partials/install/basic-quickstart-base.adoc +++ b/modules/ROOT/partials/install/basic-quickstart-base.adoc @@ -182,7 +182,7 @@ ifeval::["{productSource}" != "cloud"] diff --git a/modules/ROOT/partials/integrations/angular-tech-ref.adoc b/modules/ROOT/partials/integrations/angular-tech-ref.adoc index 4a7261db9f..3efbba4023 100644 --- a/modules/ROOT/partials/integrations/angular-tech-ref.adoc +++ b/modules/ROOT/partials/integrations/angular-tech-ref.adoc @@ -130,21 +130,18 @@ include::partial$misc/get-an-api-key.adoc[] [[licensekey]] === `+licenseKey+` -{cloudname} License key. +include::partial$integrations/common/license-key-property.adoc[] -Use this when self-hosting {productname} instead of loading from {cloudname}. For more information, see: xref:license-key.adoc[License Key]. - -*Type:* `+String+` - -*Default value:* `+undefined+` - -*Possible values:* `undefined`, `'gpl'` or a valid {productname} license key - -==== Example: using `+licenseKey+` +==== Example: Commercial license +[source,html] +---- + +---- -[source,jsx] +==== Example: using `+licenseKey+` with GPL +[source,html] ---- - + ---- [[cloudchannel]] diff --git a/modules/ROOT/partials/integrations/blazor-postinstall.adoc b/modules/ROOT/partials/integrations/blazor-postinstall.adoc index 212562feaf..05f04d7bf4 100644 --- a/modules/ROOT/partials/integrations/blazor-postinstall.adoc +++ b/modules/ROOT/partials/integrations/blazor-postinstall.adoc @@ -1,4 +1,4 @@ -. Verify the installation by checking the `+ItemGroup+` references in the project file. For example, if the project is named _BlazorApp_, the relevant file would be `+BlazorApp.csproj+` with the dependency referenced as follows: +. Verify the installation by checking the `+ItemGroup+` references in the project file. For example, if the project is named _BlazorApp_, the relevant file would be `+BlazorApp.csproj+` with the dependency referenced as follows: + [source,xml] ---- @@ -16,9 +16,9 @@ + [NOTE] ==== -The location of the script depends on the type of Blazor app, including Blazor Server and Blazor WebAssembly (WASM) which are not covered in this guide. +The location of the script depends on the type of Blazor app, including Blazor Server and Blazor WebAssembly (WASM) which are not covered in this guide. -* If using Blazor Server, add the script in `+Pages/_Host.cshtml+`, for example: +* If using Blazor Server, add the script in `+Pages/_Host.cshtml+`, for example: + [source,html] ---- @@ -35,8 +35,8 @@ The location of the script depends on the type of Blazor app, including Blazor S ==== + -. Add the `+Editor+` component to a page by either: -* Using the `+using+` directive: +. Add the `+Editor+` component to a page by either: +* Using the `+using+` directive: + [source,cs] ---- @@ -44,7 +44,7 @@ The location of the script depends on the type of Blazor app, including Blazor S ---- + -For example: +For example: + _File:_ `+Pages/Index.razor+` + @@ -58,7 +58,7 @@ _File:_ `+Pages/Index.razor+`

Welcome to your new app.

---- -* Using the component with its namespace: +* Using the component with its namespace: + [source,cs] ---- @@ -78,10 +78,10 @@ _File:_ `+Pages/Index.razor+`

Hello, world!

Welcome to your new app.

----- +---- + [IMPORTANT] -In a Blazor Web App, different render modes determine how components are rendered and how interactivity is handled. To enable JavaScript interactivity, ensure that `+@rendermode InteractiveServer+` is specified in a page component. +In a Blazor Web App, different render modes determine how components are rendered and how interactivity is handled. To enable JavaScript interactivity, ensure that `+@rendermode InteractiveServer+` is specified in a page component. + ifeval::["{productSource}" == "cloud"] @@ -91,7 +91,7 @@ ifeval::["{productSource}" == "cloud"] [source,cs] ---- ----- +---- + endif::[] @@ -101,8 +101,8 @@ ifeval::["{productSource}" != "cloud"] + [source,cs] ---- - ----- + +---- + . To load {productname} from the self-hosted package instead of the {cloudname}, configure the `+ScriptSrc+` property: diff --git a/modules/ROOT/partials/integrations/blazor-tech-ref.adoc b/modules/ROOT/partials/integrations/blazor-tech-ref.adoc index bf708c773c..bafa0b8e13 100644 --- a/modules/ROOT/partials/integrations/blazor-tech-ref.adoc +++ b/modules/ROOT/partials/integrations/blazor-tech-ref.adoc @@ -19,7 +19,7 @@ The `+TinyMCE.Blazor+` `+Editor+` component accepts the following properties: JsConfSrc="path_to_jsObj" Conf="@yourConf" ApiKey="no-api-key" - LicenseKey="your-license-key" + LicenseKey="gpl" ScriptSrc="/path/to/tinymce.min.js" ClassName="tinymce-wrapper" /> @@ -188,19 +188,29 @@ In your component: === `LicenseKey` -Specifies the {productname} license key. Required for self-hosted deployments of {productname}. This property is not required for deployments using the {cloudname}. For more information on licensing, see: xref:license-key.adoc[License key]. -*Type:* `+String+` +include::partial$integrations/common/license-key-property.adoc[] + +==== Example: Commercial license (TinyMCE 8+) +[source,cs] +---- + +---- -==== Example using LicenseKey +Use this example when you have a commercial license for TinyMCE 8 or newer. The T8LK prefix is required. +==== Example: Open source GPL license [source,cs] ---- ---- +Use this example when you're using TinyMCE under the open source GPL license in a self-hosted environment. + === `ScriptSrc` Use the `+ScriptSrc+` property to specify the location of {productname} to lazy load when the application is not using {cloudname}. This setting is required if the application uses a self-hosted version of {productname}, such as the https://www.nuget.org/packages/TinyMCE/[{productname} NuGet package] or a .zip package of {productname}. diff --git a/modules/ROOT/partials/integrations/common/license-key-property.adoc b/modules/ROOT/partials/integrations/common/license-key-property.adoc new file mode 100644 index 0000000000..815629ec26 --- /dev/null +++ b/modules/ROOT/partials/integrations/common/license-key-property.adoc @@ -0,0 +1,20 @@ +Specifies the {productname} license key. Required for self-hosted deployments of {productname}. This property is **not required** for cloud-only deployments using the {cloudname} as your cloud subscription automatically includes the commercial license. For more information, see: xref:license-key.adoc[License Key]. + +*Type:* `+String+` + +*Default value:* `+undefined+` + +*Possible values:* +* `undefined` - Use this when loading from {cloudname} with an API key +* `'gpl'` - For open source projects using GPL license +* `'T8LK:...'` - For commercial {productname} installations (must use this prefix for version 8+) +* `'GPL+T8LK:'` - For open source projects that require premium features while maintaining GPL compliance. + +[NOTE] +==== +In hybrid deployments (using both cloud and self-hosted features): + +* You can provide both an API key and a license key +* The editor will use cloud services when available +* It will automatically fall back to the local license key if cloud services are not contactable +==== diff --git a/modules/ROOT/partials/integrations/jquery-quick-start.adoc b/modules/ROOT/partials/integrations/jquery-quick-start.adoc index 9880f39997..c04e43f54a 100644 --- a/modules/ROOT/partials/integrations/jquery-quick-start.adoc +++ b/modules/ROOT/partials/integrations/jquery-quick-start.adoc @@ -119,7 +119,7 @@ ifeval::["{productSource}" == "package-manager"] @@ -149,7 +149,7 @@ ifeval::["{productSource}" == "package-manager"] + ---- The default {productname} editor will load at this location if the page is opened in a web browser. diff --git a/modules/ROOT/partials/integrations/webcomponent-tech-ref.adoc b/modules/ROOT/partials/integrations/webcomponent-tech-ref.adoc index 1640dc3354..6a421869a9 100644 --- a/modules/ROOT/partials/integrations/webcomponent-tech-ref.adoc +++ b/modules/ROOT/partials/integrations/webcomponent-tech-ref.adoc @@ -3,6 +3,7 @@ * xref:use-a-cloud-version-of-the-tinymce-web-component-integration[Use a cloud version of the {productname} Web Component integration] * xref:installing-the-tinymce-web-component-integration[Installing the {productname} Web Component integration] * xref:loading-tinymce[Loading {productname}] +* xref:licensekey[Setting the license key] * xref:configuring-the-editor[Configuring the editor] ** xref:setting-the-initial-content[Setting the initial content] ** xref:loading-plugins[Loading plugins] @@ -75,6 +76,42 @@ To use {productname} Web Component with a self-hosted copy of {productname}, ens To use {productname} from the {cloudname}, add the `+api-key+` attribute to the `+tinymce-editor+` element with an API from link:{accountpageurl}/[{accountpage}]. +[[licensekey]] +== Setting the license key + +include::partial$integrations/common/license-key-property.adoc[] + +=== Example: Commercial license +[source,html] +---- + + +---- + +=== Example: Open source GPL license +[source,html] +---- + + +---- + +[IMPORTANT] +==== +* The license key is only required when self-hosting {productname} +* License keys starting with "T8LK:" use client-side validation. +* Do not use both an API key and a license key - use API key for cloud deployments, and license key for self-hosted deployments +==== + +For more information on licensing, see: xref:license-key.adoc[License Key]. + [[configuring-the-editor]] == Configuring the editor diff --git a/modules/ROOT/partials/misc/setting-the-license.adoc b/modules/ROOT/partials/misc/setting-the-license.adoc index 57f6e78eb5..0ee4d87229 100644 --- a/modules/ROOT/partials/misc/setting-the-license.adoc +++ b/modules/ROOT/partials/misc/setting-the-license.adoc @@ -2,7 +2,7 @@ === Use {productname} with the GPLv2+ license -If the developer intends to self-host {productname} under the GPL license, they can set the `license_key` config option to 'gpl'. Case sensitivity does not matter. +If the developer intends to self-host {productname} under the GPL license and agree to its terms, they can set the `license_key` config option to 'gpl'. Case sensitivity does not matter. ==== Example @@ -18,12 +18,30 @@ tinymce.init({ If the developer intends to self-host {productname} under a commercial license, a valid license key must be provided. Customers who have purchased a self-hosted-eligible license for {productname} will find their license key in the link:https://www.tiny.cloud/auth/login/[account portal]. To purchase a commercial license, see available options on the link:{pricingpage}/[pricing page]. +The {productname} 8 commercial license key will have a `+T8LK:+` prefix. + ==== Example [source,js] ---- tinymce.init({ selector: 'textarea', // change this value according to your HTML - license_key: '' + license_key: 'T8LK:...' +}); +---- + +=== Use {productname} under GPL with Premium Features + +If the developer intends to self-host the {productname} editor under the GPL license and agree to its terms, whilst also self-hosting premium features, a valid license key must be provided. Customers who have purchased a self-hosted-eligible license for {productname} will find their license key in the link:https://www.tiny.cloud/auth/login/[account portal]. To purchase a commercial license, see available options on the link:{pricingpage}/[pricing page]. + +This type of license key is specifically for open source projects that need premium features while maintaining GPL compliance. + +The {productname} 8 commercial license key will have a `+GPL+T8LK:+` prefix. + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + license_key: 'GPL+T8LK:...' }); ---- diff --git a/modules/ROOT/partials/module-loading/bundling-vite-es6-npm_editor.adoc b/modules/ROOT/partials/module-loading/bundling-vite-es6-npm_editor.adoc index a26d8d2c51..150aef7df2 100644 --- a/modules/ROOT/partials/module-loading/bundling-vite-es6-npm_editor.adoc +++ b/modules/ROOT/partials/module-loading/bundling-vite-es6-npm_editor.adoc @@ -44,10 +44,11 @@ import contentCss from 'tinymce/skins/content/default/content.js'; export function render () { tinymce.init({ selector: 'textarea#editor', + license_key: 'gpl', plugins: 'advlist code emoticons link lists table', toolbar: 'bold italic | bullist numlist | link emoticons', skin_url: 'default', content_css: 'default', }); }; ----- \ No newline at end of file +---- From c4843a8151c5708d279e9d759bebbf966957ee2c Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Mon, 21 Jul 2025 19:53:45 +1000 Subject: [PATCH 48/60] DOC-3147: Add `crossorigin` attribute to all script tags for CORS compliance. (#3762) * DOC-3147: Add crossorigin attribute to script tags for CORS compliance. * DOC-3233: Add release notes entry for new crossorigin option, and updated script_crossorigin.adoc partial to provide examples. * DOC-3233:Refactor CORS documentation: replace script_crossorigin.adoc with crossorigin.adoc for improved clarity and organization. * DOC-3233: Update crossorigin function in release notes to match new implementaiton standard. * DOC-3147: Refactor crossorigin examples in documentation to clarify attribute handling and provide options for omitting the attribute. * DOC-3147: Fix indent issues. * DOC-3147: Update scripttag.png file to include crossorigin. * Update modules/ROOT/partials/configuration/crossorigin.adoc * Update modules/ROOT/partials/configuration/crossorigin.adoc * Update modules/ROOT/partials/configuration/crossorigin.adoc * Update modules/ROOT/partials/configuration/crossorigin.adoc * Update modules/ROOT/pages/8.0-release-notes.adoc * Update modules/ROOT/pages/editor-and-features.adoc --- modules/ROOT/images/scripttag.png | Bin 6549 -> 46908 bytes modules/ROOT/pages/8.0-release-notes.adoc | 34 ++++++++++ modules/ROOT/pages/basic-setup.adoc | 3 +- modules/ROOT/pages/cloud-troubleshooting.adoc | 6 +- modules/ROOT/pages/editor-and-features.adoc | 9 ++- modules/ROOT/pages/editor-plugin-version.adoc | 18 +++--- ...to-pdf-with-jwt-authentication-nodejs.adoc | 3 +- ...rt-to-pdf-with-jwt-authentication-php.adoc | 3 +- ...o-word-with-jwt-authentication-nodejs.adoc | 3 +- ...t-to-word-with-jwt-authentication-php.adoc | 3 +- modules/ROOT/pages/features-only.adoc | 4 +- ...m-word-with-jwt-authentication-nodejs.adoc | 3 +- ...from-word-with-jwt-authentication-php.adoc | 3 +- modules/ROOT/pages/migration-from-froala.adoc | 4 +- modules/ROOT/pages/multiple-editors.adoc | 4 +- .../plugin-editor-version-compatibility.adoc | 2 +- modules/ROOT/pages/tinymce-and-cors.adoc | 2 + modules/ROOT/pages/use-tinymce-inline.adoc | 2 +- modules/ROOT/pages/work-with-plugins.adoc | 2 +- .../partials/configuration/crossorigin.adoc | 59 ++++++++++++++++++ .../install/basic-quickstart-base.adoc | 6 +- .../integrations/bootstrap-quick-start.adoc | 2 +- .../integrations/jquery-quick-start.adoc | 4 +- .../integrations/laravel-quick-start.adoc | 2 +- .../integrations/rails-quick-start.adoc | 2 +- 25 files changed, 144 insertions(+), 39 deletions(-) create mode 100644 modules/ROOT/partials/configuration/crossorigin.adoc diff --git a/modules/ROOT/images/scripttag.png b/modules/ROOT/images/scripttag.png index 597fa5caf08a5a435b94997794be52cc09b66147..c9c5d1731b35c90bb1904bf0976e9958ce69f861 100644 GIT binary patch literal 46908 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: +=== Enhanced cross-origin resource handling + +Added a new function-based `crossorigin` configuration option that provides granular control over cross-origin resource loading. The function receives the resource URL and type (script or stylesheet) as parameters and can return 'anonymous', 'use-credentials', or undefined to control the crossorigin attribute. + +.Example: Setting `+crossorigin="anonymous"+` to script. +[source,html,subs="attributes+"] +---- + +---- +Or; + +.Example: Setting reusable constant function. +[source,js] +---- +const crossOriginFunction = (url, resourceType) => { + // Returning 'anonymous' or 'use-credentials' here would explicitly set the attribute + return 'anonymous'; + // return 'use-credentials'; + // return undefined; // Omits the 'crossorigin' attribute for all resources by returning undefined +}; + +tinymce.init({ + selector: "textarea", + crossorigin: crossOriginFunction +}); +---- + +For more details, see: xref:configure-cross-origin-resource-loading.adoc#crossorigin[crossorigin]. + +This improvement ensures consistent resource loading behavior across different deployment scenarios and provides better control over CORS settings for both scripts and stylesheets. + +For more details, see xref:tinymce-and-cors.adoc#crossorigin[crossorigin configuration option] documentation. + === Tooltips can now be closed by pressing the `escape` key. // #TINY-12054 @@ -334,6 +367,7 @@ Split buttons in {productname} {release-version} now render as two independent, Previously, menu items and tooltips containing three consecutive periods (`...`) were read aloud by the JAWS screen reader as "dot dot dot," which could confuse users relying on assistive technologies. To enhance accessibility, the `translate` API in {productname} {release-version} now automatically replaces three dots with the typographic ellipsis character (`…`) across all translations. This update ensures a consistent visual appearance while improving screen reader behavior, as the ellipsis character is not read aloud. The change is implemented directly in the translation function, ensuring comprehensive coverage across all languages. + [[additions]] == Additions diff --git a/modules/ROOT/pages/basic-setup.adoc b/modules/ROOT/pages/basic-setup.adoc index 1bbc271311..5f11695e13 100644 --- a/modules/ROOT/pages/basic-setup.adoc +++ b/modules/ROOT/pages/basic-setup.adoc @@ -198,7 +198,8 @@ The following example is a basic {productname} configuration. + ---- In this case, the editor will be in a **read-only** state, and a notification appears stating: **"A valid API key is required to continue using {productname}. Please alert the admin to check the current API key. Click here to learn more."** @@ -47,7 +47,7 @@ For example: if your API is `+abcd1234+`: + [source,html,subs="attributes+"] ---- - + ---- + . Check the `+apiKey+` provided in the script tag: @@ -82,7 +82,7 @@ For example: if your API is `+abcd1234+`: [source,html,subs="attributes+"] ---- - + ---- To retrieve your API key, or to sign up for an API key, visit: link:{accountsignup}/[{cloudname}]. diff --git a/modules/ROOT/pages/editor-and-features.adoc b/modules/ROOT/pages/editor-and-features.adoc index 96b67a2cac..8868ce3fe3 100644 --- a/modules/ROOT/pages/editor-and-features.adoc +++ b/modules/ROOT/pages/editor-and-features.adoc @@ -20,7 +20,7 @@ The following example adds a script tag into the application that inserts the co [source,html,subs="attributes+"] ---- - + ---- [cols="1,2,12",options="header"] @@ -28,6 +28,7 @@ The following example adds a script tag into the application that inserts the co | |Value |Description |1 |no-api-key |Replace with your api key |2 |origin |A `+referrerpolicy+` specifies how much of the current page's URL is sent in the `+Referer+` header when the browser fetches page resources (for example, the {productname} editor). The use of the `+Referer+` header ensures API keys are only used on domains registered to their owners. We only care about the domain portion however (similar to the operation of `+Origin+` header), so for improved performance and privacy always set the `+referrerpolicy+` to `+origin+` when requesting {cloudname} resources. +|3 |anonymous |the `+crossorigin="anonymous"+` attribute is required on all script tags loading {productname} from {cloudname}. This attribute ensures consistent Origin header behavior for license key validation and improves security for cross-origin script loading. |=== image::scripttag.png[Script Tag Description] @@ -79,13 +80,15 @@ Migrating from a self-hosted environment to {cloudname} is easy. Remove the exis NOTE: The script tag typically references `+tinymce.min.js+` hosted within the application or available at a legacy CDN. -Replace the script tag with the following: +Replace the script tag with the following, making sure to include both required attributes (`referrerpolicy` and `crossorigin`): [source,html,subs="attributes+"] ---- - + ---- +NOTE: When migrating to {cloudname}, both the `referrerpolicy="origin"` and `crossorigin="anonymous"` attributes are required for optimal performance and cross-browser functionality. + === Step 2: Update custom plugin paths Reference xref:editor-important-options.adoc#external_plugins[external_plugins] to ensure custom plugins or modified plugins continue to function in the {cloudname} deployment. diff --git a/modules/ROOT/pages/editor-plugin-version.adoc b/modules/ROOT/pages/editor-plugin-version.adoc index 34356c31a5..25113309f6 100644 --- a/modules/ROOT/pages/editor-plugin-version.adoc +++ b/modules/ROOT/pages/editor-plugin-version.adoc @@ -10,21 +10,21 @@ The example below shows the default way to load {productname} {productmajorversi [source,html,subs="attributes+"] ---- - + ---- To load a specific version of {productname} {productmajorversion} other than the latest release, replace the `{productmajorversion}` in the URL with the desired version. For example, to load a minor version such as {productname} `{productmajorversion}.1`, use the following URL: [source,html,subs="attributes+"] ---- - + ---- To load a specific patch version, replace the `{productmajorversion}` in the URL with the desired patch version. For example, to load {productname} `{productmajorversion}.1.2`, use the following URL: [source,html,subs="attributes+"] ---- - + ---- [TIP] @@ -55,7 +55,7 @@ This channel deploys the latest release of {productname} that has passed our qua [source,html,subs="attributes+"] ---- - + ---- [#{productmajorversion}-testing-release-channel] @@ -68,7 +68,7 @@ This channel deploys the current *release candidate* for the `{productmajorversi [source,html,subs="attributes+"] ---- - + ---- [#{productmajorversion}-dev-release-channel] @@ -86,7 +86,7 @@ The current version of {productname} available on the `{productmajorversion}-dev [source,html,subs="attributes+"] ---- - + ---- For more details, check out the xref:editor-and-features.adoc[{productname} editor via {cloudname}]. @@ -106,7 +106,7 @@ The `plugins.min.js` script loads every premium plugin the API key is entitled t [source,html,subs="attributes+"] ---- - + ---- === `plugins.min.js` with Exclusions for Specific Plugins @@ -115,7 +115,7 @@ To exclude specific premium plugins from `plugins.min.js` because you are self-h [source,html,subs="attributes+"] ---- - + ---- [NOTE] @@ -131,7 +131,7 @@ The `cloud-plugins.min.js` script allows loading of specific premium plugins fro [source,html,subs="attributes+"] ---- - + ---- [NOTE] diff --git a/modules/ROOT/pages/export-to-pdf-with-jwt-authentication-nodejs.adoc b/modules/ROOT/pages/export-to-pdf-with-jwt-authentication-nodejs.adoc index e597a4f8d9..f30e8a5dae 100644 --- a/modules/ROOT/pages/export-to-pdf-with-jwt-authentication-nodejs.adoc +++ b/modules/ROOT/pages/export-to-pdf-with-jwt-authentication-nodejs.adoc @@ -30,7 +30,8 @@ Inside the `public` folder where you created the `index.html` file add the HTML TinyMCE with Export to PDF + ---- == Step 2: Specify purchased TinyMCE plugins and toolbar buttons @@ -37,7 +37,7 @@ The following is a complete example, where: - + diff --git a/modules/ROOT/pages/import-from-word-with-jwt-authentication-nodejs.adoc b/modules/ROOT/pages/import-from-word-with-jwt-authentication-nodejs.adoc index 51078cfd4d..13cd80da77 100644 --- a/modules/ROOT/pages/import-from-word-with-jwt-authentication-nodejs.adoc +++ b/modules/ROOT/pages/import-from-word-with-jwt-authentication-nodejs.adoc @@ -30,7 +30,8 @@ Inside the `public` folder where you created the `index.html` file add the HTML TinyMCE with Import from Word + ---- + Replace `+no-api-key+` with your link:{accountpageurl}/[{cloudname} API key]. @@ -119,7 +119,7 @@ The following examples show an initial Froala configuration and the migrated {pr - +

diff --git a/modules/ROOT/pages/multiple-editors.adoc b/modules/ROOT/pages/multiple-editors.adoc index dd395fb803..fc6eab32dc 100644 --- a/modules/ROOT/pages/multiple-editors.adoc +++ b/modules/ROOT/pages/multiple-editors.adoc @@ -14,7 +14,7 @@ The following example breaks the page into two separate editable areas. Each are - + + ---- diff --git a/modules/ROOT/pages/tinymce-and-cors.adoc b/modules/ROOT/pages/tinymce-and-cors.adoc index 5f0a7d2c8c..b08cfbccfc 100644 --- a/modules/ROOT/pages/tinymce-and-cors.adoc +++ b/modules/ROOT/pages/tinymce-and-cors.adoc @@ -5,6 +5,8 @@ == Cross-Origin Resource Sharing related options +include::partial$configuration/crossorigin.adoc[leveloffset=+1] + include::partial$configuration/referrer_policy.adoc[leveloffset=+1] include::partial$configuration/content_css_cors.adoc[leveloffset=+1] diff --git a/modules/ROOT/pages/use-tinymce-inline.adoc b/modules/ROOT/pages/use-tinymce-inline.adoc index 35add3adf8..c3b580a7b5 100644 --- a/modules/ROOT/pages/use-tinymce-inline.adoc +++ b/modules/ROOT/pages/use-tinymce-inline.adoc @@ -26,7 +26,7 @@ Inline mode only works on content within a block element (such as: `+div+` or `+ - + + +---- +==== + +[TIP] +==== +* The crossorigin function runs for both scripts and stylesheets loaded by {productname}. +* Using `+'anonymous'+` sends the Origin header without credentials. +* Using `+'use-credentials'+` sends the Origin header with credentials (not recommended for most cases). +* Returning `undefined` means no crossorigin attribute will be set, as it omits the attribute entirely for the resource. +* For stylesheet resources, the `+content_css_cors+` option takes precedence over the `+crossorigin+` function. See: xref:add-css-options.adoc#content_css_cors[content_css_cors] for details about cross-origin stylesheet loading. +==== + + +For more details on the crossorigin attribute, see: link:https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin[MDN Web Docs - HTML attribute: crossorigin]. diff --git a/modules/ROOT/partials/install/basic-quickstart-base.adoc b/modules/ROOT/partials/install/basic-quickstart-base.adoc index 4ef25386f9..79c886efbd 100644 --- a/modules/ROOT/partials/install/basic-quickstart-base.adoc +++ b/modules/ROOT/partials/install/basic-quickstart-base.adoc @@ -131,7 +131,7 @@ Include the following line of code in the `++` of an HTML page. [source,html,subs="attributes+"] ---- - + ---- == Initialize {productname} as part of a web form @@ -151,7 +151,7 @@ ifeval::["{productSource}" == "cloud"] - + + + ---- + Replace `+no-api-key+` in the source script (`+ + ---- + Replace `no-api-key` in the source script (` - + diff --git a/modules/ROOT/partials/integrations/laravel-quick-start.adoc b/modules/ROOT/partials/integrations/laravel-quick-start.adoc index 6fef50d567..9892c1d6d6 100644 --- a/modules/ROOT/partials/integrations/laravel-quick-start.adoc +++ b/modules/ROOT/partials/integrations/laravel-quick-start.adoc @@ -115,7 +115,7 @@ _File:_ `+resources/views/components/head/tinymce-config.blade.php+` + [source,html,subs="attributes+"] ---- - + + + + +---- + +[IMPORTANT] +==== +* The license key manager is automatically included when using {companyname} Cloud. +* The plugin does not need to be added to the `plugins` configuration option. +* For bundled applications, the license key manager must be loaded before {productname} initialization. +* For bundled applications, ensure the license key manager is not excluded during build optimization. +==== + +For complete details on license key manager setup and troubleshooting, see xref:license-key.adoc##setting-up-the-commercial-license-key-manager[Setting up the Commercial License Key Manager]. + +**License Migration checklist:** + +* [ ] Contact support for new {productname} {release-version} license key or use GPL for the open source version +* [ ] Install license key manager addon for commercial licenses +* [ ] Update configuration with new license key format +* [ ] Test editor functionality with new license +* [ ] Verify all premium features are working + +[[dompurify-update-breaking-change]] +=== DOMPurify Update and Stricter Sanitization (Breaking Change) +// #TINY-12056 + +{productname} {release-version} updates the DOMPurify dependency to version 3.2.6 and enables the `SAFE_FOR_XML` flag by default. This is a breaking change: content that previously passed sanitization in {productname} 7 may now be stripped or altered during the sanitization process. + +[IMPORTANT] +==== +This change improves security and aligns with DOMPurify's recommended defaults. However, existing content and integrations that relied on the previous, less strict sanitization behavior may be impacted. +==== + +**Key Changes**: + +* **DOMPurify upgraded to 3.2.6** +* **`SAFE_FOR_XML` enabled** — This setting enforces stricter handling of comments and attribute values, preventing certain XSS vectors. +* **Content Impact** — HTML comments containing tags, Internet Explorer conditional comments, and attributes with HTML-like values may now be removed during sanitization. Content that was previously allowed may be stripped. + +**Impact**: This change improves security by preventing potential XSS attacks through comments and attributes that were previously allowed. However, it may also result in content being stripped or altered unexpectedly. + +**Migration Steps:** + +* Review workflows and test content that previously relied on relaxed sanitization. +* {productname} now provides the xref:content-filtering.adoc#allow_html_in_comments[Content Filtering: allow_html_in_comments option] option. Enabling this option allows HTML tags in comments with sanitization still enabled. + +[WARNING] +Using `allow_html_in_comments` increases the risk of XSS vulnerabilities. xref:security.adoc#allow_html_in_comments[allow_html_in_comments] is not recommended for production use unless you fully understand the implications and have appropriate security measures in place. + +.Example: Content Differences +|=== +|Content |{productname} 7 Output |{productname} {release-version} Output + +|`
` +|`
` +|`
` + +|`` +|`

` +|`` + +|`` +|`` +|`` +|=== + +[NOTE] +==== +For information on disabling DOMPurify sanitization (not recommended), see xref:security.adoc#xss_sanitization-option[xss_sanitization option]. +==== + +== Core Changes + +[[split-button-css-breaking-change]] +=== Split Button Styling Update for Custom Skins +// #TINY-8665 + +{productname} {productmajorversion}, xref:custom-split-toolbar-button.adoc[split toolbar buttons] now render as two distinct components: one for the primary action and one for the dropdown chevron. + +This structural change modifies the DOM layout of split buttons and may break custom CSS rules that rely on the previous structure. + +**Impact**: This change only affects integrators using *custom skins*. + +**Migration Guide:** + +If your implementation includes a custom skin, follow these steps to ensure compatibility: + +* [ ] Confirm whether your project uses a custom skin. +* [ ] **Rebuild your custom skin** using the {productname} {productmajorversion} codebase. See xref:creating-a-skin.adoc[Creating a Skin] for instructions. +* [ ] **Update your split button usage** to align with the new structure, including support for the `chevronTooltip` option. Refer to xref:custom-split-toolbar-button.adoc[Split Toolbar Buttons] for updated configuration details. +* [ ] **Test the rendering and interaction** of split buttons in your editor to verify expected behavior. + +**Summary of Changes:** + +* Split buttons now render as two separate DOM elements. +* CSS selectors and styles that depended on the old structure may no longer apply correctly. +* The `chevronTooltip` API option is now supported. + + +== Core API Changes + +[discrete] +=== Breaking Changes Overview + +IMPORTANT: The following sections detail important changes that require updates to your code. Please review each section carefully. + +=== Updated Methods + +[[skipfocus-consolidation]] +==== skipFocus and skip_focus +// #TINY-12044 + +The `skipFocus` and `skip_focus` options for the `ToggleToolbarDrawer` command have been consolidated into a single, more consistent argument. This reduces API complexity and clarifies the intended behavior. + +**Impact**: This change simplifies focus management, reducing the risk of confusion and unexpected behavior. + +**Migration steps:** + +[source, javascript] +---- +// Old approach (Deprecated) in TinyMCE 8 +editor.execCommand('ToggleToolbarDrawer', false, { skipFocus: true }) + +// New approach (Recommended) +editor.execCommand('ToggleToolbarDrawer', false, null, { skip_focus: true }) +---- + +**Migration checklist:** + +* [ ] Locate all instances of `ToggleToolbarDrawer` command usage +* [ ] Replace `skip_focus` with `skipFocus` in command options +* [ ] Update any custom plugins using this command +* [ ] Test toolbar drawer behavior after changes + +''' + +=== Removed Methods + +[[editor-documentbaseurl-removal]] +==== editor.documentBaseUrl +[.discrete] +// #TINY-12182 + +The undocumented `editor.documentBaseUrl` property has been removed. + +.Example Usage +[source,javascript] +---- +// Removed in TinyMCE 8 +console.log('documentBaseUrl', editor.documentBaseUrl); + +// Use this instead +console.log('documentBaseURI', editor.documentBaseURI.getURI()); +---- + +TIP: Use `editor.documentBaseURI.getURI()` for all base URL operations. + +**Impact**: This change improves URL handling consistency by removing an undocumented API that was not aligned with the documented `documentBaseURI` property. + +**Migration steps:** + +To update all references of `documentBaseUrl` to the new API, replace any usage of `editor.documentBaseUrl` (or similar) with `editor.documentBaseURI.getURI()`. The property `documentBaseUrl` has been removed, and the correct way to access the document base URL is now through the `documentBaseURI` property, which is a URI object. You can then call `.getURI()` on it to get the string value of the URL. + +.For example, update this: +[source, js] +---- +const baseUrl = editor.documentBaseUrl; +---- + +to: + +[source, js] +---- +const baseUrl = tinymce.activeEditor.documentBaseURI.getURI(); +---- + +This change is necessary because the undocumented `editor.documentBaseUrl` API has been removed to improve URL handling consistency. The new approach uses the documented `documentBaseURI` property, which provides a URI object with methods such as `getURI()` to retrieve the full URL string. + +For more information see: link:https://www.tiny.cloud/docs/tinymce/latest/apis/tinymce.editor/#properties[tinymce.editor/#properties]. + +**Migration checklist:** + +* [ ] Search your codebase for all instances of `editor.documentBaseUrl`. +* [ ] Replace them with `tinymce.activeEditor.documentBaseURI.getURI()` (or `editor.documentBaseURI.getURI()` if you have an `editor` reference). + +''' + +=== Deprecated Methods + +[[editor-selection-setcontent-deprecated]] +==== editor.selection.setContent +[.discrete] +// #TINY-12109 + +The `editor.selection.setContent` API has been deprecated and will be removed in {productname} 9. + +*Impact*: This change simplifies content manipulation by consolidating insertion methods. + +**Migration steps:** + +To replace `editor.selection.setContent`, use `editor.insertContent` instead. The new method is more consistent with other content manipulation methods in {productname}. + +.Example Usage +[source,javascript] +---- +// Deprecated in TinyMCE 8, will be removed in 9 +editor.selection.setContent('

New content

'); + +// Recommended replacement +editor.insertContent('

New content

'); +---- + +**Migration checklist:** + +* [ ] Replace all instances of `editor.selection.setContent` with `editor.insertContent` +* [ ] Update custom plugins that use the old method +* [ ] Test content insertion in your editor instances + +[[fire-method-deprecation]] +==== `fire()` +// #TINY-12012, ref TINY-8102 + +The `fire()` method has been replaced by `dispatch()` for event handling. The `fire()` method will be removed in {productname} 9 to avoid confusion with its name. + +[source, javascript] +---- +// Deprecated in TinyMCE 8, will be removed in 9 +// Old approach for dispatching custom events +editor.fire('someEvent'); + +// New approach for dispatching custom events +editor.dispatch('someEvent'); +---- + +**Impact**: This change aligns {productname} with modern event handling conventions, making the API more intuitive for developers. + +**Migration checklist:** + +* [ ] Search codebase for all uses of the `fire()` method +* [ ] Replace each instance with `dispatch()` +* [ ] Review and update third-party plugins +* [ ] Test all custom event handling + +''' + +=== Plugin Updates + +==== Language Pack Filename Changes +// #TINY-12090 + +Language pack filenames have been standardized to follow the RFC5646 format. This update ensures consistent language handling across platforms and improves internationalization support. While both the legacy underscore format (e.g., `en_GB.js`) and the new hyphenated format (e.g., `en-GB.js`) are supported in {productname} {release-version}, the underscore format is deprecated and will be removed in {productname} 9. Migrating to the RFC5646 format now will ensure future compatibility and reduce maintenance overhead during upcoming upgrades. + +**Impact**: Custom language packs and configurations using the underscore-based format should update before upgrading to {productname} 9 to avoid loading failures. + +**Migration checklist:** + +* [ ] Identify all language pack files in your deployment +* [ ] Rename files to RFC5646 format (e.g., `en_GB.js` → `en-GB.js`) +* [ ] Update configuration references to language files +* [ ] Update build scripts that handle language files +* [ ] Test language switching in your application +* [ ] Update custom translation files to use the new format + +[source, javascript] +---- +// Deprecated format (supported only in versions 8.x) +language_url: '/langs/en_GB.js' + +// Recommended format +language_url: '/langs/en-GB.js' +---- + +[IMPORTANT] +Support for the underscore format will be removed in {productname} 9. Early migration is recommended. + +==== Update to Image and Accessibility Checker Plugins +// #TINY-12226 + +The Image and Accessibility Checker plugins now follow the latest W3C standards for decorative images, requiring an empty alt attribute rather than a `+role="presentation"+` attribute. This change helps improve accessibility support. + +**Impact**: Customers using these plugins will need to update their configurations to ensure continued compliance with accessibility standards. + +**Migration checklist:** + +* [ ] Identify images previously using `role="presentation"` for decorative purposes in your content +* [ ] Replace those with empty alt attributes `alt=""` +* [ ] Update image plugin configuration if customized +* [ ] Test accessibility checker with updated content + +For more information on the changes, see: xref:a11ychecker.adoc##image-rules[Accessibility Checker: Image rules]. + +=== Cross-Origin Resource Loading Configuration +// #TINY-12228, TINY-12326 + +When upgrading to {productname} 8, you will need to review and possibly update how your integration handles cross-origin resource loading. {productname} 8 provides a new configuration option for controlling the `crossorigin` attribute on loaded resources. + +**What to check:** + +. If you're using {cloudname}: ++ +* Ensure your script tag includes both required attributes: ++ +[source,html,subs="attributes+"] +---- + +---- ++ +. If your application loads resources (scripts or stylesheets) from different domains: ++ +* Configure the new crossorigin function to control the `crossorigin` attribute for all resources. ++ +.Example: Configuring the crossorigin function +[source, javascript] +---- +const crossOriginFunction = (url, resourceType) => { + // Returning 'anonymous' or 'use-credentials' here would explicitly set the attribute + return 'anonymous'; + // return 'use-credentials'; + // return undefined; // Omits the 'crossorigin' attribute for all resources by returning undefined +}; + +tinymce.init({ + selector: "textarea", + crossorigin: crossOriginFunction +}); +---- ++ +. If you're using content_css from a different domain: + +* The `content_css_cors` option takes precedence for stylesheets. +* Review your `content_css` configuration if you use cross-origin stylesheets. + +**Migration checklist:** + +* [ ] Verify script tag attributes for Cloud deployments. +* [ ] Configure `crossorigin` function if using cross-origin resources. +* [ ] Test resource loading in your deployment environment. +* [ ] Review `content_css` configuration if using cross-origin stylesheets. + +For complete details on the new crossorigin function API, see: xref:tinymce-and-cors.adoc#crossorigin[crossorigin configuration option]. + +=== Technical Cleanup + +==== Removed Empty Files +// #TINY-11287, #TINY-12084 + +Several empty files have been removed from the codebase to reduce clutter and improve maintenance: + +* Empty CSS file from the **Comments** plugin +* Empty LESS file from the **Mentions** plugin + +**Impact**: These changes have no functional impact but may affect custom build processes that explicitly reference these files. + +**Migration checklist:** + +* [ ] Check build processes for references to Comments plugin CSS +* [ ] Check build processes for references to Mentions plugin LESS +* [ ] Remove any imports of these empty files +* [ ] Test Comments and Mentions plugins after removal + +=== Service and Configuration Changes + +==== Discontinuation of Medical English (UK) +// #EPIC-255 + +[WARNING] +The "Medical English (UK)" dictionary has been removed due to licensing constraints. Customers using this feature must update their configurations accordingly. + +**Impact**: Users relying on this dictionary will need to make alternative arrangements for medical-specific spell checking. + +**Migration checklist:** + +* [ ] Remove "Medical English (UK)" from spellchecker configurations +* [ ] Remove any custom dictionary integrations related to Medical English +* [ ] Test spellchecker functionality with remaining dictionaries +* [ ] Configure alternative medical dictionary if required + +==== Decoupling of Service Versions from {productname} Editor +// #EPIC-247, #EPIC-265 + +Services previously bundled with the editor, such as Java Servlet services, are no longer included in {productname} {release-version} packages. Customers should migrate to xref:bundle-intro-setup.adoc[Containerized service deployments] or consider alternative hosting options. + +**Impact**: This reduces the dependency between the editor and backend services, simplifying updates and maintenance. + +**Migration steps:** + +* Update the applications deployment architecture to use xref:bundle-intro-setup.adoc[Containerized services] where applicable + +==== Transition from Java WAR Files to Containerized Services +// #EPIC-247 + +{productname} {release-version} no longer includes Java WAR files for backend services like the spell checker. Customers are required to migrate to modern Docker/OCI containers for self-hosted deployments. + +**Impact**: This reduces infrastructure complexity and aligns with modern DevOps practices. + +**Migration checklist:** + +* [ ] Inventory current WAR file deployments +* [ ] Review containerization requirements for your environment +* [ ] Plan transition timeline to containerized services +* [ ] Set up container infrastructure (Docker/Kubernetes) +* [ ] Deploy and test containerized services +* [ ] Update service connection configurations +* [ ] Contact link:{supporturl}/[{supportname}] if legacy WAR files are still needed + +For more information on deploying the server-side components using Docker, see: xref:bundle-intro-setup.adoc[Containerized service deployments]. + +== Conclusion + +Upgrading to {productname} {release-version} requires integrators to update their API calls, plugin configurations, and service integrations to accommodate the breaking changes introduced in this release. While some adjustments may involve significant code updates, these enhancements are intended to simplify development, and improve the overall editor experience. + +For more guidance, refer to the: + +* link:https://www.tiny.cloud/docs[{productname} Documentation]. +* link:https://www.tiny.cloud/contact/[Contact {supportname}] for assistance. +* Try {productname}’s new **Ask AI** widget is ready to assist you, just click the icon in the bottom-right corner of any documentation page. + +image::ask-ai/ask-ai-widget.png[Ask AI Widget, width=600, align="left"] + +== Additional Resources + +For additional details on {productname} {release-version} changes, see xref:8.0-release-notes.adoc#overview[{productname} {release-version} release notes]. diff --git a/modules/ROOT/partials/security/sanitizing-html-input-and-protecting-against-xss-attacks-dom-parser-and-dom-purify.adoc b/modules/ROOT/partials/security/sanitizing-html-input-and-protecting-against-xss-attacks-dom-parser-and-dom-purify.adoc index 4038fe8c91..d1d9fbe6e3 100644 --- a/modules/ROOT/partials/security/sanitizing-html-input-and-protecting-against-xss-attacks-dom-parser-and-dom-purify.adoc +++ b/modules/ROOT/partials/security/sanitizing-html-input-and-protecting-against-xss-attacks-dom-parser-and-dom-purify.adoc @@ -48,6 +48,7 @@ As of {productname} 6.4, however, it is possible to turn DOMPurify off using the NOTE: `xss_sanitization` is set to `true` by default. That is, {productname} specifically sets the `xss_sanitization` option to `true`, even if this option is not declared in a {productname} configuration. +[[xss_sanitization-option]] *Type:* `+Boolean+` *Default value:* `+true+` @@ -65,3 +66,8 @@ tinymce.init({ ---- WARNING: Turning DomPurify off leaves {productname}, and any application using {productname}, extremely vulnerable to XSS attacks. Only turn DomPurify off if alternative and equivalently capable HTML and XML sanitization and XSS protections are in place. + +[NOTE] +==== +{productname} {release-version} upgrades DOMPurify to version 3.2.6 and enables the `SAFE_FOR_XML` flag by default. This enforces stricter sanitization, which may remove or alter content that previously passed in {productname} 7. For more information see xref:migration-from-7x.adoc#dompurify-update-breaking-change[Migration Guide] +==== From 79eb9b5c8343f18a3bb6cfec1e77a067631ef327 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 22 Jul 2025 20:16:21 +1000 Subject: [PATCH 52/60] DOC-3147: Add suggestededits to new premium plugin section in release notes. --- modules/ROOT/nav.adoc | 1 + modules/ROOT/pages/8.0-release-notes.adoc | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc index f1833cd2e2..168483013e 100644 --- a/modules/ROOT/nav.adoc +++ b/modules/ROOT/nav.adoc @@ -414,6 +414,7 @@ ** xref:release-notes.adoc[Release notes for {productname}] *** {productname} 8.0 **** xref:8.0-release-notes.adoc#overview[Overview] +**** xref:new-premium-plugins[New Premium plugins] **** xref:8.0-release-notes.adoc#accompanying-premium-plugin-changes[Accompanying Premium plugin changes] **** xref:accompanying-enhanced-skins-and-icon-packs-changes[Accompanying Enhanced Skins & Icon Packs changes] **** xref:8.0-release-notes.adoc#improvements[Improvements] diff --git a/modules/ROOT/pages/8.0-release-notes.adoc b/modules/ROOT/pages/8.0-release-notes.adoc index 937d974466..7604c6faae 100644 --- a/modules/ROOT/pages/8.0-release-notes.adoc +++ b/modules/ROOT/pages/8.0-release-notes.adoc @@ -13,6 +13,7 @@ include::partial$misc/admon-releasenotes-for-stable.adoc[] {productname} {release-version} was released for {enterpriseversion} and {cloudname} on Wednesday, July 23^rd^, 2025. These release notes provide an overview of the changes for {productname} {release-version}, including: +* xref:new-premium-plugins[New Premium plugins] * xref:accompanying-premium-plugin-changes[Accompanying Premium plugin changes] * xref:accompanying-enhanced-skins-and-icon-packs-changes[Accompanying Enhanced Skins & Icon Packs changes] * xref:improvements[Improvements] @@ -26,6 +27,19 @@ include::partial$misc/admon-releasenotes-for-stable.adoc[] This release includes breaking changes to the license key system. All commercial self-hosted deployments must update their license keys to use the new `T8LK:` prefix format. For details on this and other breaking changes when considering upgrading, see xref:migration-from-7x.adoc[Migrating from {productname} 7 to {productname} {release-version}]. ==== +[[new-premium-plugins]] +== New Premium plugins + +The following new Premium plugin was released alongside {productname} {release-version}. + +=== Suggested Edits + +The {productname} {release-version} release includes an accompanying release of the **Suggested Edits** premium plugin. + +The **Suggested Edits** plugin allows multiple users to collaborate on a document. The review window shows which user suggested which edits, whether they added, removed, modified, or replaced any content, and allows users to provide feedback on those suggestions or give a final review by accepting or rejecting them. + +For information on the **Suggested Edits** plugin, see: xref:suggestededits.adoc[Suggested Edits]. + [[accompanying-premium-plugin-changes]] == Accompanying Premium plugin changes From b87c34e455cf19b5bad98af26db6f7eb03456da1 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Tue, 22 Jul 2025 21:30:14 +1000 Subject: [PATCH 53/60] DOC-3147: Add suggestededits to full-feature demo. --- antora.yml | 8 +- .../live-demos/full-featured/example.js | 21 +- .../live-demos/full-featured/index.js | 449 +++++++++++++++++- modules/ROOT/pages/security.adoc | 4 +- 4 files changed, 465 insertions(+), 17 deletions(-) diff --git a/antora.yml b/antora.yml index 19391046b8..b869358057 100644 --- a/antora.yml +++ b/antora.yml @@ -8,10 +8,10 @@ asciidoc: idseparator: '-@' # generic variables companyurl: https://www.tiny.cloud - cdnurl: https://cdn.tiny.cloud/1/no-api-key/tinymce/7/tinymce.min.js - tdcdnurl: https://cdn.tiny.cloud/1/_your_api_key_/tinydrive/7/tinydrive.min.js - tinymce_live_demo_url: https://cdn.tiny.cloud/1/qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc/tinymce/7/tinymce.min.js - tinydrive_live_demo_url: https://cdn.tiny.cloud/1/qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc/tinydrive/7/tinydrive.min.js + cdnurl: https://cdn.tiny.cloud/1/no-api-key/tinymce/8-testing/tinymce.min.js + tdcdnurl: https://cdn.tiny.cloud/1/_your_api_key_/tinydrive/8-testing/tinydrive.min.js + tinymce_live_demo_url: https://cdn.tiny.cloud/1/qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc/tinymce/8-testing/tinymce.min.js + tinydrive_live_demo_url: https://cdn.tiny.cloud/1/qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc/tinydrive/8-testing/tinydrive.min.js webcomponent_url: https://cdn.jsdelivr.net/npm/@tinymce/tinymce-webcomponent/dist/tinymce-webcomponent.min.js jquery_url: https://cdn.jsdelivr.net/npm/@tinymce/tinymce-jquery@2/dist/tinymce-jquery.min.js openai_proxy_url: https://openai.ai-demo-proxy.tiny.cloud/v1/chat/completions diff --git a/modules/ROOT/examples/live-demos/full-featured/example.js b/modules/ROOT/examples/live-demos/full-featured/example.js index f3069b013d..a5cb112594 100644 --- a/modules/ROOT/examples/live-demos/full-featured/example.js +++ b/modules/ROOT/examples/live-demos/full-featured/example.js @@ -8,15 +8,18 @@ const openai_api_key = ""; const isSmallScreen = window.matchMedia('(max-width: 1023.5px)').matches; +const tinymceElement = document.querySelector('textarea#full-featured'); +const model = tinymceElement.getAttribute('suggestededits-model'); + tinymce.init({ selector: 'textarea#full-featured', - plugins: 'importword exportword exportpdf ai preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker editimage help formatpainter permanentpen pageembed charmap tinycomments mentions quickbars linkchecker emoticons advtable footnotes mergetags autocorrect typography advtemplate markdown revisionhistory', + plugins: 'importword exportword exportpdf ai suggestededits preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker editimage help formatpainter permanentpen pageembed charmap tinycomments mentions quickbars linkchecker emoticons advtable footnotes mergetags autocorrect typography advtemplate markdown revisionhistory', tinydrive_token_provider: 'URL_TO_YOUR_TOKEN_PROVIDER', tinydrive_dropbox_app_key: 'YOUR_DROPBOX_APP_KEY', tinydrive_google_drive_key: 'YOUR_GOOGLE_DRIVE_KEY', tinydrive_google_drive_client_id: 'YOUR_GOOGLE_DRIVE_CLIENT_ID', mobile: { - plugins: 'ai preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker help formatpainter pageembed charmap mentions quickbars linkchecker emoticons advtable footnotes mergetags autocorrect typography advtemplate', + plugins: 'ai suggestededits preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker help formatpainter pageembed charmap mentions quickbars linkchecker emoticons advtable footnotes mergetags autocorrect typography advtemplate', }, menu: { tc: { @@ -25,7 +28,7 @@ tinymce.init({ } }, menubar: 'file edit view insert format tools table tc help', - toolbar: "undo redo | importword exportword exportpdf | revisionhistory | aidialog aishortcuts | blocks fontsizeinput | bold italic | align numlist bullist | link image | table math media pageembed | lineheight outdent indent | strikethrough forecolor backcolor formatpainter removeformat | charmap emoticons checklist | code fullscreen preview | save print | pagebreak anchor codesample footnotes mergetags | addtemplate inserttemplate | addcomment showcomments | ltr rtl casechange | spellcheckdialog a11ycheck", // Note: if a toolbar item requires a plugin, the item will not present in the toolbar if the plugin is not also loaded. + toolbar: "undo redo | importword exportword exportpdf | suggestededits | revisionhistory | aidialog aishortcuts | blocks fontsizeinput | bold italic | align numlist bullist | link image | table math media pageembed | lineheight outdent indent | strikethrough forecolor backcolor formatpainter removeformat | charmap emoticons checklist | code fullscreen preview | save print | pagebreak anchor codesample footnotes mergetags | addtemplate inserttemplate | addcomment showcomments | ltr rtl casechange | spellcheckdialog a11ycheck", // Note: if a toolbar item requires a plugin, the item will not present in the toolbar if the plugin is not also loaded. autosave_ask_before_unload: true, autosave_interval: '30s', autosave_prefix: '{path}{query}-{id}-', @@ -439,4 +442,16 @@ tinymce.init({ mentions_menu_complete: mentions_menu_complete, // TODO: Implement mentions_menu_complete mentions_select: mentions_select, // TODO: Implement mentions_select mentions_item_type: "profile", + + // Suggested edits plugin settings + user_id: 'kalebwilson', + fetch_users: (userIds) => Promise.all(userIds + .map((userId) => + fetch(`/users/${userId}`) // Fetch user data from the server + .then((response) => response.json()) + .catch(() => ({ id: userId })) // Still return a valid user object even if the fetch fails + )), + suggestededits_model: model, + suggestededits_access: 'full', + suggestededits_content: 'html' }); diff --git a/modules/ROOT/examples/live-demos/full-featured/index.js b/modules/ROOT/examples/live-demos/full-featured/index.js index 3a6655ff7f..21fa722a1a 100644 --- a/modules/ROOT/examples/live-demos/full-featured/index.js +++ b/modules/ROOT/examples/live-demos/full-featured/index.js @@ -412,9 +412,432 @@ tinymce.ScriptLoader.loadScripts(['https://cdn.jsdelivr.net/npm/faker@5/dist/fak ]); }; + /** Fake user database for suggested edits */ + const suggestededitsUserDb = { + adamhayes: { + id: 'adamhayes', + name: 'Adam Hayes', + avatar: `https://randomuser.me/api/portraits/men/4.jpg`, + }, + martincook: { + id: 'martincook', + name: 'Martin Cook', + avatar: `https://randomuser.me/api/portraits/men/5.jpg`, + }, + kalebwilson: { + id: 'kalebwilson', + name: 'Kaleb Wilson', + avatar: `https://randomuser.me/api/portraits/men/6.jpg`, + }, + sarahjones: { + id: 'sarahjones', + name: 'Sarah Jones', + avatar: `https://randomuser.me/api/portraits/women/1.jpg`, + } + }; + + /** Model for the suggested edits demo */ + const model = { + "history": { + "2": [ + { + "id": 1, + "uid": "sarahjones", + "timestamp": 1752576936000, + "feedback": "Nice improvement!" + } + ] + }, + "version": 1, + "contents": [ + { + "type": "p", + "children": [ + { + "type": "img", + "attrs": { + "style": "display: block; margin-left: auto; margin-right: auto;", + "title": "Tiny Logo", + "src": "https://www.tiny.cloud/docs/images/logos/android-chrome-256x256.png", + "alt": "TinyMCE Logo", + "width": "128", + "height": "128" + } + } + ] + }, + { + "type": "h2", + "attrs": { + "style": "text-align: center;" + }, + "children": [ + { + "text": "Welcome to the TinyMCE Suggested Edits " + }, + { + "text": "interactive ", + "opData": { + "id": 1, + "type": "insert", + "uid": "adamhayes", + "timestamp": 1752015064000 + } + }, + { + "text": "demo!" + } + ] + }, + { + "type": "p", + "attrs": { + "style": "text-align: center;" + }, + "children": [ + { + "text": "Try out the Suggested Edits feature" + }, + { + "text": ": type in the editor, apply formatting or delete some content. T", + "opData": { + "id": 2, + "type": "insert", + "uid": "adamhayes", + "timestamp": 1752415064000 + } + }, + { + "text": " by typing in the editor and t", + "opData": { + "id": 2, + "type": "remove", + "uid": "adamhayes", + "timestamp": 1752415064000 + } + }, + { + "text": "hen" + }, + { + "text": ",", + "opData": { + "id": 3, + "type": "insert", + "uid": "adamhayes", + "timestamp": 1752515064000 + } + }, + { + "text": " click" + }, + { + "text": "ing", + "opData": { + "id": 4, + "type": "remove", + "uid": "adamhayes", + "timestamp": 1752515064000 + } + }, + { + "text": " the Review Changes button in the toolbar" + }, + { + "text": " to see your changes", + "opData": { + "id": 5, + "type": "insert", + "uid": "kalebwilson", + "timestamp": 1752615064000 + } + }, + { + "text": "." + } + ] + }, + { + "type": "p", + "attrs": { + "style": "text-align: center;" + }, + "children": [ + { + "text": "And visit the " + }, + { + "text": "pricing page", + "opData": { + "id": 6, + "type": "modify", + "uid": "kalebwilson", + "timestamp": 1752615064000 + }, + "format": [ + { + "type": "a", + "attrs": { + "href": "https://www.tiny.cloud/pricing" + } + } + ], + "oldFormat": [ + { + "type": "a", + "attrs": { + "href": "https://www.tiny.cloud/pricing" + } + }, + "em" + ] + }, + { + "text": " to learn more about our Premium plugins." + } + ] + }, + { + "type": "h2", + "children": [ + { + "text": "A simple table to play with" + } + ] + }, + { + "type": "table", + "attrs": { + "style": "border-collapse: collapse; width: 100%;", + "border": "1" + }, + "children": [ + { + "type": "thead", + "children": [ + { + "type": "tr", + "attrs": { + "style": "text-align: left;" + }, + "children": [ + { + "type": "th", + "children": [ + { + "text": "Product" + } + ] + }, + { + "type": "th", + "children": [ + { + "text": "Cost" + } + ] + }, + { + "type": "th", + "children": [ + { + "text": "Really?" + } + ] + } + ] + } + ] + }, + { + "type": "tbody", + "children": [ + { + "type": "tr", + "children": [ + { + "type": "td", + "children": [ + { + "text": "TinyMCE Cloud" + } + ] + }, + { + "type": "td", + "children": [ + { + "text": "Get started for free" + } + ] + }, + { + "type": "td", + "children": [ + { + "text": "Yes!", + "format": [ + "strong" + ] + } + ] + } + ] + }, + { + "type": "tr", + "children": [ + { + "type": "td", + "children": [ + { + "text": "Plupload" + } + ] + }, + { + "type": "td", + "children": [ + { + "text": "Free" + } + ] + }, + { + "type": "td", + "children": [ + { + "text": "Yes!", + "format": [ + "strong" + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "h2", + "opData": { + "id": 7, + "type": "insert", + "uid": "martincook", + "timestamp": 1752576331000 + }, + "children": [ + { + "text": "Found a bug?" + } + ] + }, + { + "type": "p", + "children": [ + { + "text": " ", + "opData": { + "id": 7, + "type": "remove", + "uid": "martincook", + "timestamp": 1752576331000 + } + }, + { + "text": "If you believe you have found a bug please create an issue on the ", + "opData": { + "id": 7, + "type": "insert", + "uid": "martincook", + "timestamp": 1752576331000 + } + }, + { + "text": "GitHub repo", + "opData": { + "id": 7, + "type": "insert", + "uid": "martincook", + "timestamp": 1752576331000 + }, + "format": [ + { + "type": "a", + "attrs": { + "href": "https://github.com/tinymce/tinymce/issues" + } + } + ] + }, + { + "text": " to report it to the developers.", + "opData": { + "id": 7, + "type": "insert", + "uid": "martincook", + "timestamp": 1752576331000 + } + } + ] + }, + { + "type": "h2", + "children": [ + { + "text": "Finally…" + } + ] + }, + { + "type": "p", + "children": [ + { + "text": "Don’t forget to check out " + }, + { + "text": "Plupload", + "format": [ + { + "type": "a", + "attrs": { + "href": "http://www.plupload.com", + "target": "_blank", + "rel": "noopener" + } + } + ] + }, + { + "text": ", the upload solution featuring HTML5 upload support." + } + ] + }, + { + "type": "p", + "children": [ + { + "text": "Thanks for supporting TinyMCE. We hope it helps you and your users create great content." + } + ] + }, + { + "type": "p", + "children": [ + { + "text": "All the best from the TinyMCE team." + } + ] + } + ] + }; + // End of fake server code for suggested edits + tinymce.init({ selector: 'textarea#full-featured', - plugins: 'ai preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker editimage help formatpainter permanentpen pageembed charmap tinycomments mentions quickbars linkchecker emoticons advtable footnotes mergetags autocorrect typography advtemplate markdown revisionhistory importword exportword exportpdf', + plugins: 'ai suggestededits preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker editimage help formatpainter permanentpen pageembed charmap tinycomments mentions quickbars linkchecker emoticons advtable footnotes mergetags autocorrect typography advtemplate markdown revisionhistory importword exportword exportpdf', editimage_cors_hosts: ['picsum.photos'], tinydrive_token_provider: (success, failure) => { success({ token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJqb2huZG9lIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.Ks_BdfH4CWilyzLNk8S2gDARFhuxIauLa8PwhdEQhEo' }); @@ -424,7 +847,7 @@ tinymce.ScriptLoader.loadScripts(['https://cdn.jsdelivr.net/npm/faker@5/dist/fak tinydrive_google_drive_key: 'AIzaSyAsVRuCBc-BLQ1xNKtnLHB3AeoK-xmOrTc', tinydrive_google_drive_client_id: '748627179519-p9vv3va1mppc66fikai92b3ru73mpukf.apps.googleusercontent.com', mobile: { - plugins: 'ai preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker help formatpainter pageembed charmap mentions quickbars linkchecker emoticons advtable footnotes mergetags autocorrect typography advtemplate', + plugins: 'ai suggestededits preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker help formatpainter pageembed charmap mentions quickbars linkchecker emoticons advtable footnotes mergetags autocorrect typography advtemplate', }, menu: { tc: { @@ -433,7 +856,7 @@ tinymce.ScriptLoader.loadScripts(['https://cdn.jsdelivr.net/npm/faker@5/dist/fak } }, menubar: 'file edit view insert format tools table tc help', - toolbar: "undo redo | importword exportword exportpdf | revisionhistory | aidialog aishortcuts | blocks fontsizeinput | bold italic | align numlist bullist | link image | table math media pageembed | lineheight outdent indent | strikethrough forecolor backcolor formatpainter removeformat | charmap emoticons checklist | code fullscreen preview | save print | pagebreak anchor codesample footnotes mergetags | addtemplate inserttemplate | addcomment showcomments | ltr rtl casechange | spellcheckdialog a11ycheck", // Note: if a toolbar item requires a plugin, the item will not present in the toolbar if the plugin is not also loaded. + toolbar: "undo redo | importword exportword exportpdf | suggestededits | revisionhistory | aidialog aishortcuts | blocks fontsizeinput | bold italic | align numlist bullist | link image | table math media pageembed | lineheight outdent indent | strikethrough forecolor backcolor formatpainter removeformat | charmap emoticons checklist | code fullscreen preview | save print | pagebreak anchor codesample footnotes mergetags | addtemplate inserttemplate | addcomment showcomments | ltr rtl casechange | spellcheckdialog a11ycheck", // Note: if a toolbar item requires a plugin, the item will not present in the toolbar if the plugin is not also loaded. autosave_ask_before_unload: true, autosave_interval: '30s', autosave_prefix: '{path}{query}-{id}-', @@ -583,10 +1006,20 @@ tinymce.ScriptLoader.loadScripts(['https://cdn.jsdelivr.net/npm/faker@5/dist/fak } }, revisionhistory_fetch: fetchRevisions, - revisionhistory_author: { - id: 'john.doe', - name: 'John Doe' - }, + // revisionhistory_author: { + // id: 'john.doe', + // name: 'John Doe' + // }, revisionhistory_display_author: true, + // Suggested Edits plugin configuration + user_id: 'kalebwilson', + fetch_users: (userIds) => Promise.all(userIds + .map((userId) => new Promise((resolve) => + resolve(suggestededitsUserDb[userId] || { id: userId })) + )), + suggestededits_model: model, + suggestededits_content: 'html', + suggestededits_access: 'full', }); -}); + +}); \ No newline at end of file diff --git a/modules/ROOT/pages/security.adoc b/modules/ROOT/pages/security.adoc index 0bfe90b472..8ef888a7fb 100644 --- a/modules/ROOT/pages/security.adoc +++ b/modules/ROOT/pages/security.adoc @@ -1,7 +1,7 @@ = Security guide :navtitle: Security guide -:description_short: Security information for {productname}. -:description: Information on reporting security issues, what {productname} does to protect users, and what you can do to protect your users. +:description_short: Security information for TinyMCE. +:description: Information on reporting security issues, what TinyMCE does to protect users, and what you can do to protect your users. :keywords: security, xss, scripting, vulnerability, hack, hacker, csp, mitigation, protection, protect, hsts, https NOTE: The following is _general_ security advice that may be relevant to a website or application using {productname}. From f394233f710538333eeddbef2dcea332a386b821 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Wed, 23 Jul 2025 09:14:58 +1000 Subject: [PATCH 54/60] DOC-3147: Remove model, and linkchecker from full feature demo as its not currently ignored. --- .../live-demos/full-featured/example.js | 4 +- .../live-demos/full-featured/index.js | 404 +----------------- 2 files changed, 4 insertions(+), 404 deletions(-) diff --git a/modules/ROOT/examples/live-demos/full-featured/example.js b/modules/ROOT/examples/live-demos/full-featured/example.js index a5cb112594..2c2f774016 100644 --- a/modules/ROOT/examples/live-demos/full-featured/example.js +++ b/modules/ROOT/examples/live-demos/full-featured/example.js @@ -13,13 +13,13 @@ const model = tinymceElement.getAttribute('suggestededits-model'); tinymce.init({ selector: 'textarea#full-featured', - plugins: 'importword exportword exportpdf ai suggestededits preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker editimage help formatpainter permanentpen pageembed charmap tinycomments mentions quickbars linkchecker emoticons advtable footnotes mergetags autocorrect typography advtemplate markdown revisionhistory', + plugins: 'importword exportword exportpdf ai suggestededits preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker editimage help formatpainter permanentpen pageembed charmap tinycomments mentions quickbars emoticons advtable footnotes mergetags autocorrect typography advtemplate markdown revisionhistory', tinydrive_token_provider: 'URL_TO_YOUR_TOKEN_PROVIDER', tinydrive_dropbox_app_key: 'YOUR_DROPBOX_APP_KEY', tinydrive_google_drive_key: 'YOUR_GOOGLE_DRIVE_KEY', tinydrive_google_drive_client_id: 'YOUR_GOOGLE_DRIVE_CLIENT_ID', mobile: { - plugins: 'ai suggestededits preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker help formatpainter pageembed charmap mentions quickbars linkchecker emoticons advtable footnotes mergetags autocorrect typography advtemplate', + plugins: 'ai suggestededits preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker help formatpainter pageembed charmap mentions quickbars emoticons advtable footnotes mergetags autocorrect typography advtemplate', }, menu: { tc: { diff --git a/modules/ROOT/examples/live-demos/full-featured/index.js b/modules/ROOT/examples/live-demos/full-featured/index.js index 21fa722a1a..c3a977f732 100644 --- a/modules/ROOT/examples/live-demos/full-featured/index.js +++ b/modules/ROOT/examples/live-demos/full-featured/index.js @@ -436,408 +436,9 @@ tinymce.ScriptLoader.loadScripts(['https://cdn.jsdelivr.net/npm/faker@5/dist/fak } }; - /** Model for the suggested edits demo */ - const model = { - "history": { - "2": [ - { - "id": 1, - "uid": "sarahjones", - "timestamp": 1752576936000, - "feedback": "Nice improvement!" - } - ] - }, - "version": 1, - "contents": [ - { - "type": "p", - "children": [ - { - "type": "img", - "attrs": { - "style": "display: block; margin-left: auto; margin-right: auto;", - "title": "Tiny Logo", - "src": "https://www.tiny.cloud/docs/images/logos/android-chrome-256x256.png", - "alt": "TinyMCE Logo", - "width": "128", - "height": "128" - } - } - ] - }, - { - "type": "h2", - "attrs": { - "style": "text-align: center;" - }, - "children": [ - { - "text": "Welcome to the TinyMCE Suggested Edits " - }, - { - "text": "interactive ", - "opData": { - "id": 1, - "type": "insert", - "uid": "adamhayes", - "timestamp": 1752015064000 - } - }, - { - "text": "demo!" - } - ] - }, - { - "type": "p", - "attrs": { - "style": "text-align: center;" - }, - "children": [ - { - "text": "Try out the Suggested Edits feature" - }, - { - "text": ": type in the editor, apply formatting or delete some content. T", - "opData": { - "id": 2, - "type": "insert", - "uid": "adamhayes", - "timestamp": 1752415064000 - } - }, - { - "text": " by typing in the editor and t", - "opData": { - "id": 2, - "type": "remove", - "uid": "adamhayes", - "timestamp": 1752415064000 - } - }, - { - "text": "hen" - }, - { - "text": ",", - "opData": { - "id": 3, - "type": "insert", - "uid": "adamhayes", - "timestamp": 1752515064000 - } - }, - { - "text": " click" - }, - { - "text": "ing", - "opData": { - "id": 4, - "type": "remove", - "uid": "adamhayes", - "timestamp": 1752515064000 - } - }, - { - "text": " the Review Changes button in the toolbar" - }, - { - "text": " to see your changes", - "opData": { - "id": 5, - "type": "insert", - "uid": "kalebwilson", - "timestamp": 1752615064000 - } - }, - { - "text": "." - } - ] - }, - { - "type": "p", - "attrs": { - "style": "text-align: center;" - }, - "children": [ - { - "text": "And visit the " - }, - { - "text": "pricing page", - "opData": { - "id": 6, - "type": "modify", - "uid": "kalebwilson", - "timestamp": 1752615064000 - }, - "format": [ - { - "type": "a", - "attrs": { - "href": "https://www.tiny.cloud/pricing" - } - } - ], - "oldFormat": [ - { - "type": "a", - "attrs": { - "href": "https://www.tiny.cloud/pricing" - } - }, - "em" - ] - }, - { - "text": " to learn more about our Premium plugins." - } - ] - }, - { - "type": "h2", - "children": [ - { - "text": "A simple table to play with" - } - ] - }, - { - "type": "table", - "attrs": { - "style": "border-collapse: collapse; width: 100%;", - "border": "1" - }, - "children": [ - { - "type": "thead", - "children": [ - { - "type": "tr", - "attrs": { - "style": "text-align: left;" - }, - "children": [ - { - "type": "th", - "children": [ - { - "text": "Product" - } - ] - }, - { - "type": "th", - "children": [ - { - "text": "Cost" - } - ] - }, - { - "type": "th", - "children": [ - { - "text": "Really?" - } - ] - } - ] - } - ] - }, - { - "type": "tbody", - "children": [ - { - "type": "tr", - "children": [ - { - "type": "td", - "children": [ - { - "text": "TinyMCE Cloud" - } - ] - }, - { - "type": "td", - "children": [ - { - "text": "Get started for free" - } - ] - }, - { - "type": "td", - "children": [ - { - "text": "Yes!", - "format": [ - "strong" - ] - } - ] - } - ] - }, - { - "type": "tr", - "children": [ - { - "type": "td", - "children": [ - { - "text": "Plupload" - } - ] - }, - { - "type": "td", - "children": [ - { - "text": "Free" - } - ] - }, - { - "type": "td", - "children": [ - { - "text": "Yes!", - "format": [ - "strong" - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "type": "h2", - "opData": { - "id": 7, - "type": "insert", - "uid": "martincook", - "timestamp": 1752576331000 - }, - "children": [ - { - "text": "Found a bug?" - } - ] - }, - { - "type": "p", - "children": [ - { - "text": " ", - "opData": { - "id": 7, - "type": "remove", - "uid": "martincook", - "timestamp": 1752576331000 - } - }, - { - "text": "If you believe you have found a bug please create an issue on the ", - "opData": { - "id": 7, - "type": "insert", - "uid": "martincook", - "timestamp": 1752576331000 - } - }, - { - "text": "GitHub repo", - "opData": { - "id": 7, - "type": "insert", - "uid": "martincook", - "timestamp": 1752576331000 - }, - "format": [ - { - "type": "a", - "attrs": { - "href": "https://github.com/tinymce/tinymce/issues" - } - } - ] - }, - { - "text": " to report it to the developers.", - "opData": { - "id": 7, - "type": "insert", - "uid": "martincook", - "timestamp": 1752576331000 - } - } - ] - }, - { - "type": "h2", - "children": [ - { - "text": "Finally…" - } - ] - }, - { - "type": "p", - "children": [ - { - "text": "Don’t forget to check out " - }, - { - "text": "Plupload", - "format": [ - { - "type": "a", - "attrs": { - "href": "http://www.plupload.com", - "target": "_blank", - "rel": "noopener" - } - } - ] - }, - { - "text": ", the upload solution featuring HTML5 upload support." - } - ] - }, - { - "type": "p", - "children": [ - { - "text": "Thanks for supporting TinyMCE. We hope it helps you and your users create great content." - } - ] - }, - { - "type": "p", - "children": [ - { - "text": "All the best from the TinyMCE team." - } - ] - } - ] - }; - // End of fake server code for suggested edits - tinymce.init({ selector: 'textarea#full-featured', - plugins: 'ai suggestededits preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker editimage help formatpainter permanentpen pageembed charmap tinycomments mentions quickbars linkchecker emoticons advtable footnotes mergetags autocorrect typography advtemplate markdown revisionhistory importword exportword exportpdf', + plugins: 'ai suggestededits preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker editimage help formatpainter permanentpen pageembed charmap tinycomments mentions quickbars emoticons advtable footnotes mergetags autocorrect typography advtemplate markdown revisionhistory importword exportword exportpdf', editimage_cors_hosts: ['picsum.photos'], tinydrive_token_provider: (success, failure) => { success({ token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJqb2huZG9lIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.Ks_BdfH4CWilyzLNk8S2gDARFhuxIauLa8PwhdEQhEo' }); @@ -847,7 +448,7 @@ tinymce.ScriptLoader.loadScripts(['https://cdn.jsdelivr.net/npm/faker@5/dist/fak tinydrive_google_drive_key: 'AIzaSyAsVRuCBc-BLQ1xNKtnLHB3AeoK-xmOrTc', tinydrive_google_drive_client_id: '748627179519-p9vv3va1mppc66fikai92b3ru73mpukf.apps.googleusercontent.com', mobile: { - plugins: 'ai suggestededits preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker help formatpainter pageembed charmap mentions quickbars linkchecker emoticons advtable footnotes mergetags autocorrect typography advtemplate', + plugins: 'ai suggestededits preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link math media mediaembed codesample table charmap pagebreak nonbreaking anchor tableofcontents insertdatetime advlist lists checklist wordcount tinymcespellchecker a11ychecker help formatpainter pageembed charmap mentions quickbars emoticons advtable footnotes mergetags autocorrect typography advtemplate', }, menu: { tc: { @@ -1017,7 +618,6 @@ tinymce.ScriptLoader.loadScripts(['https://cdn.jsdelivr.net/npm/faker@5/dist/fak .map((userId) => new Promise((resolve) => resolve(suggestededitsUserDb[userId] || { id: userId })) )), - suggestededits_model: model, suggestededits_content: 'html', suggestededits_access: 'full', }); From ff4ddf8d29ed957ea341a53be8b47b7fb2a91c62 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Wed, 23 Jul 2025 09:56:54 +1000 Subject: [PATCH 55/60] Update modules/ROOT/partials/configuration/crossorigin.adoc --- modules/ROOT/partials/configuration/crossorigin.adoc | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/ROOT/partials/configuration/crossorigin.adoc b/modules/ROOT/partials/configuration/crossorigin.adoc index b0236fb1d2..04ea054032 100644 --- a/modules/ROOT/partials/configuration/crossorigin.adoc +++ b/modules/ROOT/partials/configuration/crossorigin.adoc @@ -5,7 +5,6 @@ The `+crossorigin+` option controls how {productname} handles cross-origin resou *Type:* `+(url: string, resourceType: 'script' | 'stylesheet') => string+` -*Default value:* * For {cloudname}: A function that returns `+'anonymous'+` for cloud resources and omits the attribute for other resources. * For self-hosted: A function that **omits** the crossorigin attribute for all resources. From 6ff34309df25dbb13a7969fb996da41e9173de8e Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Wed, 23 Jul 2025 09:57:58 +1000 Subject: [PATCH 56/60] Update modules/ROOT/examples/live-demos/a11ychecker/index.js Co-authored-by: tiny-ben-tran --- modules/ROOT/examples/live-demos/a11ychecker/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/ROOT/examples/live-demos/a11ychecker/index.js b/modules/ROOT/examples/live-demos/a11ychecker/index.js index dd694f2b25..6b07a57d11 100644 --- a/modules/ROOT/examples/live-demos/a11ychecker/index.js +++ b/modules/ROOT/examples/live-demos/a11ychecker/index.js @@ -7,6 +7,5 @@ tinymce.init({ a11ychecker_html_version: 'html5', a11ychecker_level: 'aaa', a11ychecker_allow_decorative_images: true, - a11ychecker_alt_text_max_length: 150, content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }' }); From 403f91c89d4ae0c138fe78cd1be2e1dc6ac05b90 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Wed, 23 Jul 2025 09:58:13 +1000 Subject: [PATCH 57/60] Update modules/ROOT/examples/live-demos/full-featured/index.js --- modules/ROOT/examples/live-demos/full-featured/index.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/ROOT/examples/live-demos/full-featured/index.js b/modules/ROOT/examples/live-demos/full-featured/index.js index c3a977f732..c9721b1615 100644 --- a/modules/ROOT/examples/live-demos/full-featured/index.js +++ b/modules/ROOT/examples/live-demos/full-featured/index.js @@ -607,10 +607,6 @@ tinymce.ScriptLoader.loadScripts(['https://cdn.jsdelivr.net/npm/faker@5/dist/fak } }, revisionhistory_fetch: fetchRevisions, - // revisionhistory_author: { - // id: 'john.doe', - // name: 'John Doe' - // }, revisionhistory_display_author: true, // Suggested Edits plugin configuration user_id: 'kalebwilson', From f0e0bb1fe72a46a462c549e54eb4bfa3f5172434 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Wed, 23 Jul 2025 10:01:36 +1000 Subject: [PATCH 58/60] Update modules/ROOT/partials/configuration/list_max_depth.adoc --- modules/ROOT/partials/configuration/list_max_depth.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ROOT/partials/configuration/list_max_depth.adoc b/modules/ROOT/partials/configuration/list_max_depth.adoc index 3bb2ea916c..d75ef8bd43 100644 --- a/modules/ROOT/partials/configuration/list_max_depth.adoc +++ b/modules/ROOT/partials/configuration/list_max_depth.adoc @@ -19,6 +19,6 @@ tinymce.init({ selector: 'textarea', plugins: 'lists', toolbar: 'bullist numlist', - list_max_depth: 2 // limits list nesting to maximum of 2 levels + list_max_depth: 2 // limits list nesting to maximum of 2 levels }); ---- From 1670fa3ebc14cc2e17a482226f3a507cbcd70f51 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Wed, 23 Jul 2025 10:01:42 +1000 Subject: [PATCH 59/60] Update modules/ROOT/partials/misc/ui-languages.adoc --- modules/ROOT/partials/misc/ui-languages.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ROOT/partials/misc/ui-languages.adoc b/modules/ROOT/partials/misc/ui-languages.adoc index 461fe1b3b3..20fff45c2c 100644 --- a/modules/ROOT/partials/misc/ui-languages.adoc +++ b/modules/ROOT/partials/misc/ui-languages.adoc @@ -3,7 +3,7 @@ [IMPORTANT] ==== -From {productname} 8.0, language codes use RFC5646 format with hyphens (-) instead of underscores (_). For backward compatibility, both formats are supported in {productname} 8, but underscore format will show console warning. +From {productname} {productmajorversion}, language codes use RFC5646 format with hyphens (-) instead of underscores (_). For backward compatibility, both formats are supported in {productname} {productmajorversion}, but underscore format will show console warning. Example: "{productname} language code "en_US" is deprecated, please use "en-US" instead.". ==== From 4128bb84cd84f7bcbbdc73f051455750f7e4fe86 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Wed, 23 Jul 2025 12:33:53 +1000 Subject: [PATCH 60/60] DOC-3147: api-version bump to 8.0.0 and update CDN version. --- .api-version | 2 +- antora.yml | 8 +-- modules/ROOT/moxiedoc_nav.adoc | 1 + .../ROOT/pages/apis/tinymce.dom.domutils.adoc | 2 +- .../pages/apis/tinymce.dom.selection.adoc | 6 +- modules/ROOT/pages/apis/tinymce.editor.adoc | 16 ++--- modules/ROOT/pages/apis/tinymce.root.adoc | 3 +- .../ROOT/pages/apis/tinymce.userlookup.adoc | 69 +++++++++++++++++++ 8 files changed, 88 insertions(+), 19 deletions(-) create mode 100644 modules/ROOT/pages/apis/tinymce.userlookup.adoc diff --git a/.api-version b/.api-version index 84c5308f03..fa5fce04b3 100644 --- a/.api-version +++ b/.api-version @@ -1 +1 @@ -7.9.0 \ No newline at end of file +8.0.0 \ No newline at end of file diff --git a/antora.yml b/antora.yml index b869358057..5f6853f541 100644 --- a/antora.yml +++ b/antora.yml @@ -8,10 +8,10 @@ asciidoc: idseparator: '-@' # generic variables companyurl: https://www.tiny.cloud - cdnurl: https://cdn.tiny.cloud/1/no-api-key/tinymce/8-testing/tinymce.min.js - tdcdnurl: https://cdn.tiny.cloud/1/_your_api_key_/tinydrive/8-testing/tinydrive.min.js - tinymce_live_demo_url: https://cdn.tiny.cloud/1/qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc/tinymce/8-testing/tinymce.min.js - tinydrive_live_demo_url: https://cdn.tiny.cloud/1/qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc/tinydrive/8-testing/tinydrive.min.js + cdnurl: https://cdn.tiny.cloud/1/no-api-key/tinymce/8/tinymce.min.js + tdcdnurl: https://cdn.tiny.cloud/1/_your_api_key_/tinydrive/8/tinydrive.min.js + tinymce_live_demo_url: https://cdn.tiny.cloud/1/qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc/tinymce/8/tinymce.min.js + tinydrive_live_demo_url: https://cdn.tiny.cloud/1/qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc/tinydrive/8/tinydrive.min.js webcomponent_url: https://cdn.jsdelivr.net/npm/@tinymce/tinymce-webcomponent/dist/tinymce-webcomponent.min.js jquery_url: https://cdn.jsdelivr.net/npm/@tinymce/tinymce-jquery@2/dist/tinymce-jquery.min.js openai_proxy_url: https://openai.ai-demo-proxy.tiny.cloud/v1/chat/completions diff --git a/modules/ROOT/moxiedoc_nav.adoc b/modules/ROOT/moxiedoc_nav.adoc index d5a3ba9f57..286e62940d 100644 --- a/modules/ROOT/moxiedoc_nav.adoc +++ b/modules/ROOT/moxiedoc_nav.adoc @@ -17,6 +17,7 @@ *** xref:apis/tinymce.shortcuts.adoc[tinymce.Shortcuts] *** xref:apis/tinymce.theme.adoc[tinymce.Theme] *** xref:apis/tinymce.undomanager.adoc[tinymce.UndoManager] +*** xref:apis/tinymce.userlookup.adoc[tinymce.UserLookup] *** xref:apis/tinymce.windowmanager.adoc[tinymce.WindowManager] ** tinymce.dom *** xref:apis/tinymce.dom.bookmarkmanager.adoc[tinymce.dom.BookmarkManager] diff --git a/modules/ROOT/pages/apis/tinymce.dom.domutils.adoc b/modules/ROOT/pages/apis/tinymce.dom.domutils.adoc index f524798708..4dff25f656 100644 --- a/modules/ROOT/pages/apis/tinymce.dom.domutils.adoc +++ b/modules/ROOT/pages/apis/tinymce.dom.domutils.adoc @@ -269,7 +269,7 @@ Creates HTML string for element. The element will be closed unless an empty inne [source, javascript] ---- // Creates a html chunk and inserts it at the current selection/caret location -tinymce.activeEditor.selection.setContent(tinymce.activeEditor.dom.createHTML('a', { href: 'test.html' }, 'some line')); +tinymce.activeEditor.insertContent(tinymce.activeEditor.dom.createHTML('a', { href: 'test.html' }, 'some line')); ---- ==== Parameters diff --git a/modules/ROOT/pages/apis/tinymce.dom.selection.adoc b/modules/ROOT/pages/apis/tinymce.dom.selection.adoc index 575cb1dfdb..2a2c7cd0a3 100644 --- a/modules/ROOT/pages/apis/tinymce.dom.selection.adoc +++ b/modules/ROOT/pages/apis/tinymce.dom.selection.adoc @@ -48,7 +48,9 @@ node the parent element will be returned.|`xref:apis/tinymce.dom.selection.adoc[ |xref:#select[select()]|Selects the specified element. This will place the start and end of the selection range around the element.|`xref:apis/tinymce.dom.selection.adoc[Selection]` |xref:#selectorChanged[selectorChanged()]|Executes callback when the current selection starts/stops matching the specified selector. The current state will be passed to the callback as it's first argument.|`xref:apis/tinymce.dom.selection.adoc[Selection]` -|xref:#setContent[setContent()]|Sets the current selection to the specified content. If any contents is selected it will be replaced +|xref:#setContent[setContent()]|This method has been deprecated. Use "editor.insertContent" instead. + +Sets the current selection to the specified content. If any contents is selected it will be replaced with the contents passed in to this function. If there is no selection the contents will be inserted where the caret is placed in the editor/page.|`xref:apis/tinymce.dom.selection.adoc[Selection]` |xref:#setCursorLocation[setCursorLocation()]|Move the selection cursor range to the specified node and offset. @@ -356,6 +358,8 @@ state will be passed to the callback as it's first argument. ---- setContent(content: String, args: Object) ---- +This method has been deprecated. Use "editor.insertContent" instead. + Sets the current selection to the specified content. If any contents is selected it will be replaced with the contents passed in to this function. If there is no selection the contents will be inserted where the caret is placed in the editor/page. diff --git a/modules/ROOT/pages/apis/tinymce.editor.adoc b/modules/ROOT/pages/apis/tinymce.editor.adoc index 0aa6ddec6f..3d8f8a5cc2 100644 --- a/modules/ROOT/pages/apis/tinymce.editor.adoc +++ b/modules/ROOT/pages/apis/tinymce.editor.adoc @@ -1,7 +1,7 @@ = tinymce.Editor :navtitle: tinymce.Editor :description: This class contains the core logic for a TinyMCE editor. -:keywords: Editor, addCommand, addCommandCallback, addQueryStateHandler, addQueryStateHandlerCallback, addQueryValueHandler, addQueryValueHandlerCallback, addShortcut, addVisual, baseURI, contentCSS, contentStyles, convertURL, destroy, dispatch, documentBaseURI, dom, editorUpload, execCommand, fire, focus, formatter, getBody, getContainer, getContent, getContentAreaContainer, getDoc, getElement, getParam, getWin, hasEditableRoot, hasEventListeners, hasFocus, hasPlugin, hide, id, initialized, insertContent, isDirty, isHidden, load, mode, nodeChanged, notificationManager, off, on, once, options, parser, plugins, queryCommandState, queryCommandSupported, queryCommandValue, remove, render, resetContent, save, schema, selection, serializer, setContent, setDirty, setEditableRoot, setProgressState, show, theme, translate, ui, undoManager, uploadImages, windowManager +:keywords: Editor, addCommand, addCommandCallback, addQueryStateHandler, addQueryStateHandlerCallback, addQueryValueHandler, addQueryValueHandlerCallback, addShortcut, addVisual, baseURI, contentCSS, contentStyles, convertURL, destroy, dispatch, documentBaseURI, dom, editorUid, editorUpload, execCommand, fire, focus, formatter, getBody, getContainer, getContent, getContentAreaContainer, getDoc, getElement, getParam, getWin, hasEditableRoot, hasEventListeners, hasFocus, hasPlugin, hide, id, initialized, insertContent, isDirty, isHidden, load, mode, nodeChanged, notificationManager, off, on, once, options, parser, plugins, queryCommandState, queryCommandSupported, queryCommandValue, remove, render, resetContent, save, schema, selection, serializer, setContent, setDirty, setEditableRoot, setProgressState, show, theme, translate, ui, undoManager, uploadImages, userLookup, windowManager :moxie-type: api This class contains the core logic for a TinyMCE editor. @@ -37,6 +37,7 @@ ed.render(); |contentStyles|`Array`|Array of CSS styles to add to head of document when the editor loads.|`xref:apis/tinymce.editor.adoc[Editor]` |documentBaseURI|`xref:apis/tinymce.util.uri.adoc[URI]`|URI object to document configured for the TinyMCE instance.|`xref:apis/tinymce.editor.adoc[Editor]` |dom|`xref:apis/tinymce.dom.domutils.adoc[DOMUtils]`|DOM instance for the editor.|`xref:apis/tinymce.editor.adoc[Editor]` +|editorUid|`String`|A uuid string to uniquely identify an editor across any page.|`xref:apis/tinymce.editor.adoc[Editor]` |editorUpload|`xref:apis/tinymce.editorupload.adoc[EditorUpload]`|Editor upload API|`xref:apis/tinymce.editor.adoc[Editor]` |formatter|`xref:apis/tinymce.formatter.adoc[Formatter]`|Formatter instance.|`xref:apis/tinymce.editor.adoc[Editor]` |id|`String`|Editor instance id, normally the same as the div/textarea that was replaced.|`xref:apis/tinymce.editor.adoc[Editor]` @@ -52,6 +53,7 @@ ed.render(); |theme|`xref:apis/tinymce.theme.adoc[Theme]`|Reference to the theme instance that was used to generate the UI.|`xref:apis/tinymce.editor.adoc[Editor]` |ui|`xref:apis/tinymce.editor.ui.ui.adoc[Ui]`|Editor ui components|`xref:apis/tinymce.editor.adoc[Editor]` |undoManager|`xref:apis/tinymce.undomanager.adoc[UndoManager]`|Undo manager instance, responsible for handling undo levels.|`xref:apis/tinymce.editor.adoc[Editor]` +|userLookup|`xref:apis/tinymce.userlookup.adoc[UserLookup]`|Editor user lookup API|`xref:apis/tinymce.editor.adoc[Editor]` |windowManager|`xref:apis/tinymce.windowmanager.adoc[WindowManager]`|Window manager reference, use this to open new windows and dialogs.|`xref:apis/tinymce.editor.adoc[Editor]` |=== @@ -723,7 +725,7 @@ Returns true/false if the editor is hidden or not. === load() [source, javascript] ---- -load(args: Object): String +load(args: Object) ---- Loads contents from the textarea, input or other element that got converted into an editor instance. This method will move the contents from that textarea, input or other element into the editor by using setContent @@ -733,10 +735,6 @@ so all events etc that method has will get dispatched as well. * `args (Object)` - Optional content object, this gets passed around through the whole load process. -==== Return value - -* `String` - HTML string that got set into the editor. - ''' [[nodeChanged]] @@ -949,7 +947,7 @@ so all events etc that method has will get dispatched as well. === setContent() [source, javascript] ---- -setContent(content: String, args: Object): String +setContent(content: String, args: Object) ---- Sets the specified content to the editor instance, this will cleanup the content before it gets set using the different cleanup rules options. @@ -975,10 +973,6 @@ tinymce.activeEditor.setContent('

Some html

', { format: 'html' }); * `content (String)` - Content to set to editor, normally HTML contents but can be other formats as well. * `args (Object)` - Optional content object, this gets passed around through the whole set process. -==== Return value - -* `String` - HTML string that got set into the editor. - ''' [[setDirty]] diff --git a/modules/ROOT/pages/apis/tinymce.root.adoc b/modules/ROOT/pages/apis/tinymce.root.adoc index 65c46cc4c4..60db0f8dd3 100644 --- a/modules/ROOT/pages/apis/tinymce.root.adoc +++ b/modules/ROOT/pages/apis/tinymce.root.adoc @@ -1,7 +1,7 @@ = tinymce :navtitle: tinymce :description: TinyMCE core class. -:keywords: DOM, PluginManager, ScriptLoader, ThemeManager, activeEditor, add, addI18n, baseURI, baseURL, createEditor, defaultOptions, documentBaseURL, each, execCommand, explode, get, grep, hasOwnProperty, i18n, inArray, init, is, isArray, majorVersion, makeMap, map, minorVersion, overrideDefaults, releaseDate, remove, resolve, setActive, suffix, toArray, translate, triggerSave, trim, walk +:keywords: DOM, PluginManager, ScriptLoader, ThemeManager, activeEditor, add, addI18n, baseURI, baseURL, createEditor, defaultOptions, documentBaseURL, each, execCommand, explode, get, grep, hasOwnProperty, i18n, inArray, init, is, isArray, majorVersion, makeMap, map, minorVersion, overrideDefaults, pageUid, releaseDate, remove, resolve, setActive, suffix, toArray, translate, triggerSave, trim, walk :moxie-type: api TinyMCE core class. @@ -26,6 +26,7 @@ TinyMCE core class. |i18n|`Object`|Collection of language pack data.|`xref:apis/tinymce.root.adoc[tinymce]` |majorVersion|`String`|Major version of TinyMCE build.|`xref:apis/tinymce.root.adoc[tinymce]` |minorVersion|`String`|Minor version of TinyMCE build.|`xref:apis/tinymce.root.adoc[tinymce]` +|pageUid|`String`|A uuid string to anonymously identify the page tinymce is loaded in|`xref:apis/tinymce.root.adoc[tinymce]` |releaseDate|`String`|Release date of TinyMCE build.|`xref:apis/tinymce.root.adoc[tinymce]` |suffix|`String`|Current suffix to add to each plugin/theme that gets loaded for example ".min".|`xref:apis/tinymce.root.adoc[tinymce]` |=== diff --git a/modules/ROOT/pages/apis/tinymce.userlookup.adoc b/modules/ROOT/pages/apis/tinymce.userlookup.adoc new file mode 100644 index 0000000000..02890d9ddb --- /dev/null +++ b/modules/ROOT/pages/apis/tinymce.userlookup.adoc @@ -0,0 +1,69 @@ += tinymce.UserLookup +:navtitle: tinymce.UserLookup +:description: TinyMCE User Lookup API Handles user information retrieval and caching. +:keywords: fetchUsers, userId +:moxie-type: api + +TinyMCE User Lookup API Handles user information retrieval and caching. + +[[examples]] +== Examples +[source, javascript] +---- +// Get the current user's ID from the editor options, or defaults to 'Anonymous'. +tinymce.activeEditor.userLookup.userId; + +// Fetch user information by IDs which returns a record of promises +const userPromises = tinymce.activeEditor.userLookup.fetchUsers(['user-1', 'user-2']); + +// Access individual promises by user ID +userPromises['user-1'].then(user => console.log('User 1:', user)); +userPromises['user-2'].then(user => console.log('User 2:', user)); + +// Or wait for all promises +Promise.all(Object.values(userPromises)).then((users) => { + users.forEach(user => console.log('User found:', user)); +}).catch((error) => { + console.error('Error fetching users:', error); +}); +---- + +[[summary]] +== Summary + +[[properties]] +=== Properties +[cols="2,1,4,1",options="header"] +|=== +|Name|Type|Summary|Defined by +|userId|`String`|The current user's ID retrieved from the editor options, or defaults to 'Anonymous'.|`xref:apis/tinymce.userlookup.adoc[UserLookup]` +|=== + +[[methods-summary]] +=== Methods +[cols="2,5,1",options="header"] +|=== +|Name|Summary|Defined by +|xref:#fetchUsers[fetchUsers()]|Fetches user information using a provided array of userIds.|`xref:apis/tinymce.userlookup.adoc[UserLookup]` +|=== + +[[methods]] +== Methods + +[[fetchUsers]] +=== fetchUsers() +[source, javascript] +---- +fetchUsers(userIds: string[]): Record> +---- +Fetches user information using a provided array of userIds. + +==== Parameters + +* `userIds (string[])` - - A list of user IDs to fetch information for. + +==== Return value + +* `Record>` - An object where each key is a user ID and its value is a Promise that resolves to the user's data or rejects if the user is not found. + +'''