diff --git a/-new-material-templates/configuration-options-templates/ROOT/pages/content..adoc b/-new-material-templates/configuration-options-templates/ROOT/pages/content.{appearance-behavior-filtering-or-formatting}.adoc similarity index 100% rename from -new-material-templates/configuration-options-templates/ROOT/pages/content..adoc rename to -new-material-templates/configuration-options-templates/ROOT/pages/content.{appearance-behavior-filtering-or-formatting}.adoc diff --git a/-new-material-templates/configuration-options-templates/ROOT/partials/configuration/.adoc b/-new-material-templates/configuration-options-templates/ROOT/partials/configuration/{configuration_option}.adoc similarity index 100% rename from -new-material-templates/configuration-options-templates/ROOT/partials/configuration/.adoc rename to -new-material-templates/configuration-options-templates/ROOT/partials/configuration/{configuration_option}.adoc diff --git a/-new-material-templates/integration-example-(ie)-templates/ROOT/examples/live-demos/ie-/index.html b/-new-material-templates/integration-example-(ie)-templates/ROOT/examples/live-demos/ie-{hyphen-delimited-descriptor}/index.html similarity index 100% rename from -new-material-templates/integration-example-(ie)-templates/ROOT/examples/live-demos/ie-/index.html rename to -new-material-templates/integration-example-(ie)-templates/ROOT/examples/live-demos/ie-{hyphen-delimited-descriptor}/index.html diff --git a/-new-material-templates/integration-example-(ie)-templates/ROOT/examples/live-demos/ie-/index.js b/-new-material-templates/integration-example-(ie)-templates/ROOT/examples/live-demos/ie-{hyphen-delimited-descriptor}/index.js similarity index 100% rename from -new-material-templates/integration-example-(ie)-templates/ROOT/examples/live-demos/ie-/index.js rename to -new-material-templates/integration-example-(ie)-templates/ROOT/examples/live-demos/ie-{hyphen-delimited-descriptor}/index.js diff --git a/-new-material-templates/integration-example-(ie)-templates/ROOT/pages/ie-.adoc b/-new-material-templates/integration-example-(ie)-templates/ROOT/pages/ie-{hyphen-delimited-descriptor}.adoc similarity index 100% rename from -new-material-templates/integration-example-(ie)-templates/ROOT/pages/ie-.adoc rename to -new-material-templates/integration-example-(ie)-templates/ROOT/pages/ie-{hyphen-delimited-descriptor}.adoc diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos/full-featured/index.html b/-new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos/full-featured/index.html index 4896337a72..18c2f7c5fb 100644 --- a/-new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos/full-featured/index.html +++ b/-new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos/full-featured/index.html @@ -1,6 +1,5 @@ \ No newline at end of file diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos/full-featured/index.js b/-new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos/full-featured/index.js index 962b99b07b..27f5ea1887 100644 --- a/-new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos/full-featured/index.js +++ b/-new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos/full-featured/index.js @@ -1,6 +1,6 @@ /* -Add new plugin to this file’s extant configuration +Update tinymce-docs/modules/ROOT/examples/live-demos/full-featured/index.js to include the new plugin. */ diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos//example.js b/-new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos/{plugincode}/example.js similarity index 91% rename from -new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos//example.js rename to -new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos/{plugincode}/example.js index 30d2613ffa..6b8e2b18e0 100644 --- a/-new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos//example.js +++ b/-new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos/{plugincode}/example.js @@ -23,7 +23,7 @@ NB: there is one UX consequence of setting up demos to work in these cases. The *Edit on CodePen* tab does not — and cannot — present in the documentation. -The initial setup of these ‘inclues-an-emulated-back-end’ examples +The initial setup of these ‘includes-an-emulated-back-end’ examples will almost certainly include significant initial input from the plugin’s developer. diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos//index.html b/-new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos/{plugincode}/index.html similarity index 100% rename from -new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos//index.html rename to -new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos/{plugincode}/index.html diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos//index.js b/-new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos/{plugincode}/index.js similarity index 100% rename from -new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos//index.js rename to -new-material-templates/plugin-documentation-templates/ROOT/examples/live-demos/{plugincode}/index.js diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/nav.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/nav.adoc index a91d9c153d..a36b79c6e7 100644 --- a/-new-material-templates/plugin-documentation-templates/ROOT/nav.adoc +++ b/-new-material-templates/plugin-documentation-templates/ROOT/nav.adoc @@ -1,13 +1,8 @@ * xref:plugins.adoc[Plugins] ** Premium plugins -// If the new plugin is a Premium plugin -// Replace the boilerplate below with the file-name of the new Premium plugin. -// Also, place this new Premium plugin into alphabetical place within the Premium plugin sub-section. -*** xref:.adoc[] -** Open source plugins -// If the new plugin is an open source plugin -// Replace the boilerplate below with the file-name of the new open source plugin. -// Also, place this new open source plugin into alphabetical place within the open source plugin sub-section. -*** xref:.adoc[] +// If Premium plugin, place the following entry into Premium plugins list in alphabetical order by plugin name. +*** xref:.adoc[] -// This file is instructional and is never included in the published name-space. +** Open source plugins +// If Open source plugin, place the following entry into Open source plugins list in alphabetical order by plugin name. +*** xref:.adoc[] diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/pages/available-menu-items.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/pages/available-menu-items.adoc index b25859f6a6..79b053e32e 100644 --- a/-new-material-templates/plugin-documentation-templates/ROOT/pages/available-menu-items.adoc +++ b/-new-material-templates/plugin-documentation-templates/ROOT/pages/available-menu-items.adoc @@ -1,13 +1,6 @@ -// 0. Set :plugincategory: to appropriate value -// 1. premium; or -// 2. opensource. -// Note neither value is capitalised. -// Note the second value has no space between the two words. -// 1. Replace instances with appropriate material. -// 2. Add the edited material to -// /tinymce-docs/modules/ROOT/pages/available-menu-items.adoc -// in alphabetical order by . (*not* ). -// 3. Do not bring these comments over with the edited material. +// Add the edited material to +// tinymce-docs/modules/ROOT/pages/available-menu-items.adoc +// in alphabetical order by . (*not* ). :plugincategory: :pluginname: diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/pages/available-toolbar-buttons.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/pages/available-toolbar-buttons.adoc index 564aeb501e..f4864cd218 100644 --- a/-new-material-templates/plugin-documentation-templates/ROOT/pages/available-toolbar-buttons.adoc +++ b/-new-material-templates/plugin-documentation-templates/ROOT/pages/available-toolbar-buttons.adoc @@ -1,13 +1,6 @@ -// 0. Set :plugincategory: to appropriate value -// 1. premium; or -// 2. opensource. -// Note neither value is capitalised. -// Note the second value has no space between the two words. -// 1. Replace instances with appropriate material. -// 2. Add the edited material to -// /tinymce-docs/modules/ROOT/pages/available-toolbar-buttons.adoc -// in alphabetical order by . (*not* ). -// 3. Do not bring these comments over with the edited material. +// Add the edited material to +// tinymce-docs/modules/ROOT/pages/available-toolbar-buttons.adoc +// in alphabetical order by . (*not* ). :plugincategory: :pluginname: diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/pages/editor-command-identifiers.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/pages/editor-command-identifiers.adoc index cbc92854c5..dd4ba23052 100644 --- a/-new-material-templates/plugin-documentation-templates/ROOT/pages/editor-command-identifiers.adoc +++ b/-new-material-templates/plugin-documentation-templates/ROOT/pages/editor-command-identifiers.adoc @@ -1,16 +1,14 @@ -// 0. Replace instances with appropriate material. -// 1. Add the edited material to -// /tinymce-docs/modules/ROOT/pages/editor-command-identifiers.adoc -// in alphabetical order by . (*not* ). -// 2. Do not bring these comments over with the edited material. +// Add the edited material to +// tinymce-docs/modules/ROOT/pages/editor-command-identifiers.adoc +// in alphabetical order by . (*not* ). -// add an xref in alphabetical order to the summary list that is below the following lines: +// add an xref in alphabetical order by to the summary list that is below the following lines: // [[plugin-commands]] // === Plugin Commands * xref:[] -// add the include in alphabetical order to the body of the "Plugin Commands" section +// add the include in alphabetical order by to the body of the "Plugin Commands" section [[]] ==== diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/pages/events.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/pages/events.adoc index b71e0f83d6..8898c1f2f8 100644 --- a/-new-material-templates/plugin-documentation-templates/ROOT/pages/events.adoc +++ b/-new-material-templates/plugin-documentation-templates/ROOT/pages/events.adoc @@ -1,15 +1,13 @@ -// 0. Replace instances with appropriate material. -// 1. Add the edited material to -// /tinymce-docs/modules/ROOT/pages/events.adoc -// in alphabetical order by . (*not* ). -// 2. Do not bring these comments over with the edited material. +// Add the edited material to +// tinymce-docs/modules/ROOT/pages/events.adoc +// in alphabetical order by . (*not* ). // add the xref in alphabetical order to the summary list that is below the following line: // == Plugin events * xref:-events[ events] -// add the include in alphabetical order to the body of the "Plugin events" section +// add the include in alphabetical order by to the body of the "Plugin events" section [[-events]] === events diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/pages/pluginpage.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/pages/pluginpage.adoc index 7ecc5c616f..398444a855 100644 --- a/-new-material-templates/plugin-documentation-templates/ROOT/pages/pluginpage.adoc +++ b/-new-material-templates/plugin-documentation-templates/ROOT/pages/pluginpage.adoc @@ -1,6 +1,3 @@ -// Replace instances with material then remove this, and other comments. - -// : the product name. Reference on this page with the {pluginname} variable. = plugin :navtitle: :description: . @@ -11,25 +8,22 @@ // opensource plugin = tieroneplan // premium plugin = tiertwoplan or tierthreeplan or enterpriseplan :pluginminimumplan: -// : adds the plugin to an editor configuration. -// Reference on this page with the {plugincode} variable :plugincode: -:plugincategory: premium|opensource +:plugincategory: // Remove the line below (and this comment) for open source plugins include::partial$misc/admon-premium-plugin.adoc[] -// Edit the line below to add the correct requires- file from `/partials/misc`. +// Edit the line below to add the correct requires- file from `tinymce-docs/modules/ROOT/partials/misc`. include::partial$misc/admon-requires-v.adoc // Add an introduction. What does the plugin do? Why would I use this plugin? Keep it concise. == Interactive example -// No Lorem Ipsum. Add test material, or, at least, a description of how end-users use the feature. liveDemo::{plugincode}[] -// Logic for customising what presents from this included file relies on +// Logic for customizing what presents from this included file relies on // the :pluginminimumplan: attribute value above. // // 2023-09-06 addendum: the logic in purchase-premium-plugins.adoc needs @@ -49,9 +43,9 @@ For example: ---- tinymce.init({ selector: 'textarea', // change this value according to your HTML - plugins: '{{plugincode}}', + plugins: '', toolbar: '', - an_essential_option: false + : false }); ---- @@ -65,9 +59,7 @@ The following configuration options affect the behavior of the {pluginname} plug // The template file for each such file is // -new-material-templates/partials/commands/.adoc // Add one include:: statement for each added file as per the example immediately below. -include::partial$configuration/.adoc[][leveloffset=+1] - - +include::partial$configuration/.adoc[leveloffset=+1] // If the plugin offers toolbar buttons // 1. Add an entry to /pages/available-toolbar-buttons.adoc @@ -131,6 +123,4 @@ include::partial$events/{plugincode}-events.adoc[] The {pluginname} plugin provides the following APIs. -include::partial$plugin-apis/{plugincode}-apis.adoc[] - -// Remove all comment lines and comment blocks before publishing. +include::partial$plugin-apis/{plugincode}-apis.adoc[] \ No newline at end of file diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/partials/commands/-cmds.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/partials/commands/-cmds.adoc deleted file mode 100644 index 33fcc82704..0000000000 --- a/-new-material-templates/plugin-documentation-templates/ROOT/partials/commands/-cmds.adoc +++ /dev/null @@ -1,62 +0,0 @@ -[cols="1,3",options="header"] -|=== -|Command |Description - -|mceCommandOne |Description one. -// Boilerplate for commands that require further documentation -|mceCommandTwo |Description two. For details, see xref:using-mcecommandtwo[Using `+mcecommandtwo+`]. -|mceCommandThree |Description three. -|mceCommandFour |Description four. -|mceCommandFive |Description five. -|mceCommandSix |Description six. -// Boilerplate for commands that require further documentation -|mceCommandSeven |Description seven. For details, see xref:using-mcecommandseven[Using `+mcecommandtwo+`]. -|mceCommandEn |Description en. -|=== - -.Examples -[source,js] ----- -tinymce.activeEditor.execCommand('mceCommandOne'); -tinymce.activeEditor.execCommand('mceCommandTwo', true|false, { : '', : '', : '', : '' }); -tinymce.activeEditor.execCommand('mceCommandThree'); -tinymce.activeEditor.execCommand('mceCommandFour'); -tinymce.activeEditor.execCommand('mceCommandFive'); -tinymce.activeEditor.execCommand('mceCommandSix'); -tinymce.activeEditor.execCommand('mceCommandSeven', true|false, { : '' }); ----- - -// Boilerplate for further documentation of commands that require it. -[[using-mcecommmandtwo]] -== Using `+mcecommandtwo+` - -`+mceCommandTwo+` accepts an object with the following key-value pairs: - -[cols="1,,1,2",options="header"] -|=== -|Name |Value |Requirement |Description - -| |`+'this'+` or `+'that'+` | [Rr]equired |Key-value description one. -| |`+number+` | [Rr]equired |Key-value description two. -| |`+'other'+`, `+'thing'+`, `+'doohickie'+`, or `+'widget'+` | [Rr]equired |Key-value description three. -| |`+'word'+` or `+'notword'+` | [Rr]equired |Key-value description four. -|=== - -// Further notes as required. Delete this comment once notes are added or if they are not required. - -// Boilerplate for further documentation of commands that require it. -[[using-mcetabletoggleseries]] -== Using `+mceTableToggleSeries+` - -`+mceCommandSeven+` accepts an object with the following key-value pair: - -[cols="1,1,1,2",options="header"] -|=== -|Name |Value |Requirement |Description - -| |`+string+` | [Rr]equired |Key-value description five. -|=== - -// Further notes as required. Delete this comment once notes are added or if they are not required. - -// Remove all comment lines and comment blocks before publishing. diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/partials/commands/{plugincode}-cmds.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/partials/commands/{plugincode}-cmds.adoc new file mode 100644 index 0000000000..9d61f6860b --- /dev/null +++ b/-new-material-templates/plugin-documentation-templates/ROOT/partials/commands/{plugincode}-cmds.adoc @@ -0,0 +1,33 @@ +[cols="1,3",options="header"] +|=== +|Command |Description + +| | +// Boilerplate for commands that require further documentation +| |Description two. For details, see xref:using-[Using `++`]. +|=== + +.Examples +[source,js] +---- +tinymce.activeEditor.execCommand(''); +tinymce.activeEditor.execCommand('', , { : '', : '' }); +---- + +// Boilerplate for further documentation of commands that require it. +[[using-]] +== Using `++` + +`++` accepts an object with the following key-value pairs: + +[cols="1,,1,2",options="header"] +|=== +|Name |Value |Requirement |Description + +| |`+''+` or `+''+` |equired | +| |`++` |equired | +|=== + +// Further notes as required. Delete this comment once notes are added or if they are not required. + +// Remove all comment lines and comment blocks before publishing. diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/partials/configuration/icon_list.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/partials/configuration/icon_list.adoc index 692ae906f5..531b26502b 100644 --- a/-new-material-templates/plugin-documentation-templates/ROOT/partials/configuration/icon_list.adoc +++ b/-new-material-templates/plugin-documentation-templates/ROOT/partials/configuration/icon_list.adoc @@ -1,7 +1,6 @@ -// 0. Replace instances with appropriate material. -// 1. Add the edited material to -// /tinymce-docs/modules/ROOT/partials/configuration/icon_list.adoc +// 1. Replace instances with appropriate material. +// 2. Add the edited material to +// tinymce-docs/modules/ROOT/partials/configuration/icon_list.adoc // in alphabetical order by . (*not* ). -// 2. Do not bring these comments over with the edited material. | `++` | image:icons/.svg[.svg] | `+.svg+` diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/partials/configuration/.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/partials/configuration/{configuration_option}.adoc similarity index 66% rename from -new-material-templates/plugin-documentation-templates/ROOT/partials/configuration/.adoc rename to -new-material-templates/plugin-documentation-templates/ROOT/partials/configuration/{configuration_option}.adoc index 05bc7e93ea..391b450c3b 100644 --- a/-new-material-templates/plugin-documentation-templates/ROOT/partials/configuration/.adoc +++ b/-new-material-templates/plugin-documentation-templates/ROOT/partials/configuration/{configuration_option}.adoc @@ -1,12 +1,6 @@ [[]] == `` -// Replace all instances of with the -// configuration option name then remove this comment. - -// Add explanatory material as per the comment block below then remove -// the block and this comment. - //// What does the option do? Why use it? @@ -32,7 +26,7 @@ Are there risks? [source,js] ---- tinymce.init({ - selector: 'textarea', // change this value according to your html + selector: 'textarea', // Change this value according to your HTML : '' }); ---- @@ -46,24 +40,18 @@ To disable , set `` to `false`. [source,js] ---- tinymce.init({ - selector: 'textarea', // change this value according to your HTML + selector: 'textarea', // Change this value according to your HTML : 'false' }); ---- // Remove if not applicable. -// Edit the sub-head to singular or plural as required. -=== Limitation(s) of the `` option +=== Limitation of the `` option The `` option has the following limitations. -// Add explanatory material as per the comment block below then remove -// the block and this comment. - //// Known limitations. Complicated scenarios. Anything that warrants a CAUTION or WARNING admonition. -//// - -// Remove all comment lines and comment blocks before publishing. +//// \ No newline at end of file diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/partials/events/-events.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/partials/events/{plugincode}-events.adoc similarity index 90% rename from -new-material-templates/plugin-documentation-templates/ROOT/partials/events/-events.adoc rename to -new-material-templates/plugin-documentation-templates/ROOT/partials/events/{plugincode}-events.adoc index 245d8f32a5..2ac4644b64 100644 --- a/-new-material-templates/plugin-documentation-templates/ROOT/partials/events/-events.adoc +++ b/-new-material-templates/plugin-documentation-templates/ROOT/partials/events/{plugincode}-events.adoc @@ -3,8 +3,6 @@ The following events are provided by the xref:.adoc[ pl [cols="1,1,2",options="header"] |=== |Name |Data |Description - -// Five boilerplate rows. |EventOne |`+{ : }+` |Fired when event one description. |EventTwo |`+{ : , : }+` |Fired when event two description. |EventThree |N/A |Fired when event three description. @@ -16,6 +14,4 @@ The following events are provided by the xref:.adoc[ pl include::partial$misc/admon-requires-v.adoc[] |EventFour |`+{ : }+` |Fired when the event seven description. |EventEn |`+{ : , : }+` |Fired when event en description. -|=== - -// Remove all comment lines and comment blocks before publishing. +|=== \ No newline at end of file diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/partials/index-pages/opensource-plugins.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/partials/index-pages/opensource-plugins.adoc index ee3711a78f..92e47189f3 100644 --- a/-new-material-templates/plugin-documentation-templates/ROOT/partials/index-pages/opensource-plugins.adoc +++ b/-new-material-templates/plugin-documentation-templates/ROOT/partials/index-pages/opensource-plugins.adoc @@ -1,10 +1,8 @@ // Table row for an open-source plugin. -// Place this row into the extant table in `partials/index-pages/opensource-plugins.adoc` in alphabetical order. +// Place this row into the existing table in `partials/index-pages/opensource-plugins.adoc` in alphabetical order by . a| [.lead] xref:.adoc[] - - -// This file is instructional and is never included in the published name-space. + \ No newline at end of file diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/partials/index-pages/premium-plugins.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/partials/index-pages/premium-plugins.adoc index 472431f303..d8905d4459 100644 --- a/-new-material-templates/plugin-documentation-templates/ROOT/partials/index-pages/premium-plugins.adoc +++ b/-new-material-templates/plugin-documentation-templates/ROOT/partials/index-pages/premium-plugins.adoc @@ -1,10 +1,8 @@ // Table row for a Premium plugin. -// Place this row into the extant table in `partials/index-pages/premium-plugins.adoc` in alphabetical order. +// Place this row into the existing table in `partials/index-pages/premium-plugins.adoc` in alphabetical order by . a| [.lead] xref:.adoc[] - - -// This file is instructional and is never included in the published name-space. + \ No newline at end of file diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/partials/menu-item-ids/-menu-items.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/partials/menu-item-ids/-menu-items.adoc deleted file mode 100644 index c6cc961a91..0000000000 --- a/-new-material-templates/plugin-documentation-templates/ROOT/partials/menu-item-ids/-menu-items.adoc +++ /dev/null @@ -1,10 +0,0 @@ -[cols="1,1,2",options="header"] -|=== -|Menu item identifier |xref:menus-configuration-options.adoc#example-the-tinymce-default-menu-items[Default Menu Location] |Description - -|`+menu-identifier-1+` | |Description one. -|`+menu-identifier-2+` | |Description two. -|`+menu-identifier-n+` | |Description en. -|=== - -// Remove all comment lines and comment blocks before publishing. diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/partials/menu-item-ids/{plugincode}-menu-items.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/partials/menu-item-ids/{plugincode}-menu-items.adoc new file mode 100644 index 0000000000..f7bc1b666e --- /dev/null +++ b/-new-material-templates/plugin-documentation-templates/ROOT/partials/menu-item-ids/{plugincode}-menu-items.adoc @@ -0,0 +1,7 @@ +[cols="1,1,2",options="header"] +|=== +|Menu item identifier |xref:menus-configuration-options.adoc#example-the-tinymce-default-menu-items[Default Menu Location] |Description + +|`+menu-item-id-1+` | | +|`+menu-item-id-2+` | | +|=== \ No newline at end of file diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/partials/plugin-apis/-apis.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/partials/plugin-apis/{plugincode}-apis.adoc similarity index 58% rename from -new-material-templates/plugin-documentation-templates/ROOT/partials/plugin-apis/-apis.adoc rename to -new-material-templates/plugin-documentation-templates/ROOT/partials/plugin-apis/{plugincode}-apis.adoc index 29c7a14c12..6ed4b64b52 100644 --- a/-new-material-templates/plugin-documentation-templates/ROOT/partials/plugin-apis/-apis.adoc +++ b/-new-material-templates/plugin-documentation-templates/ROOT/partials/plugin-apis/{plugincode}-apis.adoc @@ -2,18 +2,14 @@ |=== |Name |Arguments |Description -// Four boilerplate rows. | | | -| | | -| | | // Markup to add a ‘requires this version of TinyMCE’ admonition into its own row // immediately above the event requiring such a notice. // If not needed, remove the markup and this comment. // If needed, edit the file-name and remove this comment. 3+| include::partial$misc/admon-requires-v.adoc[] -| | | -| | | +| | | |=== .Examples @@ -24,15 +20,4 @@ tinymce.activeEditor.plugins..(); // what this example does tinymce.activeEditor.plugins..(); - -// what this example does -tinymce.activeEditor.plugins..(); - -// what this example does -tinymce.activeEditor.plugins..(); - -// what this example does -tinymce.activeEditor.plugins..(); ---- - -// Remove all comment lines and comment blocks before publishing. diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/partials/toolbar-button-ids/-toolbar-buttons.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/partials/toolbar-button-ids/-toolbar-buttons.adoc deleted file mode 100644 index 8d7d27663a..0000000000 --- a/-new-material-templates/plugin-documentation-templates/ROOT/partials/toolbar-button-ids/-toolbar-buttons.adoc +++ /dev/null @@ -1,11 +0,0 @@ -[cols="1,3",options="header"] -|=== -|Toolbar button identifier |Description - -|`+ai-button-1+` |Description one. -|`+ai-button-2+` |Description two. -|`+ai-button-3+` |Description three. -|`+ai-button-n+` |Description en. -|=== - -// Remove all comment lines and comment blocks before publishing. diff --git a/-new-material-templates/plugin-documentation-templates/ROOT/partials/toolbar-button-ids/{plugincode}-toolbar-buttons.adoc b/-new-material-templates/plugin-documentation-templates/ROOT/partials/toolbar-button-ids/{plugincode}-toolbar-buttons.adoc new file mode 100644 index 0000000000..3a8f5f30be --- /dev/null +++ b/-new-material-templates/plugin-documentation-templates/ROOT/partials/toolbar-button-ids/{plugincode}-toolbar-buttons.adoc @@ -0,0 +1,7 @@ +[cols="1,3",options="header"] +|=== +|Toolbar button identifier |Description + +|`+toolbar-button-id-1+` | +|`+toolbar-button-id-2+` | +|=== \ No newline at end of file diff --git a/-new-material-templates/release-notes-template/ROOT/nav.adoc b/-new-material-templates/release-notes-template/ROOT/nav.adoc index c04931033b..839dc79e6d 100644 --- a/-new-material-templates/release-notes-template/ROOT/nav.adoc +++ b/-new-material-templates/release-notes-template/ROOT/nav.adoc @@ -1,4 +1,4 @@ -// The following two lines are already extant in `nav.adoc` and are here as a guidepost. +// The following two lines already exist in `nav.adoc` and are here as a guidepost. // The new navigation material is added immediately below these lines. * Release information ** xref:release-notes.adoc[Release notes for {productname} {productmajorversion}] @@ -18,6 +18,4 @@ **** xref:-release-notes.adoc#bug-fixes[Bug fixes] **** xref:-release-notes.adoc#security-fixes[Security fixes] **** xref:-release-notes.adoc#deprecated[Deprecated] -**** xref:-release-notes.adoc#known-issues[Known issues] - -// This file is instructional and is never included in the published name-space. +**** xref:-release-notes.adoc#known-issues[Known issues] \ No newline at end of file diff --git a/-new-material-templates/release-notes-template/ROOT/pages/release-notes.adoc b/-new-material-templates/release-notes-template/ROOT/pages/release-notes.adoc index 969edeb032..0b66f575d4 100644 --- a/-new-material-templates/release-notes-template/ROOT/pages/release-notes.adoc +++ b/-new-material-templates/release-notes-template/ROOT/pages/release-notes.adoc @@ -5,17 +5,4 @@ xref:-release-notes.adoc#overview[{productname} ] Release notes for {productname} -//rest of extant table here - -// Dummy table cell. -// 1. When the number of cells in the table is odd: -// * remove the inline comment markup pre-pending this -// element. -// -// 2. When the number of cells in the table is even: -// * prepend the inline comment markup to this -// element. -//a| - -|=== - +// Remember to uncomment the dummy cell when the number of cells in the table is odd to ensure the table renders correctly. diff --git a/-new-material-templates/release-notes-template/ROOT/pages/-release-notes.adoc b/-new-material-templates/release-notes-template/ROOT/pages/{x.y[.z]}-release-notes.adoc similarity index 72% rename from -new-material-templates/release-notes-template/ROOT/pages/-release-notes.adoc rename to -new-material-templates/release-notes-template/ROOT/pages/{x.y[.z]}-release-notes.adoc index aac899c021..fd60f60040 100644 --- a/-new-material-templates/release-notes-template/ROOT/pages/-release-notes.adoc +++ b/-new-material-templates/release-notes-template/ROOT/pages/{x.y[.z]}-release-notes.adoc @@ -1,15 +1,17 @@ -= TinyMCE -:navtitle: TinyMCE -:description: Release notes for TinyMCE += {productname} {release-version} +:release-version: +:navtitle: {productname} {release-version} +:description: Release notes for {productname} {release-version} :keywords: releasenotes, new, changes, bugfixes :page-toclevels: 1 include::partial$misc/admon-releasenotes-for-stable.adoc[] + [[overview]] == Overview -{productname} was released for {enterpriseversion} and {cloudname} on ,
^^, . These release notes provide an overview of the changes for {productname} , including: +{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. @@ -31,7 +33,7 @@ include::partial$misc/admon-releasenotes-for-stable.adoc[] [[new-premium-plugin]] New Premium plugin -The following new Premium plugin was released alongside {productname} . +The following new Premium plugin was released alongside {productname} {release-version}. === @@ -43,7 +45,7 @@ For information on the **** plugin, see xref:.a [[new-open-source-plugin]] == New Open Source plugin -The following new Open Source plugin was released alongside {productname} . +The following new Open Source plugin was released alongside {productname} {release-version}. === @@ -51,14 +53,15 @@ The new open source plugin, **** // description here. For information on the **** plugin, see xref:.adoc[]. + [[accompanying-premium-plugin-changes]] == Accompanying Premium plugin changes -The following premium plugin updates were released alongside {productname} . +The following premium plugin updates were released alongside {productname} {release-version}. === -The {productname} 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 . @@ -92,13 +95,13 @@ The following open source plugin has been announced as reaching its end-of-life: [[accompanying-enhanced-skins-and-icon-packs-changes]] == Accompanying Enhanced Skins & Icon Packs changes -The {productname} release includes an accompanying release of the **Enhanced Skins & Icon Packs**. +The {productname} {release-version} release includes an accompanying release of the **Enhanced Skins & Icon Packs**. === Enhanced Skins & Icon Packs The **Enhanced Skins & Icon Packs** release includes the following updates: -The **Enhanced Skins & Icon Packs** were rebuilt to pull in the changes also incorporated into the default {productname} skin, Oxide. +The **Enhanced Skins & Icon Packs** were rebuilt to pull in the changes also incorporated into the default {productname} {release-version} skin, Oxide. For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-and-icon-packs.adoc[Enhanced Skins & Icon Packs]. @@ -106,7 +109,7 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a [[improvements]] == Improvements -{productname} also includes the following improvement: +{productname} {release-version} also includes the following improvement: === // #TINY-vwxyz1 @@ -117,7 +120,7 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a [[additions]] == Additions -{productname} also includes the following addition: +{productname} {release-version} also includes the following addition: === // #TINY-vwxyz1 @@ -128,7 +131,7 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a [[changes]] == Changes -{productname} also includes the following change: +{productname} {release-version} also includes the following change: === // #TINY-vwxyz1 @@ -139,7 +142,7 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a [[removed]] == Removed -{productname} also includes the following removal: +{productname} {release-version} also includes the following removal: === // #TINY-vwxyz1 @@ -150,7 +153,7 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a [[bug-fixes]] == Bug fixes -{productname} also includes the following bug fix: +{productname} {release-version} also includes the following bug fix: === // #TINY-vwxyz1 @@ -161,7 +164,7 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a [[security-fixes]] == Security fixes -{productname} includes : +{productname} {release-version} includes : === // #TINY-vwxyz1 @@ -172,7 +175,7 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a [[deprecated]] == Deprecated -{productname} includes the following deprecation: +{productname} {release-version} includes the following deprecation: === The `` configuration property, ``, has been deprecated @@ -182,9 +185,9 @@ For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-a [[known-issues]] == Known issues -This section describes issues that users of {productname} may encounter and possible workarounds for these issues. +This section describes issues that users of {productname} {release-version} may encounter and possible workarounds for these issues. -There known issue in {productname} . +There known issue in {productname} {release-version}. === // #TINY-vwxyz1 diff --git a/-new-material-templates/release-notes-template/ROOT/partials/misc/supported-versions.adoc b/-new-material-templates/release-notes-template/ROOT/partials/misc/supported-versions.adoc deleted file mode 100644 index cce8334762..0000000000 --- a/-new-material-templates/release-notes-template/ROOT/partials/misc/supported-versions.adoc +++ /dev/null @@ -1,32 +0,0 @@ -[[supported-tinymce-versions]] -== Supported {productname} versions - -Supported versions of {productname}: - -[cols="^,^,^",options="header"] -|=== -|Version |Release Date |End of Support -// add new row with version, release date, and end-of-support date. -// use the internal spreadsheet to calculate the end-of-support date from the release date. -|6.6 |2023-07-19 |2025-01-19 -|6.5 |2023-06-21 |2024-12-21 -|6.4 |2023-03-29 |2024-09-29 -|6.3 |2022-12-08 |2024-06-08 -|6.2 |2022-09-26 |2024-03-26 -|6.1 |2022-07-13 |2024-01-13 -|6.0 |2022-04-07 |2023-10-07 -|=== - - - - - -To view our Software License Agreements, visit: - -* link:{legalpages}/cloud-use-subscription-agreement/[The {cloudname} Services Subscription Agreement]. -* link:{legalpages}/tiny-self-hosted-enterprise-agreement/[The {companyname} Self-Hosted Software License Agreement - (Enterprise Users)]. -* link:{legalpages}/tiny-self-hosted-oem-saas-agreement/[The {companyname} Self-Hosted Software License Agreement - (OEM & SaaS Users)]. - -Support for Partner Plugins is provided by Partner companies and is not the responsibility of {companynameformal}. For information on Partner Plugins, see: link:{companyurl}/partners/[https://www.tiny.cloud/partners/]. - -// This file is instructional and is never included in the published name-space. diff --git a/-new-material-templates/release-notes-template/antora.yml b/-new-material-templates/release-notes-template/antora.yml deleted file mode 100644 index f382848b8e..0000000000 --- a/-new-material-templates/release-notes-template/antora.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: tinymce -title: TinyMCE Documentation -# update the version value if required. Almost certainly *not* required. -version: '6' -asciidoc: - attributes: - # anchor configuration (the @ allows it to be overridden if required) - idprefix: '@' - 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 - webcomponent_url: https://cdn.jsdelivr.net/npm/@tinymce/tinymce-webcomponent@2/dist/tinymce-webcomponent.min.js - jquery_url: https://cdn.jsdelivr.net/npm/@tinymce/tinymce-jquery@2/dist/tinymce-jquery.min.js - default_meta_keywords: tinymce, documentation, docs, plugins, customizable skins, configuration, examples, html, php, java, javascript, image editor, inline editor, distraction-free editor, classic editor, wysiwyg - # product variables - productname: TinyMCE - productmajorversion: 6 - # update the productminorversion value if required. Likely required. - # Note: this value is not changed for .z updates. - # For example, an update from 6.6.0 to 6.6.1 does not require a change to this variable’s value. - productminorversion: '6.6' - ##### product name in codeblock - prodnamecode: tinymce - #### more names - companyname: Tiny - companynameformal: Tiny Technologies, Inc. - cloudname: Tiny Cloud - cloudfilemanager: Tiny Drive - enterpriseversion: TinyMCE Enterprise - communityname: TinyMCE Community - accountpage: Tiny Account - supportname: Tiny Support - betaprogram: Tiny Insights Program - #### some plugin names - prem_skins_icons: Enhanced Skins & Icon Packs - #### Plan names - tieroneplan: Tiny Cloud Core Plan - tiertwoplan: Tiny Cloud Essential Plan - tierthreeplan: Tiny Cloud Professional Plan - enterpriseplan: Tiny Custom Plans - ## common tiny.cloud URLs - supporturl: https://support.tiny.cloud - plugindirectory: https://www.tiny.cloud/tinymce/features/ - gettiny: https://www.tiny.cloud/get-tiny - blogurl: https://www.tiny.cloud/blog - download-community: https://www.tiny.cloud/get-tiny/self-hosted/ - download-enterprise: https://www.tiny.cloud/my-account/downloads/ - accountpageurl: https://www.tiny.cloud/my-account - accountkeyurl: https://www.tiny.cloud/my-account/key-manager/ - accountjwturl: https://www.tiny.cloud/my-account/jwt/ - accountsignup: https://www.tiny.cloud/auth/signup - pricingpage: https://www.tiny.cloud/pricing - contactpage: https://www.tiny.cloud/contact - legalpages: https://www.tiny.cloud/legal - communitysupporturl: https://stackoverflow.com/questions/tagged/tinymce - betaprogramurl: https://www.tiny.cloud/insights-program/ - # plugin-specific tiny.cloud URLs - aipricingurl: https://www.tiny.cloud/tinymce/features/ai-integration/ - revisionhistorypricingurl: https://www.tiny.cloud/tinymce/features/revision-history/ - importwordpricingurl: https://www.tiny.cloud/tinymce/features/import-from-word/ - exportwordpricingurl: https://www.tiny.cloud/tinymce/features/export-word/ - exportpdfpricingurl: https://www.tiny.cloud/tinymce/features/export-pdf/ - # HTML entities - tick: '✔' - cross: '✖' - tab: '  ' - newline: '
' - virt_ellps: '⋮' - ellps: '…' - # Demo logos - logofordemos: 'https://www.tiny.cloud/docs/images/logos/android-chrome-256x256.png' - logofordemoshtml: '

TinyMCE Logo

' - logofordemoshtmlright: '

TinyMCE Logo

' - -nav: -- modules/ROOT/nav.adoc -- modules/ROOT/moxiedoc_nav.adoc - -# This file is instructional and is never included in the published name-space. diff --git a/.api-version b/.api-version index 4122521804..8df288f274 100644 --- a/.api-version +++ b/.api-version @@ -1 +1 @@ -7.0.0 \ No newline at end of file +7.6.0 \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1a75130023..cdb643f696 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,4 +1,4 @@ -* @tinymce/documentation-team +* @tinymce/documentation-team @abhinavgandham @soritaheng @FarzadHayat @LewisAtTiny @kemister85 # Integration docs /integrations/ @tinymce/documentation-team @tinymce/editor-platform-team @tinymce/integrations-team diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a69a57aabd..253d9432ca 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -2,12 +2,9 @@ name: "CodeQL" on: push: - branches: [ "feature/**", "hotfix/**", "staging/**", "release/**" ] + branches: [ "feature/**", "hotfix/**", "release/**", "staging/**", "tinymce/**" ] pull_request: - branches: [ "staging/**", "release/**" ] -## Add schedule if needed -# schedule: -# - cron: "17 23 * * 5" + branches: [ "tinymce/**" ] jobs: analyze: @@ -25,18 +22,18 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} queries: +security-and-quality - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/develop_7_docs.yml b/.github/workflows/develop_7_docs.yml new file mode 100644 index 0000000000..1b17cc862e --- /dev/null +++ b/.github/workflows/develop_7_docs.yml @@ -0,0 +1,62 @@ +name: Develop 7 Docs + +on: + workflow_dispatch: + push: + paths: + - '**' + branches: + - 'feature/**' + - 'hotfix/**' + - 'release/**' + - 'staging/**' + +jobs: + build: + name: Build Docs and Deploy + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [21] + + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js + uses: actions/setup-node@v4 + with: + cache: 'yarn' + node-version: ${{ matrix.node-version }} + + - name: (Develop 7 Docs) Install dependencies + run: yarn install + + - name: (Develop 7 Docs) Build API References + run: yarn build + + - name: (Develop 7 Docs) Build Website + run: yarn antora ./antora-playbook.yml + + - name: (deploy) Prepare for branch deployments + shell: bash + run: | + printf "User-agent: * \nDisallow: /\n" > ./build/site/robots.txt + S3_BUCKET=$(node -e 'console.log(`s3://docs-${process.env.GITHUB_REF.replace("refs/heads/","").replace(/[/\s]/g, "-").replace(/[^0-9a-zA-Z-]/g, "").replace(/-$/g, "").toLowerCase()}.staging.tiny.cloud`)') + printf "S3_BUCKET: ${S3_BUCKET} (${#S3_BUCKET})\n" + if [ ${#S3_BUCKET} -lt 3 ] + then + echo "WARNING! S3_BUCKET name is too short" + fi + if [ ${#S3_BUCKET} -gt 63 ] + then + echo "WARNING! S3_BUCKET name is too long" + fi + echo $S3_BUCKET > S3_BUCKET + + - name: (deploy) Upload website to S3 + run: aws s3 sync --acl=public-read --delete ./build/site $(cat S3_BUCKET)/docs + env: + AWS_ACCESS_KEY_ID: ${{ secrets.STAGING_AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.STAGING_AWS_SECRET_ACCESS_KEY }} + AWS_EC2_METADATA_DISABLED: true \ No newline at end of file diff --git a/antora-playbook-local.yml b/antora-playbook-local.yml new file mode 100644 index 0000000000..3f6ce3c0fe --- /dev/null +++ b/antora-playbook-local.yml @@ -0,0 +1,21 @@ +site: + title: TinyMCE Documentation + url: https://www.tiny.cloud/docs + start_page: tinymce::index.adoc +content: + sources: + - url: ./ + branches: HEAD + start_path: ./ +urls: + html_extension_style: indexify + latest_version_segment: latest +ui: + bundle: + url: https://tiny-cloud-docs-antora-themes-production.s3.amazonaws.com/ui-bundle.zip + snapshot: true +asciidoc: + extensions: + - '@tinymce/antora-extension-livedemos' +runtime: + fetch: true diff --git a/antora-playbook.yml b/antora-playbook.yml index 0cc29750e2..c5fc872959 100644 --- a/antora-playbook.yml +++ b/antora-playbook.yml @@ -14,7 +14,8 @@ urls: latest_version_segment: latest ui: bundle: - url: https://tiny-cloud-docs-antora-themes-staging.s3.amazonaws.com/ui-bundle.zip + url: https://tiny-cloud-docs-antora-themes-production.s3.amazonaws.com/ui-bundle.zip + snapshot: true asciidoc: extensions: - '@tinymce/antora-extension-livedemos' diff --git a/antora.yml b/antora.yml index 5bb29f197e..23beb449cb 100644 --- a/antora.yml +++ b/antora.yml @@ -14,11 +14,19 @@ asciidoc: tinydrive_live_demo_url: https://cdn.tiny.cloud/1/qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc/tinydrive/7/tinydrive.min.js webcomponent_url: https://cdn.jsdelivr.net/npm/@tinymce/tinymce-webcomponent@2/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 + openai_proxy_token: eyJhbGciOiJFUzM4NCJ9.eyJhdWQiOlsiaHR0cHM6Ly9vcGVuYWkuYWktZGVtby1wcm94eS50aW55LmNsb3VkLyJdLCJleHAiOjE3NTEzMjgwMDAsImh0dHBzOi8vb3BlbmFpLmFpLWRlbW8tcHJveHkudGlueS5jbG91ZC9yb2xlIjoicHVibGljLWRlbW8iLCJpc3MiOiJodHRwczovL2FpLWRlbW8tcHJveHkudGlueS5jbG91ZC8iLCJqdGkiOiJmOGFmY2EyNC1mN2FhLTQxMjktYTc2Yy02YThlZDU3YjAyZjYiLCJzdWIiOiJhaS1hc3Npc3RhbnQtZGVtbyJ9.Xu0apHCbxgmRQTeTqrTIDFFhh2CgKeARRXa3mCxSGoCwZqkoQaFRZBCzDo8Xz7DuUa5mW2XHl-HYcYiXJM9ly16d0oY7lJefHBeLlmJEBE1CSttHBkCRWZS8eFLCasL6 default_meta_keywords: tinymce, documentation, docs, plugins, customizable skins, configuration, examples, html, php, java, javascript, image editor, inline editor, distraction-free editor, classic editor, wysiwyg + # product docker variables + dockerimageimportfromwordexporttoword: registry.containers.tiny.cloud/docx-converter-tiny + dockerimageexporttopdf: registry.containers.tiny.cloud/pdf-converter-tiny + dockerimageexporttopdfwindows: registry.containers.tiny.cloud/pdf-converter-windows-tiny + # document converter placeholder variables + exportpdf_service_url: exportpdf_service_url placeholder # product variables productname: TinyMCE productmajorversion: 7 - productminorversion: '7.0' + productminorversion: '7.6' ##### product name in codeblock prodnamecode: tinymce #### more names @@ -30,6 +38,7 @@ asciidoc: communityname: TinyMCE Community accountpage: Tiny Account supportname: Tiny Support + contactsales: Contact Sales betaprogram: Tiny Insights Program #### some plugin names prem_skins_icons: Enhanced Skins & Icon Packs diff --git a/modules/ROOT/examples/live-demos/advtemplate-readonly-template/example.js b/modules/ROOT/examples/live-demos/advtemplate-readonly-template/example.js new file mode 100644 index 0000000000..4d380e6211 --- /dev/null +++ b/modules/ROOT/examples/live-demos/advtemplate-readonly-template/example.js @@ -0,0 +1,102 @@ +const headers = { + 'Accept': 'application/json', + 'Content-Type': 'application/json', +}; + +const handleResponse = (message) => (response) => { + if (!response.ok) { + return response.text().then((error) => { + console.error(error); + throw new Error(message); + }); + } + return response.json(); +}; + +const advtemplate_list = () => + fetch('/categories', { + method: 'GET', + headers, + }).then(handleResponse('Failed to get template list')); + +const advtemplate_get_template = (id) => + fetch(`/templates/${id}`, { + method: 'GET', + headers, + }).then(handleResponse('Failed to get template')); + +const advtemplate_create_category = (title) => + fetch('/categories', { + method: 'POST', + body: JSON.stringify({ title }), + headers, + }).then(handleResponse('Failed to create category')); + +const advtemplate_create_template = (title, content, categoryId) => + fetch('/templates', { + method: 'POST', + body: JSON.stringify({ title, content, categoryId }), + headers, + }).then(handleResponse('Failed to create template')); + +const advtemplate_rename_category = (id, title) => + fetch(`/categories/${id}`, { + method: 'PUT', + body: JSON.stringify({ title }), + headers, + }).then(handleResponse('Failed to rename category')); + +const advtemplate_rename_template = (id, title) => + fetch(`/templates/${id}`, { + method: 'PUT', + body: JSON.stringify({ title }), + headers, + }).then(handleResponse('Failed to rename template')); + +const advtemplate_delete_template = (id) => + fetch(`/templates/${id}`, { + method: 'DELETE', + headers, + }).then(handleResponse('Failed to delete template')); + +const advtemplate_delete_category = (id) => + fetch(`/categories/${id}`, { + method: 'DELETE', + headers, + }).then(handleResponse('Failed to delete category')); + +const advtemplate_move_template = (id, categoryId) => + fetch(`/templates/${id}`, { + method: 'PATCH', + body: JSON.stringify({ categoryId }), + headers, + }).then(handleResponse('Failed to move template')); + +const advtemplate_move_category_items = (id, categoryId) => + fetch(`/categories/${id}`, { + method: 'PATCH', + body: JSON.stringify({ categoryId }), + headers, + }).then(handleResponse('Failed to move all templates to new category')); + +tinymce.init({ + selector: 'textarea#readonly-locked-template', + plugins: [ + 'advlist', 'anchor', 'autolink', 'charmap', 'code', 'fullscreen', + 'help', 'image', 'insertdatetime', 'link', 'lists', 'media', + 'preview', 'searchreplace', 'table', 'visualblocks', 'advtemplate' + ], + contextmenu: 'advtemplate', + toolbar: 'addtemplate inserttemplate | undo redo | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image', + + advtemplate_list, + advtemplate_get_template, + advtemplate_create_category, + advtemplate_create_template, + advtemplate_rename_category, + advtemplate_move_category_items, + advtemplate_delete_category, + advtemplate_rename_template, + advtemplate_move_template, + advtemplate_delete_template, +}); diff --git a/modules/ROOT/examples/live-demos/advtemplate-readonly-template/index.html b/modules/ROOT/examples/live-demos/advtemplate-readonly-template/index.html new file mode 100644 index 0000000000..23fe3723c5 --- /dev/null +++ b/modules/ROOT/examples/live-demos/advtemplate-readonly-template/index.html @@ -0,0 +1,52 @@ + diff --git a/modules/ROOT/examples/live-demos/advtemplate-readonly-template/index.js b/modules/ROOT/examples/live-demos/advtemplate-readonly-template/index.js new file mode 100644 index 0000000000..d14a053d9d --- /dev/null +++ b/modules/ROOT/examples/live-demos/advtemplate-readonly-template/index.js @@ -0,0 +1,348 @@ +const data = [ + { + title: 'Quick replies', + items: [ + { + title: 'Message received', + content: '

Hey {{prefix}}Customer.FirstName{{suffix}}!

\n

Just a quick note to say we’ve received your message, and will get back to you within 48 hours.

\n

For reference, your ticket number is: {{mergetag-open}}Ticket.Number{{suffix}}

\n

Should you have any questions in the meantime, just reply to this email and it will be attached to this ticket.

\n

 

\n

Regards,

\n

{{prefix}}Agent.FirstName{{suffix}}

' + }, + { + title: 'Thanks for the feedback', + content: '

Hi {{prefix}}Customer.FirstName{{suffix}},

\n

We appreciate you taking the time to provide feedback on {{prefix}}Product.Name{{suffix}}.

\n

It sounds like it wasn’t able to fully meet your expectations, for which we apologize. Rest assured our team looks at each piece of feedback and uses it to decide what to focus on next with {{prefix}}Product.Name{{suffix}}.

\n

 

\n

All the best, and let us know if there’s anything else we can do to help.

\n

-{{prefix}}Agent.FirstName{{suffix}}

' + }, + { + title: 'Still working on case', + content: '

Hi {{prefix}}Customer.FirstName{{suffix}},

\n

Just a quick note to let you know we’re still working on your case. It’s taking a bit longer than we hoped, but we’re aiming to get you an answer in the next 48 hours.

\n

Stay tuned,

\n

{{prefix}}Agent.FirstName{{suffix}}

' + } + ] + }, + { + title: 'Closing tickets', + items: [ + { + title: 'Closing ticket', + content: '

Hi {{prefix}}Customer.FirstName{{suffix}},

\n

We haven’t heard back from you in over a week, so we have gone ahead and closed your ticket number {{prefix}}Ticket.Number{{suffix}}.

\n

If you’re still running into issues, not to worry, just reply to this email and we will re-open your ticket.

\n

 

\n

All the best,

\n

{{prefix}}Agent.FirstName{{suffix}}

' + }, + { + title: 'Post-call survey', + content: '

Hey {{prefix}}Customer.FirstName{{suffix}}!

\n

 

\n

How did we do?

\n

If you have a few moments, we’d love you to fill out our post-support survey: {{prefix}}Survey.Link{{suffix}}

\n

 

\n

Thanks in advance!
{{prefix}}Company.Name{{suffix}} Customer Support

' + } + ] + }, + { + title: 'Locked Product support', + locked: true, + items: [ + { + title: 'How to find model number', + content: '

Hi {{prefix}}Customer.FirstName{{suffix}},

\n

 

\n

My name is {{prefix}}Agent.FirstName{{suffix}} and I will be glad to assist you today.

\n

To troubleshoot your issue, we first need your model number, which can be found on the underside of your product beneath the safety warning label. 

\n

It should look something like the following: XX.XXXXX.X

\n

Once you send it over, I will advise on next steps.

\n

 

\n

Thanks!

\n

{{prefix}}Agent.FirstName{{suffix}}

' + }, + { + title: 'Support escalation', + content: '

Hi {{prefix}}Customer.FirstName{{suffix}},

\n

We have escalated your ticket {{prefix}}Ticket.Number{{suffix}} to second-level support.

\n

You should hear back from the new agent on your case, {{prefix}}NewAgent.FirstName{{suffix}}, shortly.

\n

 

\n

Thanks,

\n

{{prefix}}Company.Name{{suffix}} Customer Support

' + } + ] + } +]; + +class StoreError extends Error { + constructor(status, message) { + super(message); + this.name = "StoreError"; + this.status = status + } +} + +const isStoreError = (e) => + e instanceof StoreError; + + +const create = (data = []) => { + const storeItems = { + items: [] + }; + + let id = 0; + const genId = () => (++id).toString(); + const categoryIndex = {}; + const templateIndex = {}; + + const isNonEmptyString = (value) => + typeof value === 'string' && value.length > 0; + + const isPositiveInteger = (str) => { + const number = Number(str); + return Number.isInteger(number) && number > 0; + } + + const isValidId = (value) => + isNonEmptyString(value) && isPositiveInteger(value); + + const validate = (value, predicate, message) => { + if (predicate(value)) { + return; + } else { + throw new StoreError(400, message); + } + }; + + const validateId = (id) => + validate(id, isValidId, `Invalid "id" parameter: ${id}`); + + const validateTitle = (title) => + validate(title, isNonEmptyString, `Invalid "title" parameter: ${title}`); + + const getParent = (id) => + typeof id === 'undefined' ? storeItems : getCategory(id); + + const filterOut = (items, id) => + items.filter((item) => item.id !== id); + + const list = () => { + const resp = [...storeItems.items]; + return resp; + }; + + const getCategory = (id) => { + validate(id, isValidId, `Invalid "id" parameter: ${id}`) + const category = categoryIndex[id]; + if (typeof category !== 'undefined') { + return category; + } else { + throw new StoreError(404, 'Category not found'); + } + }; + + const getTemplate = (id) => { + validateId(id) + const res = templateIndex[id]; + if (typeof res !== 'undefined') { + return res + } else { + throw new StoreError(404, 'Template not found'); + } + }; + + const createCategory = (title, locked) => { + validateTitle(title); + + const id = genId(); + const category = { + id, + title, + locked, + items: [] + }; + categoryIndex[id] = category; + storeItems.items = [...storeItems.items, category]; + return category; + }; + + const createTemplate = (title, content, categoryId) => { + validateTitle(title); + validate(content, isNonEmptyString, `Invalid "content" parameter: ${content}`); + + const id = genId(); + const template = { + id, + title, + content, + }; + const parent = getParent(categoryId); + parent.items = [...parent.items, template]; + templateIndex[id] = [template, categoryId]; + + return template; + }; + + const renameCategory = (id, title) => { + validateTitle(title); + const category = getCategory(id); + category.title = title; + }; + + const renameTemplate = (id, title) => { + validateTitle(title); + const [template] = getTemplate(id); + template.title = title; + }; + + const deleteTemplate = (id) => { + const [, categoryId] = getTemplate(id); + const parent = getParent(categoryId); + parent.items = filterOut(parent.items, id); + delete templateIndex[id]; + }; + + const deleteCategory = (id) => { + const category = getCategory(id); + category.items.forEach((template) => deleteTemplate(template.id)); + store.items = filterOut(storeItems.items, id); + delete categoryIndex[category.id]; + }; + + const moveTemplate = (id, newCategoryId) => { + const [template, categoryId] = getTemplate(id); + if (categoryId === newCategoryId) { + return; + } + + const oldParent = getParent(categoryId); + const newParent = getParent(newCategoryId); + newParent.items = [...newParent.items, template]; + oldParent.items = filterOut(oldParent.items, id); + templateIndex[id] = [template, newCategoryId]; + }; + + const moveCategoryItems = (id, newCategoryId) => { + const oldCategory = getCategory(id); + if (id === newCategoryId) { + return; + } + oldCategory.items.forEach((item) => moveTemplate(item.id, newCategoryId)); + }; + + const load = (items, id) => { + items.forEach((item) => { + if (item.items) { + const category = createCategory(item.title, item.locked); + load(item.items, category.id); + } else { + createTemplate(item.title, item.content, id); + } + }); + }; + + load(data); + + return { + list, + getTemplate, + createCategory, + createTemplate, + renameCategory, + renameTemplate, + deleteTemplate, + deleteCategory, + moveTemplate, + moveCategoryItems + }; +} + + +const store = create(data); + +const advtemplate_list = async () => store.list(); + +const advtemplate_create_category = async (title) => { + try { + return store.createCategory(title); + } catch (e) { + console.error(e); + throw new Error('Failed to create category'); + } +}; + + +const advtemplate_create_template = async (title, content, categoryId) => { + try { + return store.createTemplate(title, content, categoryId); + } catch (e) { + console.error(e); + throw new Error('Failed to create template'); + } +}; + + +const advtemplate_get_template = async (id) => { + try { + const [template] = store.getTemplate(id); + return template; + } catch (e) { + console.error(e); + throw new Error('Failed to get template'); + } +}; + +const advtemplate_rename_category = async (id, title) => { + try { + store.renameCategory(id, title); + return {}; + } catch (e) { + console.error(e); + throw new Error('Failed to rename category'); + } +}; + +const advtemplate_rename_template = async (id, title) => { + try { + store.renameTemplate(id, title); + return {}; + } catch (e) { + console.error(e); + throw new Error('Failed to rename template'); + } +}; + +const advtemplate_delete_category = async (id) => { + try { + store.deleteCategory(id); + return {}; + } catch (e) { + console.error(e); + throw new Error('Failed to delete category'); + } +}; + +const advtemplate_delete_template = async (id) => { + try { + store.deleteTemplate(id); + return {}; + } catch (e) { + console.error(e); + throw new Error('Failed to delete template'); + } +}; + + +const advtemplate_move_template = async (id, categoryId) => { + try { + store.moveTemplate(id, categoryId); + return {}; + } catch (e) { + console.error(e); + throw new Error('Failed to move template'); + } +}; + +const advtemplate_move_category_items = async (id, categoryId) => { + try { + store.moveCategoryItems(id, categoryId); + return {}; + } catch (e) { + console.error(e); + throw new Error('Failed to move category items'); + } +}; + +tinymce.init({ + selector: 'textarea#readonly-locked-template', + plugins: [ + 'advlist', 'anchor', 'autolink', 'charmap', 'code', 'fullscreen', + 'help', 'image', 'insertdatetime', 'link', 'lists', 'media', + 'preview', 'searchreplace', 'table', 'visualblocks', 'advtemplate' + ], + contextmenu: 'advtemplate', + toolbar: 'addtemplate inserttemplate | undo redo | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image', + + advtemplate_list, + advtemplate_get_template, + advtemplate_create_category, + advtemplate_create_template, + advtemplate_rename_category, + advtemplate_move_category_items, + advtemplate_delete_category, + advtemplate_rename_template, + advtemplate_move_template, + advtemplate_delete_template, +}); diff --git a/modules/ROOT/examples/live-demos/ai-demo/index.html b/modules/ROOT/examples/live-demos/ai-demo/index.html deleted file mode 100644 index 608c7b5fd3..0000000000 --- a/modules/ROOT/examples/live-demos/ai-demo/index.html +++ /dev/null @@ -1,30 +0,0 @@ - diff --git a/modules/ROOT/examples/live-demos/ai-demo/index.js b/modules/ROOT/examples/live-demos/ai-demo/index.js deleted file mode 100644 index d992b1a016..0000000000 --- a/modules/ROOT/examples/live-demos/ai-demo/index.js +++ /dev/null @@ -1,13 +0,0 @@ -// a generic TinyMCE configuration with ai plugin and toolbar added. - -tinymce.init({ - selector: 'textarea#ai', - plugins: [ - "advlist", "anchor", "autolink", "charmap", "code", "fullscreen", - "help", "image", "insertdatetime", "link", "lists", "media", - "preview", "searchreplace", "table", "visualblocks", "ai", - ], - height: 1200, - toolbar: "aidialog | undo redo |link image accordion | styles | bold italic underline strikethrough | align | bullist numlist", -}); - diff --git a/modules/ROOT/examples/live-demos/ai/example.js b/modules/ROOT/examples/live-demos/ai/example.js new file mode 100644 index 0000000000..5da681e52d --- /dev/null +++ b/modules/ROOT/examples/live-demos/ai/example.js @@ -0,0 +1,149 @@ +const fetchApi = import( + 'https://unpkg.com/@microsoft/fetch-event-source@2.0.1/lib/esm/index.js' +).then((module) => module.fetchEventSource); + +// This example stores the API key in the client side integration. This is not recommended for any purpose. +// Instead, an alternate method for retrieving the API key should be used. +const api_key = ''; + +const ai_request = (request, respondWith) => { + respondWith.stream((signal, streamMessage) => { + // Adds each previous query and response as individual messages + const conversation = request.thread.flatMap((event) => { + if (event.response) { + return [ + { role: 'user', content: event.request.query }, + { role: 'assistant', content: event.response.data }, + ]; + } else { + return []; + } + }); + + // System messages provided by the plugin to format the output as HTML content. + const systemMessages = request.system.map((content) => ({ + role: 'system', + content, + })); + + // Forms the new query sent to the API + const content = + request.context.length === 0 || conversation.length > 0 + ? request.query + : `Question: ${request.query} Context: """${request.context}"""`; + + const messages = [ + ...conversation, + ...systemMessages, + { role: 'user', content }, + ]; + + let hasHead = false; + let markdownHead = ''; + + const hasMarkdown = (message) => { + if (message.includes('`') && markdownHead !== '```') { + const numBackticks = message.split('`').length - 1; + markdownHead += '`'.repeat(numBackticks); + if (hasHead && markdownHead === '```') { + markdownHead = ''; + hasHead = false; + } + return true; + } else if (message.includes('html') && markdownHead === '```') { + markdownHead = ''; + hasHead = true; + return true; + } + return false; + }; + + const requestBody = { + model: 'gpt-4o', + temperature: 0.7, + max_tokens: 4000, + messages, + stream: true, + }; + + const openAiOptions = { + signal, + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${api_key}`, + }, + body: JSON.stringify(requestBody), + }; + + const onopen = async (response) => { + if (response) { + const contentType = response.headers.get('content-type'); + if (response.ok && contentType?.includes('text/event-stream')) { + return; + } else if (contentType?.includes('application/json')) { + const data = await response.json(); + if (data.error) { + throw new Error( + `${data.error.type}: ${data.error.message}` + ); + } + } + } else { + throw new Error('Failed to communicate with the ChatGPT API'); + } + }; + + // This function passes each new message into the plugin via the `streamMessage` callback. + const onmessage = (ev) => { + const data = ev.data; + if (data !== '[DONE]') { + const parsedData = JSON.parse(data); + const firstChoice = parsedData?.choices[0]; + const message = firstChoice?.delta?.content; + if (message && message !== '') { + if (!hasMarkdown(message)) { + streamMessage(message); + } + } + } + }; + + const onerror = (error) => { + // Stop operation and do not retry by the fetch-event-source + throw error; + }; + + // Use microsoft's fetch-event-source library to work around the 2000 character limit + // of the browser `EventSource` API, which requires query strings + return fetchApi + .then((fetchEventSource) => + fetchEventSource('https://api.openai.com/v1/chat/completions', { + ...openAiOptions, + openWhenHidden: true, + onopen, + onmessage, + onerror, + }) + ) + .then(async (response) => { + if (response && !response.ok) { + const data = await response.json(); + if (data.error) { + throw new Error( + `${data.error.type}: ${data.error.message}` + ); + } + } + }) + .catch(onerror); + }); +}; + +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'ai advlist anchor autolink charmap advcode emoticons fullscreen help image link lists media preview searchreplace table', + toolbar: 'undo redo | aidialog aishortcuts | styles fontsizeinput | bold italic | align bullist numlist | table link image | code', + height: 650, + ai_request, +}); diff --git a/modules/ROOT/examples/live-demos/ai/index.html b/modules/ROOT/examples/live-demos/ai/index.html new file mode 100644 index 0000000000..8302adecc4 --- /dev/null +++ b/modules/ROOT/examples/live-demos/ai/index.html @@ -0,0 +1,13 @@ + diff --git a/modules/ROOT/examples/live-demos/ai/index.js b/modules/ROOT/examples/live-demos/ai/index.js new file mode 100644 index 0000000000..deccd1ebc6 --- /dev/null +++ b/modules/ROOT/examples/live-demos/ai/index.js @@ -0,0 +1,145 @@ +const fetchApi = import( + 'https://unpkg.com/@microsoft/fetch-event-source@2.0.1/lib/esm/index.js' +).then((module) => module.fetchEventSource); + +const ai_request = (request, respondWith) => { + respondWith.stream((signal, streamMessage) => { + // Adds each previous query and response as individual messages + const conversation = request.thread.flatMap((event) => { + if (event.response) { + return [ + { role: 'user', content: event.request.query }, + { role: 'assistant', content: event.response.data }, + ]; + } else { + return []; + } + }); + + // System messages provided by the plugin to format the output as HTML content. + const systemMessages = request.system.map((content) => ({ + role: 'system', + content, + })); + + // Forms the new query sent to the API + const content = + request.context.length === 0 || conversation.length > 0 + ? request.query + : `Question: ${request.query} Context: """${request.context}"""`; + + const messages = [ + ...conversation, + ...systemMessages, + { role: 'user', content }, + ]; + + let hasHead = false; + let markdownHead = ''; + + const hasMarkdown = (message) => { + if (message.includes('`') && markdownHead !== '```') { + const numBackticks = message.split('`').length - 1; + markdownHead += '`'.repeat(numBackticks); + if (hasHead && markdownHead === '```') { + markdownHead = ''; + hasHead = false; + } + return true; + } else if (message.includes('html') && markdownHead === '```') { + markdownHead = ''; + hasHead = true; + return true; + } + return false; + }; + + const requestBody = { + model: 'gpt-4o', + temperature: 0.7, + max_tokens: 4000, + messages, + stream: true, + }; + + const openAiOptions = { + signal, + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer {{ openai_proxy_token }}`, + }, + body: JSON.stringify(requestBody), + }; + + const onopen = async (response) => { + if (response) { + const contentType = response.headers.get('content-type'); + if (response.ok && contentType?.includes('text/event-stream')) { + return; + } else if (contentType?.includes('application/json')) { + const data = await response.json(); + if (data.error) { + throw new Error( + `${data.error.type}: ${data.error.message}` + ); + } + } + } else { + throw new Error('Failed to communicate with the ChatGPT API'); + } + }; + + // This function passes each new message into the plugin via the `streamMessage` callback. + const onmessage = (ev) => { + const data = ev.data; + if (data !== '[DONE]') { + const parsedData = JSON.parse(data); + const firstChoice = parsedData?.choices[0]; + const message = firstChoice?.delta?.content; + if (message && message !== '') { + if (!hasMarkdown(message)) { + streamMessage(message); + } + } + } + }; + + const onerror = (error) => { + // Stop operation and do not retry by the fetch-event-source + throw error; + }; + + // Use microsoft's fetch-event-source library to work around the 2000 character limit + // of the browser `EventSource` API, which requires query strings + return fetchApi + .then((fetchEventSource) => + fetchEventSource('{{ openai_proxy_url }}', { + ...openAiOptions, + openWhenHidden: true, + onopen, + onmessage, + onerror, + }) + ) + .then(async (response) => { + if (response && !response.ok) { + const data = await response.json(); + if (data.error) { + throw new Error( + `${data.error.type}: ${data.error.message}` + ); + } + } + }) + .catch(onerror); + }); +}; + +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'ai advlist anchor autolink charmap advcode emoticons fullscreen help image link lists media preview searchreplace table', + toolbar: 'undo redo | aidialog aishortcuts | styles fontsizeinput | bold italic | align bullist numlist | table link image | code', + height: 650, + ai_request, +}); diff --git a/modules/ROOT/examples/live-demos/comments-callback-with-mentions/index.html b/modules/ROOT/examples/live-demos/comments-callback-with-mentions/index.html new file mode 100644 index 0000000000..fb90bbd07a --- /dev/null +++ b/modules/ROOT/examples/live-demos/comments-callback-with-mentions/index.html @@ -0,0 +1,32 @@ + diff --git a/modules/ROOT/examples/live-demos/comments-callback-with-mentions/index.js b/modules/ROOT/examples/live-demos/comments-callback-with-mentions/index.js new file mode 100644 index 0000000000..d59ba9e27c --- /dev/null +++ b/modules/ROOT/examples/live-demos/comments-callback-with-mentions/index.js @@ -0,0 +1,335 @@ +import ('https://cdn.jsdelivr.net/npm/@faker-js/faker@9/dist/index.min.js').then(({ faker }) => { + const adminUser = { + id: 'johnsmith', + name: 'John Smith', + fullName: 'John Smith', + description: 'Company Founder', + image: "https://i.pravatar.cc/150?img=11" + }; + + const currentUser = { + id: 'jennynichols', + name: 'Jenny Nichols', + fullName: 'Jenny Nichols', + description: 'Marketing Director', + image: "https://i.pravatar.cc/150?img=10" + }; + + const conversationDb = { + 'mce-conversation_19679600221621399703915': { + uid: 'mce-conversation_19679600221621399703915', + comments: [{ + uid: 'mce-conversation_19679600221621399703915', + author: currentUser.id, + authorName: currentUser.fullName, + authorAvatar: currentUser.image, + content: `What do you think about this @${adminUser.id}?`, + createdAt: '2021-05-19T04:48:23.914Z', + modifiedAt: '2021-05-19T04:48:23.914Z' + }, + { + uid: 'mce-conversation_19679600221621399703917', + author: adminUser.id, + authorName: adminUser.fullName, + authorAvatar: adminUser.image, + content: `I think this is a great idea @${currentUser.id}!`, + createdAt: "2024-05-28T12:54:24.126Z", + modifiedAt: "2024-05-28T12:54:24.126Z", + }] + }, + 'mce-conversation_420304606321716900864126': { + uid: 'mce-conversation_420304606321716900864126', + comments: [{ + uid: 'mce-conversation_420304606321716900864126', + author: adminUser.id, + authorName: adminUser.fullName, + authorAvatar: adminUser.image, + content: `@${currentUser.id} Please revise this sentence, exclamation points are unprofessional!`, + createdAt: '2024-05-28T12:54:24.126Z', + modifiedAt: '2024-05-28T12:54:24.126Z' + }] + } + }; + + const fakeDelay = 200; + const numberOfUsers = 200; + const randomString = () => { + return crypto.getRandomValues(new Uint32Array(1))[0].toString(36).substring(2, 14); + }; + + /* These are "local" caches of the data returned from the fake server */ + let fetchedUsers = false; + let usersRequest; // Promise + const userRequest = {}; + const resolvedConversationDb = {}; + + const setupFakeServer = () => { + const images = [ adminUser.image, currentUser.image ]; + const userNames = [ adminUser.fullName, currentUser.fullName ]; + + for (let i = 0; i < numberOfUsers; i++) { + images.push(faker.image.avatar()); + userNames.push(`${faker.person.firstName()} ${faker.person.lastName()}`); + } + + /* This represents a database of users on the server */ + const userDb = { + [adminUser.id]: adminUser, + [currentUser.id]: currentUser + }; + userNames.map((fullName) => { + if ((fullName !== currentUser.fullName) && (fullName !== adminUser.fullName)) { + const id = fullName.toLowerCase().replace(/ /g, ''); + userDb[id] = { + id, + name: fullName, + fullName, + description: faker.person.jobTitle(), + image: images[Math.floor(images.length * Math.random())] + }; + } + }); + + /* This represents getting the complete list of users from the server with the details required for the mentions "profile" item */ + const fetchUsers = () => new Promise((resolve) => { + /* simulate a server delay */ + setTimeout(() => { + const users = Object.keys(userDb).map((id) => ({ + id, + name: userDb[id].name, + image: userDb[id].image, + description: userDb[id].description + })); + resolve(users); + }, fakeDelay); + }); + + const fetchUser = (id) => new Promise((resolve, reject) => { + /* simulate a server delay */ + setTimeout(() => { + if (Object.prototype.hasOwnProperty.call(userDb, id)) { + resolve(userDb[id]); + } + reject('unknown user id "' + id + '"'); + }, fakeDelay); + }); + + return { + fetchUsers, + fetchUser + }; + }; + + const fakeServer = setupFakeServer(); + + const mentions_fetch = (query, success) => { + if (!fetchedUsers) { + fetchedUsers = true; + usersRequest = fakeServer.fetchUsers(); + } + usersRequest.then((users) => { + const userMatch = (name) => name.toLowerCase().indexOf(query.term.toLowerCase()) !== -1; + success(users.filter((user) => userMatch(user.name) || userMatch(user.id))); + fetchedUsers = false; + }); + }; + + const mentions_menu_hover = (userInfo, success) => { + if (!userRequest[userInfo.id]) { + userRequest[userInfo.id] = fakeServer.fetchUser(userInfo.id); + } + userRequest[userInfo.id].then((userDetail) => { + success({ type: 'profile', user: userDetail }); + }); + }; + + const mentions_menu_complete = (editor, userInfo) => { + const span = editor.getDoc().createElement('span'); + span.className = 'mymention'; + span.setAttribute('style', 'color: #37F;'); + span.setAttribute('data-mention-id', userInfo.id); + span.appendChild(editor.getDoc().createTextNode('@' + userInfo.name)); + return span; + }; + + const mentions_select = (mention, success) => { + const id = mention.getAttribute('data-mention-id'); + if (id) { + userRequest[id] = fakeServer.fetchUser(id); + userRequest[id].then((userDetail) => { + success({ type: 'profile', user: userDetail }); + }); + } + }; + + const tinycomments_create = (req, done, fail) => { + if (req.content === 'fail') { + fail(new Error('Something has gone wrong...')); + } else { + const uid = 'annotation-' + randomString(); + conversationDb[uid] = { + uid, + comments: [{ + uid, + authorName: currentUser.fullName, + authorAvatar: currentUser.image, + author: currentUser.name, + content: req.content, + createdAt: req.createdAt, + modifiedAt: req.createdAt + }] + }; + + setTimeout(() => { + done({ + conversationUid: uid + }); + }, fakeDelay); + } + }; + + const tinycomments_reply = (req, done) => { + const replyUid = 'annotation-' + randomString(); + const current = conversationDb[req.conversationUid]; + current.comments.push( + { + uid: replyUid, + authorName: currentUser.fullName, + authorAvatar: currentUser.image, + author: currentUser.name, + content: req.content, + createdAt: req.createdAt, + modifiedAt: req.createdAt + } + ); + + setTimeout(() => { + done({ + commentUid: replyUid + }); + }, fakeDelay); + }; + + const tinycomments_delete = (req, done) => { + delete conversationDb[req.conversationUid]; + + setTimeout(() => { + done({ + canDelete: true + }); + }, fakeDelay); + }; + + const tinycomments_resolve = (req, done) => { + resolvedConversationDb[req.conversationUid] = conversationDb[req.conversationUid]; + delete conversationDb[req.conversationUid]; + + setTimeout(() => { + done({ + canResolve: true + }); + }, fakeDelay); + }; + + const tinycomments_delete_comment = (req, done) => { + const current = conversationDb[req.conversationUid]; + // Should be supported on browsers ... + current.comments = current.comments.filter((f) => { + return f.uid !== req.commentUid; + }); + + setTimeout(() => { + done({ + canDelete: true + }); + }, fakeDelay); + }; + + const tinycomments_edit_comment = (req, done) => { + const current = conversationDb[req.conversationUid]; + // Should be supported on browsers ... + current.comments = current.comments.map((f) => { + return f.uid === req.commentUid ? { + ...f, + content: req.content, + modifiedAt: new Date().toISOString() + } : f; + }); + + setTimeout(() => { + done({ + canEdit: true + }); + }, fakeDelay); + }; + + const tinycomments_delete_all = (req, done) => { + Object.keys(conversationDb).forEach((k) => { + delete conversationDb[k]; + }); + + setTimeout(() => { + done({ + canDelete: true + }); + }, fakeDelay); + }; + + const tinycomments_lookup = (req, done) => { + setTimeout(() => { + done({ + conversation: { + uid: conversationDb[req.conversationUid].uid, + comments: conversationDb[req.conversationUid].comments.slice(0) + } + }); + }, fakeDelay); + }; + + const tinycomments_fetch = (_, done) => { + setTimeout(() => done({ + conversations: conversationDb + }), fakeDelay); + }; + + + tinymce.init({ + selector: 'textarea#comments-callback', + license_key: 'gpl', + toolbar: 'addcomment showcomments code | bold italic underline', + menubar: 'file edit view insert format tools tc help', + menu: { + tc: { + title: 'TinyComments', + items: 'addcomment showcomments deleteallconversations' + } + }, + plugins: [ 'tinycomments', 'mentions', 'help', 'code', 'quickbars', 'link', 'lists', 'image' ], + quickbars_selection_toolbar: 'alignleft aligncenter alignright | addcomment showcomments', + quickbars_image_toolbar: 'alignleft aligncenter alignright | rotateleft rotateright | imageoptions', + tinycomments_mentions_enabled: true, + sidebar_show: 'showcomments', + + mentions_item_type: 'profile', + mentions_min_chars: 0, + mentions_selector: '.mymention', + mentions_fetch, + mentions_menu_hover, + mentions_menu_complete, + mentions_select, + + tinycomments_mode: 'callback', + tinycomments_author: currentUser.id, + tinycomments_author_name: currentUser.fullName, + tinycomments_avatar: currentUser.image, + tinycomments_create, + tinycomments_reply, + tinycomments_delete, + tinycomments_resolve, + tinycomments_delete_all, + tinycomments_lookup, + tinycomments_delete_comment, + tinycomments_edit_comment, + tinycomments_fetch, + }); +}); diff --git a/modules/ROOT/examples/live-demos/comments-callback/example.js b/modules/ROOT/examples/live-demos/comments-callback/example.js index 68e5977e10..1d944e99ee 100644 --- a/modules/ROOT/examples/live-demos/comments-callback/example.js +++ b/modules/ROOT/examples/live-demos/comments-callback/example.js @@ -48,7 +48,11 @@ const tinycomments_reply = (req, done, fail) => { }) .then((req2) => { const commentUid = req2.commentUid; - done({ commentUid }); + done({ + commentUid: replyUid, + author: currentUser.id, + authorName: currentUser.fullName + }); }) .catch((e) => { fail(e); @@ -169,22 +173,57 @@ const tinycomments_lookup = ({ conversationUid }, done, fail) => { }); }; +const tinycomments_fetch = (conversationUids, done, fail) => { + const requests = conversationUids.map((uid) => fetch(`https://api.example/conversations/${uid}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }}) + .then((response) => response.json()) + .then((data) => ({ + [uid]: { + uid: uid, + comments: data + } + })) + ); + + Promise.all(requests) + .then((data) => { + console.log('data', data); + const conversations = data.reduce((conv, d) => ({ + ...conv, + ...d + }) + , {}); + console.log(`Fetch success ${conversationUids}`, conversations); + done({ conversations }); + }) + .catch((err) => { + console.error(`Fetch failure ${conversationUids}`, err); + fail('Fetching conversations failed'); + }); +}; + tinymce.init({ selector: 'textarea#comments-callback', height: 800, - plugins: 'code tinycomments help lists', + plugins: 'code tinycomments help lists quickbars link image', toolbar: - 'undo redo | blocks | ' + + 'addcomment showcomments | undo redo | blocks | ' + 'bold italic backcolor | alignleft aligncenter ' + 'alignright alignjustify | bullist numlist outdent indent | ' + - 'removeformat | addcomment showcomments | help', + 'removeformat | help', menubar: 'file edit view insert format tc', + sidebar_show: 'showcomments', menu: { tc: { title: 'Comments', items: 'addcomment showcomments deleteallconversations', }, }, + quickbars_selection_toolbar: 'alignleft aligncenter alignright | addcomment showcomments', + quickbars_image_toolbar: 'alignleft aligncenter alignright | rotateleft rotateright | imageoptions', tinycomments_create, tinycomments_reply, tinycomments_edit_comment, @@ -192,10 +231,5 @@ tinymce.init({ tinycomments_delete_all, tinycomments_delete_comment, tinycomments_lookup, - /* The following setup callback opens the comments sidebar when the editor loads */ - setup: (editor) => { - editor.on('SkinLoaded', () => { - editor.execCommand('ToggleSidebar', false, 'showcomments'); - }); - }, + tinycomments_fetch, }); diff --git a/modules/ROOT/examples/live-demos/comments-callback/index.html b/modules/ROOT/examples/live-demos/comments-callback/index.html index 06a2740b8a..92c933f6e6 100644 --- a/modules/ROOT/examples/live-demos/comments-callback/index.html +++ b/modules/ROOT/examples/live-demos/comments-callback/index.html @@ -7,7 +7,7 @@

Welcome to Tiny Comments!

  • Type your comment into the text field at the bottom of the Comment sidebar.
  • Click Comment.
  • -

    Your comment is then attached to the text, exactly like this!

    +

    Your comment is then attached to the text, exactly like this!

    If you want to take Tiny Comments for a test drive in your own environment, Tiny Comments is one of the premium plugins you can try for free for 14 days by signing up for a Tiny account. Make sure to check out our documentation as well.

    A simple table to play with

    diff --git a/modules/ROOT/examples/live-demos/comments-callback/index.js b/modules/ROOT/examples/live-demos/comments-callback/index.js index 5a5d2e8abd..c0b27fc248 100644 --- a/modules/ROOT/examples/live-demos/comments-callback/index.js +++ b/modules/ROOT/examples/live-demos/comments-callback/index.js @@ -46,8 +46,47 @@ tinymce.ScriptLoader.loadScripts( }; /* Our server "database" */ - const getDB = () => - JSON.parse(localStorage.getItem('fakedb') ?? '{}'); + const initialDB = { + "mce-conversation_19679600221621399703915": [ + { + uid: "mce-conversation_19679600221621399703915", + author: "Another Tiny User", + authorName: "Another Tiny User", + content: "Please revise this sentence, exclamation points are unprofessional!", + createdAt: "2021-05-19T04:48:23.914Z", + modifiedAt: "2021-05-19T04:48:23.914Z", + }, + { + uid: "mce-conversation_19679600221621399703917", + author: "Another Tiny User", + authorName: "Another Tiny User", + content: "Replied", + createdAt: "2021-05-19T04:48:23.914Z", + modifiedAt: "2021-05-19T04:48:23.914Z", + }, + { + uid: "mce-conversation_19679600221621399703918", + author: "Another Tiny User", + authorName: "Another Tiny User", + content: "Replied again", + createdAt: "2021-05-19T04:48:23.914Z", + modifiedAt: "2021-05-19T04:48:23.914Z", + }, + ], + "mce-conversation_420304606321716900864126": [ + { + uid: "mce-conversation_420304606321716900864126", + author: "john_smith", + authorName: "John Smith", + authorAvatar: "https://i.pravatar.cc/150?img=11", + content: "I think this is a great idea!", + createdAt: "2024-05-28T12:54:24.126Z", + modifiedAt: "2024-05-28T12:54:24.126Z", + }, + ], + }; + + const getDB = () => JSON.parse(localStorage.getItem('fakedb') ?? JSON.stringify(initialDB)); const setDB = (data) => { localStorage.setItem('fakedb', JSON.stringify(data)); }; @@ -621,17 +660,51 @@ tinymce.ScriptLoader.loadScripts( fail(err); }); }; + + const tinycomments_fetch = (conversationUids, done, fail) => { + const requests = conversationUids.map((uid) => fetch(`https://api.example/conversations/${uid}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }}) + .then((response) => response.json()) + .then((data) => ({ + [uid]: { + uid: uid, + comments: data + } + })) + ); + + Promise.all(requests) + .then((data) => { + console.log('data', data); + const conversations = data.reduce((conv, d) => ({ + ...conv, + ...d + }) + , {}); + console.log(`Fetch success ${conversationUids}`, conversations); + done({ conversations }); + }) + .catch((err) => { + console.error(`Fetch failure ${conversationUids}`, err); + fail('Fetching conversations failed'); + }); + }; tinymce.init({ selector: 'textarea#comments-callback', height: 800, - plugins: 'code tinycomments help lists', + plugins: 'code tinycomments help lists quickbars link image', toolbar: - 'undo redo | blocks | ' + + 'addcomment showcomments | undo redo | blocks | ' + 'bold italic backcolor | alignleft aligncenter ' + 'alignright alignjustify | bullist numlist outdent indent | ' + - 'removeformat | addcomment showcomments | help', + 'removeformat | help', menubar: 'file edit view insert format tc', + quickbars_selection_toolbar: 'alignleft aligncenter alignright | addcomment showcomments', + quickbars_image_toolbar: 'alignleft aligncenter alignright | rotateleft rotateright | imageoptions', menu: { tc: { title: 'Comments', @@ -645,13 +718,7 @@ tinymce.ScriptLoader.loadScripts( tinycomments_delete_all, tinycomments_delete_comment, tinycomments_lookup, - /* The following setup callback opens the comments sidebar when the editor loads */ - setup: (editor) => { - editor.on('SkinLoaded', () => { - editor.execCommand('ToggleSidebar', false, 'showcomments', { - skip_focus: true, - }); - }); - }, + tinycomments_fetch, + sidebar_show: 'showcomments', }); }); diff --git a/modules/ROOT/examples/live-demos/comments-embedded-with-mentions/index.html b/modules/ROOT/examples/live-demos/comments-embedded-with-mentions/index.html new file mode 100644 index 0000000000..4f012193f1 --- /dev/null +++ b/modules/ROOT/examples/live-demos/comments-embedded-with-mentions/index.html @@ -0,0 +1,35 @@ +
    + +
    \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/comments-embedded-with-mentions/index.js b/modules/ROOT/examples/live-demos/comments-embedded-with-mentions/index.js new file mode 100644 index 0000000000..c2639167f7 --- /dev/null +++ b/modules/ROOT/examples/live-demos/comments-embedded-with-mentions/index.js @@ -0,0 +1,163 @@ +import ('https://cdn.jsdelivr.net/npm/@faker-js/faker@9/dist/index.min.js').then(({ faker }) => { + const adminUser = { + id: 'johnsmith', + name: 'John Smith', + fullName: 'John Smith', + description: 'Company Founder', + image: "https://i.pravatar.cc/150?img=11" + }; + + const currentUser = { + id: 'jennynichols', + name: 'Jenny Nichols', + fullName: 'Jenny Nichols', + description: 'Marketing Director', + image: "https://i.pravatar.cc/150?img=10" + }; + + const fakeDelay = 500; + const numberOfUsers = 200; + + /* These are "local" caches of the data returned from the fake server */ + let fetchedUsers = false; + let usersRequest; // Promise + const userRequest = {}; + + const setupFakeServer = () => { + const images = [ adminUser.image, currentUser.image ]; + const userNames = [ adminUser.fullName, currentUser.fullName ]; + + for (let i = 0; i < numberOfUsers; i++) { + images.push(faker.image.avatar()); + userNames.push(`${faker.person.firstName()} ${faker.person.lastName()}`); + } + + /* This represents a database of users on the server */ + const userDb = { + [adminUser.id]: adminUser, + [currentUser.id]: currentUser + }; + userNames.map((fullName) => { + if ((fullName !== currentUser.fullName) && (fullName !== adminUser.fullName)) { + const id = fullName.toLowerCase().replace(/ /g, ''); + userDb[id] = { + id, + name: fullName, + fullName, + description: faker.person.jobTitle(), + image: images[Math.floor(images.length * Math.random())] + }; + } + }); + + /* This represents getting the complete list of users from the server with the details required for the mentions "profile" item */ + const fetchUsers = () => new Promise((resolve) => { + /* simulate a server delay */ + setTimeout(() => { + const users = Object.keys(userDb).map((id) => ({ + id, + name: userDb[id].name, + image: userDb[id].image, + description: userDb[id].description + })); + resolve(users); + }, fakeDelay); + }); + + const fetchUser = (id) => new Promise((resolve, reject) => { + /* simulate a server delay */ + setTimeout(() => { + if (Object.prototype.hasOwnProperty.call(userDb, id)) { + resolve(userDb[id]); + } + reject('unknown user id "' + id + '"'); + }, fakeDelay); + }); + + return { + fetchUsers, + fetchUser + }; + }; + + const fakeServer = setupFakeServer(); + + const mentions_fetch = (query, success) => { + if (!fetchedUsers) { + fetchedUsers = true; + usersRequest = fakeServer.fetchUsers(); + } + usersRequest.then((users) => { + const userMatch = (name) => name.toLowerCase().indexOf(query.term.toLowerCase()) !== -1; + success(users.filter((user) => userMatch(user.name) || userMatch(user.id))); + fetchedUsers = false; + }); + }; + + const mentions_menu_hover = (userInfo, success) => { + if (!userRequest[userInfo.id]) { + userRequest[userInfo.id] = fakeServer.fetchUser(userInfo.id); + } + userRequest[userInfo.id].then((userDetail) => { + success({ type: 'profile', user: userDetail }); + }); + }; + + const mentions_menu_complete = (editor, userInfo) => { + const span = editor.getDoc().createElement('span'); + span.className = 'mymention'; + span.setAttribute('style', 'color: #37F;'); + span.setAttribute('data-mention-id', userInfo.id); + span.appendChild(editor.getDoc().createTextNode('@' + userInfo.name)); + return span; + }; + + const mentions_select = (mention, success) => { + const id = mention.getAttribute('data-mention-id'); + if (id) { + userRequest[id] = fakeServer.fetchUser(id); + userRequest[id].then((userDetail) => { + success({ type: 'profile', user: userDetail }); + }); + } + }; + + const tinycomments_can_resolve = (req, done, _fail) => { + const allowed = req.comments.length > 0 && req.comments[0].author === author; + done({ + canResolve: allowed + }); + }; + + tinymce.init({ + selector: 'textarea#comments-embedded', + license_key: 'gpl', + toolbar: 'addcomment showcomments code | bold italic underline', + menubar: 'file edit view insert format tools tc help', + menu: { + tc: { + title: 'TinyComments', + items: 'addcomment showcomments deleteallconversations' + } + }, + plugins: [ 'tinycomments', 'mentions', 'help', 'code', 'quickbars', 'link', 'lists', 'image' ], + quickbars_selection_toolbar: 'alignleft aligncenter alignright | addcomment showcomments', + quickbars_image_toolbar: 'alignleft aligncenter alignright | rotateleft rotateright | imageoptions', + tinycomments_mentions_enabled: true, + + mentions_item_type: 'profile', + mentions_min_chars: 0, + mentions_selector: '.mymention', + mentions_fetch, + mentions_menu_hover, + mentions_menu_complete, + mentions_select, + + tinycomments_mode: 'embedded', + sidebar_show: 'showcomments', + tinycomments_author: currentUser.id, + tinycomments_author_name: currentUser.fullName, + tinycomments_avatar: currentUser.image, + tinycomments_can_resolve, + }); +}); diff --git a/modules/ROOT/examples/live-demos/comments-embedded/index.js b/modules/ROOT/examples/live-demos/comments-embedded/index.js index 13517fd03f..d0aa9d9c21 100644 --- a/modules/ROOT/examples/live-demos/comments-embedded/index.js +++ b/modules/ROOT/examples/live-demos/comments-embedded/index.js @@ -3,8 +3,8 @@ const userAllowedToResolve = 'Admin1'; tinymce.init({ selector: 'textarea#comments-embedded', - plugins: 'code tinycomments', - toolbar: 'bold italic underline | addcomment showcomments', + plugins: 'code tinycomments quickbars link lists image', + toolbar: 'addcomment showcomments | bold italic underline', menubar: 'file edit view insert format tools tc', menu: { tc: { @@ -12,7 +12,10 @@ tinymce.init({ items: 'addcomment showcomments deleteallconversations' } }, + quickbars_selection_toolbar: 'alignleft aligncenter alignright | addcomment showcomments', + quickbars_image_toolbar: 'alignleft aligncenter alignright | rotateleft rotateright | imageoptions', tinycomments_mode: 'embedded', + sidebar_show: 'showcomments', tinycomments_author: currentAuthor, tinycomments_can_resolve: (req, done, fail) => { const allowed = req.comments.length > 0 && @@ -22,10 +25,4 @@ tinymce.init({ }); }, content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', - /* The following setup callback opens the comments sidebar when the editor loads */ - setup: (editor) => { - editor.on('SkinLoaded', () => { - editor.execCommand('ToggleSidebar', false, 'showcomments', { skip_focus: true }); - }); - } }); diff --git a/modules/ROOT/examples/live-demos/comments-readonly-mode/index.html b/modules/ROOT/examples/live-demos/comments-readonly-mode/index.html new file mode 100644 index 0000000000..fe676301b3 --- /dev/null +++ b/modules/ROOT/examples/live-demos/comments-readonly-mode/index.html @@ -0,0 +1,36 @@ +
    + +
    \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/comments-readonly-mode/index.js b/modules/ROOT/examples/live-demos/comments-readonly-mode/index.js new file mode 100644 index 0000000000..9e366a42b1 --- /dev/null +++ b/modules/ROOT/examples/live-demos/comments-readonly-mode/index.js @@ -0,0 +1,29 @@ +tinymce.init({ + selector: "textarea#comment-readonly-ui-mode", + plugins: [ + "tinycomments", "advlist", "anchor", "autolink", "charmap", "code", "fullscreen", + "help", "image", "insertdatetime", "link", "lists", "media", + "preview", "searchreplace", "table", "visualblocks", "quickbars", + ], + toolbar: "addcomment showcomments togglereadonly | undo redo | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image", + quickbars_selection_toolbar: 'alignleft aligncenter alignright | addcomment showcomments', + quickbars_image_toolbar: 'alignleft aligncenter alignright | rotateleft rotateright | imageoptions', + tinycomments_mode: 'embedded', + sidebar_show: 'showcomments', + readonly: true, + setup: (editor) => { + const isReadonlyMode = () => editor.mode.get() === 'readonly'; + editor.ui.registry.addToggleButton('togglereadonly', { + text: 'Readonly mode', + context: 'any', // Available from 7.4 + onSetup: (buttonApi) => { + const activate = (api) => () => api.setActive(isReadonlyMode()); + editor.on('SwitchMode', activate(buttonApi)); + return (teardownApi) => editor.off('SwitchMode', activate(teardownApi)); + }, + onAction: (api) => { + editor.mode.set(isReadonlyMode() ? 'design' : 'readonly'); + } + }); + } +}); \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/comments-ui-mode/index.html b/modules/ROOT/examples/live-demos/comments-ui-mode/index.html new file mode 100644 index 0000000000..4c34ab043b --- /dev/null +++ b/modules/ROOT/examples/live-demos/comments-ui-mode/index.html @@ -0,0 +1,38 @@ +
    + +
    \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/comments-ui-mode/index.js b/modules/ROOT/examples/live-demos/comments-ui-mode/index.js new file mode 100644 index 0000000000..2b4ebb3852 --- /dev/null +++ b/modules/ROOT/examples/live-demos/comments-ui-mode/index.js @@ -0,0 +1,14 @@ +tinymce.init({ + selector: "textarea#comments-ui-mode", + plugins: [ + "tinycomments", "advlist", "anchor", "autolink", "charmap", "code", "fullscreen", + "help", "image", "insertdatetime", "link", "lists", "media", + "preview", "searchreplace", "table", "visualblocks", "quickbars", 'quickbars', 'image', + ], + toolbar: "addcomment showcomments | undo redo | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image", + quickbars_selection_toolbar: 'alignleft aligncenter alignright | addcomment showcomments', + quickbars_image_toolbar: 'alignleft aligncenter alignright | rotateleft rotateright | imageoptions', + tinycomments_mode: 'embedded', + tinycomments_access: 'comment', + sidebar_show: 'showcomments' +}); \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/context-form/index.js b/modules/ROOT/examples/live-demos/context-form/index.js index 44016f88e6..bd0ff9db0a 100644 --- a/modules/ROOT/examples/live-demos/context-form/index.js +++ b/modules/ROOT/examples/live-demos/context-form/index.js @@ -18,6 +18,7 @@ tinymce.init({ }, label: 'Link', predicate: isAnchorElement, + placeholder: 'https://www.example.com', initValue: () => { const elm = getAnchorElement(); return !!elm ? elm.href : ''; diff --git a/modules/ROOT/examples/live-demos/context-toolbar-labels/index.html b/modules/ROOT/examples/live-demos/context-toolbar-labels/index.html new file mode 100644 index 0000000000..172316e060 --- /dev/null +++ b/modules/ROOT/examples/live-demos/context-toolbar-labels/index.html @@ -0,0 +1,9 @@ + diff --git a/modules/ROOT/examples/live-demos/context-toolbar-labels/index.js b/modules/ROOT/examples/live-demos/context-toolbar-labels/index.js new file mode 100644 index 0000000000..7c0d94b2dc --- /dev/null +++ b/modules/ROOT/examples/live-demos/context-toolbar-labels/index.js @@ -0,0 +1,34 @@ +tinymce.init({ + selector: 'textarea#context-toolbar-labels', + height: 350, + setup: (editor) => { + editor.ui.registry.addContextToolbar('imagealignment', { + predicate: (node) => node.nodeName.toLowerCase() === 'img', + position: 'node', + scope: 'node', + items: [ + { + name: 'Formatting', + items: ['alignleft', 'aligncenter', 'alignright'] + }, + { + label: 'Copy', + items: ['copy', 'paste'] + } + ], + }); + + editor.ui.registry.addContextToolbar('textselection', { + predicate: (node) => !editor.selection.isCollapsed(), + position: 'selection', + scope: 'node', + items: [ + { + name: 'Format', + items: ['bold', 'italic', 'underline'] + }, + ], + }); + }, + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }' +}); diff --git a/modules/ROOT/examples/live-demos/exportpdf/index.html b/modules/ROOT/examples/live-demos/exportpdf/index.html new file mode 100644 index 0000000000..6dd3537e02 --- /dev/null +++ b/modules/ROOT/examples/live-demos/exportpdf/index.html @@ -0,0 +1,78 @@ + \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/exportpdf/index.js b/modules/ROOT/examples/live-demos/exportpdf/index.js new file mode 100644 index 0000000000..04bec75035 --- /dev/null +++ b/modules/ROOT/examples/live-demos/exportpdf/index.js @@ -0,0 +1,18 @@ +tinymce.init({ + selector: 'textarea#exportpdf', + height: '800px', + plugins: [ + "exportpdf", "advlist", "anchor", "autolink", "charmap", "code", "codesample", "fullscreen", + "help", "image", "insertdatetime", "link", "lists", "media", + "preview", "searchreplace", "table", "visualblocks", + ], + toolbar: "undo redo | exportpdf | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image", + image_caption: true, + exportpdf_converter_options: { + format: 'A4', + margin_top: '1in', + margin_right: '1in', + margin_bottom: '1in', + margin_left: '1in' + } +}); diff --git a/modules/ROOT/examples/live-demos/exportword/index.html b/modules/ROOT/examples/live-demos/exportword/index.html new file mode 100644 index 0000000000..91179d470c --- /dev/null +++ b/modules/ROOT/examples/live-demos/exportword/index.html @@ -0,0 +1,78 @@ + diff --git a/modules/ROOT/examples/live-demos/exportword/index.js b/modules/ROOT/examples/live-demos/exportword/index.js new file mode 100644 index 0000000000..c2dac8038c --- /dev/null +++ b/modules/ROOT/examples/live-demos/exportword/index.js @@ -0,0 +1,21 @@ +tinymce.init({ + selector: 'textarea#exportword', + height: '800px', + plugins: [ + "exportword", "advlist", "anchor", "autolink", "charmap", "code", "fullscreen", + "help", "image", "insertdatetime", "link", "lists", "media", + "preview", "searchreplace", "table", "visualblocks", + ], + toolbar: "undo redo | exportword | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image", + exportword_converter_options: { + document: { + size: 'A4', + margins: { + top: "1in", + bottom: "1in", + left: "1in", + right: "1in" + } + } + } +}); diff --git a/modules/ROOT/examples/live-demos/full-featured/example.js b/modules/ROOT/examples/live-demos/full-featured/example.js index 937f239e70..109bcccdbe 100644 --- a/modules/ROOT/examples/live-demos/full-featured/example.js +++ b/modules/ROOT/examples/live-demos/full-featured/example.js @@ -1,15 +1,23 @@ +const fetchApi = import( + "https://unpkg.com/@microsoft/fetch-event-source@2.0.1/lib/esm/index.js" +).then((module) => module.fetchEventSource); + +// This example stores the OpenAI API key in the client side integration. This is not recommended for any purpose. +// Instead, an alternate method for retrieving the API key should be used. +const openai_api_key = ""; + const useDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches; const isSmallScreen = window.matchMedia('(max-width: 1023.5px)').matches; tinymce.init({ selector: 'textarea#full-featured', - plugins: 'preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link 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 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: 'preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link 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 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: { @@ -18,7 +26,7 @@ tinymce.init({ } }, menubar: 'file edit view insert format tools table tc help', - toolbar: "undo redo | revisionhistory | aidialog aishortcuts | blocks fontsizeinput | bold italic | align numlist bullist | link image | table 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 | 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}-', @@ -105,17 +113,6 @@ tinymce.init({ a11y_advanced_options: true, skin: useDarkMode ? 'oxide-dark' : 'oxide', content_css: useDarkMode ? 'dark' : 'default', - /* - The following settings require more configuration than shown here. - For information on configuring the mentions plugin, see: - https://www.tiny.cloud/docs/tinymce/6/mentions/. - */ - mentions_selector: '.mymention', - mentions_fetch: mentions_fetch, // TODO: Implement mentions_fetch - mentions_menu_hover: mentions_menu_hover, // TODO: Implement mentions_menu_hover - mentions_menu_complete: mentions_menu_complete, // TODO: Implement mentions_menu_complete - mentions_select: mentions_select, // TODO: Implement mentions_select - mentions_item_type: 'profile', autocorrect_capitalize: true, mergetags_list: [ { @@ -149,13 +146,300 @@ tinymce.init({ title: 'Salutation' } ], - revisionhistory_fetch: () => { // Implement the fetch function for the revision history plugin + // For revision history plugin + revisionhistory_fetch: () => { return Promise.resolve([ { - revisionId: '1', + revisionId: '3', createdAt: '2023-11-24T22:26:21.578Z', - content: '

    Initial content

    ' + author: { + id: 'husky', + name: 'A Tiny Husky', + avatar: '{{imagesdir}}/tiny-husky.jpg' + }, + content: ` +

    TinyMCE Logo

    +

    Welcome to the TinyMCE editor demo!

    +

    A simple table to play with

    +
    + + + + + + + + + + + + + + + + + + + +
    ProductCostReally?
    TinyMCEFreeYES!
    PluploadFreeYES!
    +

    Found a bug?

    +

    If you think you have found a bug please create an issue on the GitHub repo to report it to the developers.

    +

    Finally ...

    +

    Don't forget to check out our other product Plupload, your ultimate upload solution featuring HTML5 upload support.

    +

    Thanks for supporting TinyMCE! We hope it helps you and your users create great content.
    All the best from the TinyMCE team.

    + `, + }, + { + revisionId: '2', + createdAt: '2023-11-25T08:30:21.578Z', + author: { + id: 'tiny.user', + name: 'A Tiny User', + avatar: '{{imagesdir}}/logos/android-chrome-192x192.png' + }, + content: ` +

    TinyMCE Logo

    +

    Welcome to the TinyMCE editor demo!

    +

    Got questions or need help?

    +
      +
    1. Our documentation is a great resource for learning how to configure TinyMCE.
    2. +
    3. Have a specific question? Try the tinymce tag at Stack Overflow.
    4. +
    5. We also offer enterprise grade support as part of TinyMCE premium plans.
    6. +
    +

    A simple table to play with

    + + + + + + + + + + + + + + + + + + + + +
    ProductCostReally?
    TinyMCEFreeYES!
    PluploadFreeYES!
    +

    Found a bug?

    +

    If you think you have found a bug please create an issue on the GitHub repo to report it to the developers.

    +

    Finally ...

    +

    Don't forget to check out our other product Plupload, your ultimate upload solution featuring HTML5 upload support.

    +

    Thanks for supporting TinyMCE! We hope it helps you and your users create great content.
    All the best from the TinyMCE team.

    + `, + }, + { + revisionId: '1', + createdAt: '2023-11-29T10:11:21.578Z', + author: { + id: 'tiny.user', + name: 'A Tiny User', + avatar: '{{imagesdir}}/logos/android-chrome-192x192.png' + }, + content: ` +

    TinyMCE Logo

    +

    Welcome to the TinyMCE editor demo!

    +

    Got questions or need help?

    + +

    A simple table to play with

    + + + + + + + + + + + + + + + + + + + + +
    ProductCostReally?
    TinyMCEFreeYES!
    PluploadFreeYES!
    +

    Found a bug?

    +

    If you think you have found a bug please create an issue on the GitHub repo to report it to the developers.

    +

    Finally ...

    +

    Don't forget to check out our other product Plupload, your ultimate upload solution featuring HTML5 upload support.

    +

    Thanks for supporting TinyMCE! We hope it helps you and your users create great content.
    All the best from the TinyMCE team.

    + `, }, ]); - } + }, + ai_request: (request, respondWith) => { + respondWith.stream((signal, streamMessage) => { + // Adds each previous query and response as individual messages + const conversation = request.thread.flatMap((event) => { + if (event.response) { + return [ + { role: "user", content: event.request.query }, + { role: "assistant", content: event.response.data }, + ]; + } else { + return []; + } + }); + + // System messages provided by the plugin to format the output as HTML content. + const systemMessages = request.system.map((content) => ({ + role: "system", + content, + })); + + // Forms the new query sent to the API + const content = + request.context.length === 0 || conversation.length > 0 + ? request.query + : `Question: ${request.query} Context: """${request.context}"""`; + + const messages = [ + ...conversation, + ...systemMessages, + { role: "user", content }, + ]; + + let hasHead = false; + let markdownHead = ""; + + const hasMarkdown = (message) => { + if (message.includes("`") && markdownHead !== "```") { + const numBackticks = message.split("`").length - 1; + markdownHead += "`".repeat(numBackticks); + if (hasHead && markdownHead === "```") { + markdownHead = ""; + hasHead = false; + } + return true; + } else if (message.includes("html") && markdownHead === "```") { + markdownHead = ""; + hasHead = true; + return true; + } + return false; + }; + + const requestBody = { + model: "gpt-4o", + temperature: 0.7, + max_tokens: 4000, + messages, + stream: true, + }; + + const openAiOptions = { + signal, + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${openai_api_key}`, + }, + body: JSON.stringify(requestBody), + }; + + const onopen = async (response) => { + if (response) { + const contentType = response.headers.get("content-type"); + if (response.ok && contentType?.includes("text/event-stream")) { + return; + } else if (contentType?.includes("application/json")) { + const data = await response.json(); + if (data.error) { + throw new Error(`${data.error.type}: ${data.error.message}`); + } + } + } else { + throw new Error("Failed to communicate with the ChatGPT API"); + } + }; + + // This function passes each new message into the plugin via the `streamMessage` callback. + const onmessage = (ev) => { + const data = ev.data; + if (data !== "[DONE]") { + const parsedData = JSON.parse(data); + const firstChoice = parsedData?.choices[0]; + const message = firstChoice?.delta?.content; + if (message && message !== "") { + if (!hasMarkdown(message)) { + streamMessage(message); + } + } + } + }; + + const onerror = (error) => { + // Stop operation and do not retry by the fetch-event-source + throw error; + }; + + // Use microsoft's fetch-event-source library to work around the 2000 character limit + // of the browser `EventSource` API, which requires query strings + return fetchApi + .then((fetchEventSource) => + fetchEventSource("https://api.openai.com/v1/chat/completions", { + ...openAiOptions, + openWhenHidden: true, + onopen, + onmessage, + onerror, + }) + ) + .then(async (response) => { + if (response && !response.ok) { + const data = await response.json(); + if (data.error) { + throw new Error(`${data.error.type}: ${data.error.message}`); + } + } + }) + .catch(onerror); + }); + }, + exportpdf_converter_options: { + 'format': 'Letter', + 'margin_top': '1in', + 'margin_right': '1in', + 'margin_bottom': '1in', + 'margin_left': '1in' + }, + exportword_converter_options: { + 'document': { + 'size': 'Letter' + } + }, + importword_converter_options: { + 'formatting': { + 'styles': 'inline', + 'resets': 'inline', + 'defaults': 'inline', + } + }, + /* + The following settings require more configuration than shown here. + For information on configuring the mentions plugin, see: + https://www.tiny.cloud/docs/tinymce/latest/mentions/. + */ + mentions_selector: ".mymention", + mentions_fetch: mentions_fetch, // TODO: Implement mentions_fetch + mentions_menu_hover: mentions_menu_hover, // TODO: Implement mentions_menu_hover + mentions_menu_complete: mentions_menu_complete, // TODO: Implement mentions_menu_complete + mentions_select: mentions_select, // TODO: Implement mentions_select + mentions_item_type: "profile", }); diff --git a/modules/ROOT/examples/live-demos/full-featured/index.html b/modules/ROOT/examples/live-demos/full-featured/index.html index 392d932bdc..a35479e914 100644 --- a/modules/ROOT/examples/live-demos/full-featured/index.html +++ b/modules/ROOT/examples/live-demos/full-featured/index.html @@ -54,6 +54,20 @@

    Character strings to demonstrate some of the Advanced Typography plugin’s
  • 30C is 86F
  • +

    🤖 Try out AI Assistant!

    + +

    Below are just a few of the ways you can use AI Assistant within your app. Since you can define your own custom prompts, the sky really is the limit!

    +

     🎭 Changing tone  Lighten up the sentence below by selecting the text, clicking , and choosing Change tone > Friendly.

    +
    +

    The 3Q23 financial results followed a predictable trend, reflecting the status quo from previous years.

    +
    +

    📝 Summarizing – Below is a long paragraph that people may not want to read from start to finish. Get a quick summary by selecting the text, clicking , and choosing Summarize content.

    +
    +

    Population growth in the 17th century was marked by significant increment in the number of people around the world. Various factors contributed to this demographic trend. Firstly, advancements in agriculture and technology resulted in increased food production and improved living conditions. This led to decreased mortality rates and better overall health, allowing for more individuals to survive and thrive. Additionally, the exploration and expansion of European powers, such as colonization efforts, fostered migration and settlement in new territories.

    +
    +

    💡 Writing from scratch – Ask AI Assistant to generate content from scratch by clicking , and typing Write a marketing email announcing TinyMCE's new AI Assistant plugin.

    +

     

    +

    Note on the included Templates demonstration

    The included Templates demonstration uses the advtemplate_list configuration option to return a local promise containing a basic Template structure with self-contained examples.

    diff --git a/modules/ROOT/examples/live-demos/full-featured/index.js b/modules/ROOT/examples/live-demos/full-featured/index.js index c61b6a307a..3ceb31f729 100644 --- a/modules/ROOT/examples/live-demos/full-featured/index.js +++ b/modules/ROOT/examples/live-demos/full-featured/index.js @@ -1,3 +1,7 @@ +const fetchApi = import( + "https://unpkg.com/@microsoft/fetch-event-source@2.0.1/lib/esm/index.js" +).then((module) => module.fetchEventSource); + /* Script to import faker.js for generating random data for demonstration purposes */ tinymce.ScriptLoader.loadScripts(['https://cdn.jsdelivr.net/npm/faker@5/dist/faker.min.js']).then(() => { @@ -140,137 +144,277 @@ tinymce.ScriptLoader.loadScripts(['https://cdn.jsdelivr.net/npm/faker@5/dist/fak const useDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches; const isSmallScreen = window.matchMedia('(max-width: 1023.5px)').matches; - // revisionhistory_fetch + const ai_request = (request, respondWith) => { + respondWith.stream((signal, streamMessage) => { + // Adds each previous query and response as individual messages + const conversation = request.thread.flatMap((event) => { + if (event.response) { + return [ + { role: "user", content: event.request.query }, + { role: "assistant", content: event.response.data }, + ]; + } else { + return []; + } + }); + + // System messages provided by the plugin to format the output as HTML content. + const systemMessages = request.system.map((content) => ({ + role: "system", + content, + })); + + // Forms the new query sent to the API + const content = + request.context.length === 0 || conversation.length > 0 + ? request.query + : `Question: ${request.query} Context: """${request.context}"""`; + + const messages = [ + ...conversation, + ...systemMessages, + { role: "user", content }, + ]; + + let hasHead = false; + let markdownHead = ""; + + const hasMarkdown = (message) => { + if (message.includes("`") && markdownHead !== "```") { + const numBackticks = message.split("`").length - 1; + markdownHead += "`".repeat(numBackticks); + if (hasHead && markdownHead === "```") { + markdownHead = ""; + hasHead = false; + } + return true; + } else if (message.includes("html") && markdownHead === "```") { + markdownHead = ""; + hasHead = true; + return true; + } + return false; + }; + + const requestBody = { + model: "gpt-4o", + temperature: 0.7, + max_tokens: 4000, + messages, + stream: true, + }; + + const openAiOptions = { + signal, + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer {{ openai_proxy_token }}`, + }, + body: JSON.stringify(requestBody), + }; + + const onopen = async (response) => { + if (response) { + const contentType = response.headers.get("content-type"); + if (response.ok && contentType?.includes("text/event-stream")) { + return; + } else if (contentType?.includes("application/json")) { + const data = await response.json(); + if (data.error) { + throw new Error(`${data.error.type}: ${data.error.message}`); + } + } + } else { + throw new Error("Failed to communicate with the ChatGPT API"); + } + }; + + // This function passes each new message into the plugin via the `streamMessage` callback. + const onmessage = (ev) => { + const data = ev.data; + if (data !== "[DONE]") { + const parsedData = JSON.parse(data); + const firstChoice = parsedData?.choices[0]; + const message = firstChoice?.delta?.content; + if (message && message !== "") { + if (!hasMarkdown(message)) { + streamMessage(message); + } + } + } + }; + + const onerror = (error) => { + // Stop operation and do not retry by the fetch-event-source + throw error; + }; + + // Use microsoft's fetch-event-source library to work around the 2000 character limit + // of the browser `EventSource` API, which requires query strings + return fetchApi + .then((fetchEventSource) => + fetchEventSource("{{ openai_proxy_url }}", { + ...openAiOptions, + openWhenHidden: true, + onopen, + onmessage, + onerror, + }) + ) + .then(async (response) => { + if (response && !response.ok) { + const data = await response.json(); + if (data.error) { + throw new Error(`${data.error.type}: ${data.error.message}`); + } + } + }) + .catch(onerror); + }); + }; + + // Fetch revisions const fetchRevisions = () => { - return new Promise((resolve, _reject) => { - /* Simulate fetching revisions from a server */ - setTimeout(() => { - resolve([ - { - revisionId: '3', - createdAt: '2023-11-24T22:26:21.578Z', - content: ` -

    TinyMCE Logo

    -

    Welcome to the TinyMCE editor demo!

    -

    A simple table to play with

    - - - - - - - - - - - - - - - - - - - - -
    ProductCostReally?
    TinyMCEFreeYES!
    PluploadFreeYES!
    -

    Found a bug?

    -

    If you think you have found a bug please create an issue on the GitHub repo to report it to the developers.

    -

    Finally ...

    -

    Don't forget to check out our other product Plupload, your ultimate upload solution featuring HTML5 upload support.

    -

    Thanks for supporting TinyMCE! We hope it helps you and your users create great content.
    All the best from the TinyMCE team.

    - `, + return Promise.resolve([ + { + revisionId: '3', + createdAt: '2023-11-24T22:26:21.578Z', + author: { + id: 'husky', + name: 'A Tiny Husky', + avatar: '{{imagesdir}}/tiny-husky.jpg' }, - { - revisionId: '2', - createdAt: '2023-11-25T08:30:21.578Z', - content: ` -

    TinyMCE Logo

    -

    Welcome to the TinyMCE editor demo!

    -

    Got questions or need help?

    -
      -
    1. Our documentation is a great resource for learning how to configure TinyMCE.
    2. -
    3. Have a specific question? Try the tinymce tag at Stack Overflow.
    4. -
    5. We also offer enterprise grade support as part of TinyMCE premium plans.
    6. -
    -

    A simple table to play with

    - - - - - - - - - - - - - - - - - - - - -
    ProductCostReally?
    TinyMCEFreeYES!
    PluploadFreeYES!
    -

    Found a bug?

    -

    If you think you have found a bug please create an issue on the GitHub repo to report it to the developers.

    -

    Finally ...

    -

    Don't forget to check out our other product Plupload, your ultimate upload solution featuring HTML5 upload support.

    -

    Thanks for supporting TinyMCE! We hope it helps you and your users create great content.
    All the best from the TinyMCE team.

    - `, + content: ` +

    TinyMCE Logo

    +

    Welcome to the TinyMCE editor demo!

    +

    A simple table to play with

    + + + + + + + + + + + + + + + + + + + + +
    ProductCostReally?
    TinyMCEFreeYES!
    PluploadFreeYES!
    +

    Found a bug?

    +

    If you think you have found a bug please create an issue on the GitHub repo to report it to the developers.

    +

    Finally ...

    +

    Don't forget to check out our other product Plupload, your ultimate upload solution featuring HTML5 upload support.

    +

    Thanks for supporting TinyMCE! We hope it helps you and your users create great content.
    All the best from the TinyMCE team.

    + `, + }, + { + revisionId: '2', + createdAt: '2023-11-25T08:30:21.578Z', + author: { + id: 'tiny.user', + name: 'A Tiny User', + avatar: '{{imagesdir}}/logos/android-chrome-192x192.png' }, - { - revisionId: '1', - createdAt: '2023-11-29T10:11:21.578Z', - content: ` -

    TinyMCE Logo

    -

    Welcome to the TinyMCE editor demo!

    -

    Got questions or need help?

    - -

    A simple table to play with

    - - - - - - - - - - - - - - - - - - - - -
    ProductCostReally?
    TinyMCEFreeYES!
    PluploadFreeYES!
    -

    Found a bug?

    -

    If you think you have found a bug please create an issue on the GitHub repo to report it to the developers.

    -

    Finally ...

    -

    Don't forget to check out our other product Plupload, your ultimate upload solution featuring HTML5 upload support.

    -

    Thanks for supporting TinyMCE! We hope it helps you and your users create great content.
    All the best from the TinyMCE team.

    - `, + content: ` +

    TinyMCE Logo

    +

    Welcome to the TinyMCE editor demo!

    +

    Got questions or need help?

    +
      +
    1. Our documentation is a great resource for learning how to configure TinyMCE.
    2. +
    3. Have a specific question? Try the tinymce tag at Stack Overflow.
    4. +
    5. We also offer enterprise grade support as part of TinyMCE premium plans.
    6. +
    +

    A simple table to play with

    + + + + + + + + + + + + + + + + + + + + +
    ProductCostReally?
    TinyMCEFreeYES!
    PluploadFreeYES!
    +

    Found a bug?

    +

    If you think you have found a bug please create an issue on the GitHub repo to report it to the developers.

    +

    Finally ...

    +

    Don't forget to check out our other product Plupload, your ultimate upload solution featuring HTML5 upload support.

    +

    Thanks for supporting TinyMCE! We hope it helps you and your users create great content.
    All the best from the TinyMCE team.

    + `, + }, + { + revisionId: '1', + createdAt: '2023-11-29T10:11:21.578Z', + author: { + id: 'tiny.user', + name: 'A Tiny User', + avatar: '{{imagesdir}}/logos/android-chrome-192x192.png' }, - ]); - }, 500); - }); + content: ` +

    TinyMCE Logo

    +

    Welcome to the TinyMCE editor demo!

    +

    Got questions or need help?

    + +

    A simple table to play with

    + + + + + + + + + + + + + + + + + + + + +
    ProductCostReally?
    TinyMCEFreeYES!
    PluploadFreeYES!
    +

    Found a bug?

    +

    If you think you have found a bug please create an issue on the GitHub repo to report it to the developers.

    +

    Finally ...

    +

    Don't forget to check out our other product Plupload, your ultimate upload solution featuring HTML5 upload support.

    +

    Thanks for supporting TinyMCE! We hope it helps you and your users create great content.
    All the best from the TinyMCE team.

    + `, + }, + ]); }; tinymce.init({ selector: 'textarea#full-featured', - plugins: 'preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link 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: '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', editimage_cors_hosts: ['picsum.photos'], tinydrive_token_provider: (success, failure) => { success({ token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJqb2huZG9lIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.Ks_BdfH4CWilyzLNk8S2gDARFhuxIauLa8PwhdEQhEo' }); @@ -280,7 +424,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: 'preview powerpaste casechange importcss tinydrive searchreplace autolink autosave save directionality advcode visualblocks visualchars fullscreen image link 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 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: { @@ -289,7 +433,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 | revisionhistory | aidialog aishortcuts | blocks fontsizeinput | bold italic | align numlist bullist | link image | table 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 | 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}-', @@ -420,6 +564,31 @@ tinymce.ScriptLoader.loadScripts(['https://cdn.jsdelivr.net/npm/faker@5/dist/fak title: 'Salutation' } ], + ai_request, + exportpdf_converter_options: { + 'format': 'Letter', + 'margin_top': '1in', + 'margin_right': '1in', + 'margin_bottom': '1in', + 'margin_left': '1in' + }, + exportword_converter_options: { + 'document': { + 'size': 'Letter' + } + }, + importword_converter_options: { + 'formatting': { + 'styles': 'inline', + 'resets': 'inline', + 'defaults': 'inline', + } + }, revisionhistory_fetch: fetchRevisions, + revisionhistory_author: { + id: 'john.doe', + name: 'John Doe' + }, + revisionhistory_display_author: true, }); }); diff --git a/modules/ROOT/examples/live-demos/importword/index.html b/modules/ROOT/examples/live-demos/importword/index.html new file mode 100644 index 0000000000..1c6fd82ae6 --- /dev/null +++ b/modules/ROOT/examples/live-demos/importword/index.html @@ -0,0 +1,9 @@ + diff --git a/modules/ROOT/examples/live-demos/importword/index.js b/modules/ROOT/examples/live-demos/importword/index.js new file mode 100644 index 0000000000..cf520309b4 --- /dev/null +++ b/modules/ROOT/examples/live-demos/importword/index.js @@ -0,0 +1,10 @@ +tinymce.init({ + selector: 'textarea#importword', + height: '800px', + plugins: [ + "importword", "advlist", "anchor", "autolink", "charmap", "code", "fullscreen", + "help", "image", "insertdatetime", "link", "lists", "media", + "preview", "searchreplace", "table", "visualblocks", +], +toolbar: "undo redo | importword | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image", +}); diff --git a/modules/ROOT/examples/live-demos/math/index.html b/modules/ROOT/examples/live-demos/math/index.html new file mode 100644 index 0000000000..dbaa8cd99a --- /dev/null +++ b/modules/ROOT/examples/live-demos/math/index.html @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/math/index.js b/modules/ROOT/examples/live-demos/math/index.js new file mode 100644 index 0000000000..26e2ef1132 --- /dev/null +++ b/modules/ROOT/examples/live-demos/math/index.js @@ -0,0 +1,9 @@ +tinymce.init({ + selector: "textarea#math_demo", + plugins: [ + "math", "advlist", "anchor", "autolink", "charmap", "code", "codesample", "fullscreen", + "help", "image", "insertdatetime", "link", "lists", "media", + "preview", "searchreplace", "table", "visualblocks", + ], + toolbar: "math | codesample | undo redo | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image", +}); \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/mentions/index.js b/modules/ROOT/examples/live-demos/mentions/index.js index 330d8ba102..57d75acbe3 100644 --- a/modules/ROOT/examples/live-demos/mentions/index.js +++ b/modules/ROOT/examples/live-demos/mentions/index.js @@ -21,6 +21,7 @@ tinymce.ScriptLoader.loadScripts(['https://cdn.jsdelivr.net/npm/faker@5/dist/fak for (let i = 0; i < 200; i++) { userNames.push(faker.name.findName()); } + userNames.sort((a, b) => a.localeCompare(b)); /* This represents a database of users on the server */ const userDb = {}; @@ -79,7 +80,7 @@ tinymce.ScriptLoader.loadScripts(['https://cdn.jsdelivr.net/npm/faker@5/dist/fak } usersRequest.then((users) => { /* `query.term` is the text the user typed after the '@' */ - users = users.filter((user) => user.name.indexOf(query.term.toLowerCase()) !== -1); + users = users.filter((user) => user.name.toLowerCase().includes(query.term.toLowerCase())) users = users.slice(0, 10); diff --git a/modules/ROOT/examples/live-demos/revisionhistory/index.html b/modules/ROOT/examples/live-demos/revisionhistory/index.html index 8f8c1bb3c9..624dbac699 100644 --- a/modules/ROOT/examples/live-demos/revisionhistory/index.html +++ b/modules/ROOT/examples/live-demos/revisionhistory/index.html @@ -1,34 +1,16 @@ \ No newline at end of file + +

    Got questions or need help?

    + + + +

    Found a bug?

    + +

    If you think you have found a bug please create an issue on the GitHub repo to report it to the developers.

    + +

    Finally…

    + +

    Don’t forget to check out our other product Plupload, your ultimate upload solution featuring HTML5 upload support.

    + +

    Thanks for supporting TinyMCE! We hope it helps you and your users create great content.

    + +

    All the best from the TinyMCE team.

    + diff --git a/modules/ROOT/examples/live-demos/revisionhistory/index.js b/modules/ROOT/examples/live-demos/revisionhistory/index.js index efc3a59a25..946faa0854 100644 --- a/modules/ROOT/examples/live-demos/revisionhistory/index.js +++ b/modules/ROOT/examples/live-demos/revisionhistory/index.js @@ -1,102 +1,210 @@ +const getRandomDelay = () => { + const minDelay = 500; + const maxDelay = 2000; + return Math.floor(Math.random() * (maxDelay - minDelay + 1)) + minDelay; +}; + +const lightRevisions = [ + { + revisionId: '3', + author: { + id: 'tiny.husky', + name: 'A Tiny Husky', + avatar: '{{imagesdir}}/tiny-husky.jpg', + }, + createdAt: '2023-11-25T08:30:21.578Z' + }, + { + revisionId: '2', + author: { + id: 'tiny.user', + name: 'A Tiny User', + avatar: '{{imagesdir}}/logos/android-chrome-192x192.png', + }, + createdAt: '2023-11-24T22:26:21.578Z', + }, + { + revisionId: '1', + author: { + id: 'tiny.user', + name: 'A Tiny User', + avatar: '{{imagesdir}}/logos/android-chrome-192x192.png', + }, + createdAt: '2023-11-23T20:26:21.578Z', + }, +]; + +const revisionhistory_fetch = () => + new Promise((resolve) => { + setTimeout(() => { + resolve( + lightRevisions + .sort((a, b) => + new Date(a.createdAt) < new Date(b.createdAt) ? -1 : 1 + ) + .reverse() + ); + }, getRandomDelay()); + }); + const revisions = [ { - revisionId: '4', - createdAt: '2023-11-29T10:11:21.578Z', + revisionId: '3', + createdAt: '2023-11-24T22:26:21.578Z', + author: { + id: 'tiny.husky', + name: 'A Tiny Husky', + avatar: '{{imagesdir}}/tiny-husky.jpg', + }, content: ` -

    The world’s first Rich Text Editor in the cloud

    -

     

    -
    Have you heard about Tiny Cloud? It’s the first step in our journey to help you deliver fantastic content creation experiences, no matter your level of expertise. 50,000 developers already agree. They get free access to our global CDN, image proxy services and auto updates to the TinyMCE editor. They’re also ready for some exciting updates coming soon.
    -

    An editor for every project

    -

    Here are some of our customer’s most common use cases for TinyMCE:

    -
      -
    1. Content Management Systems (e.g. WordPress, Umbraco)
    2. -
    3. Customer Relationship Management and marketing automation (e.g. Marketo)
    4. -
    5. Email marketing (e.g. Constant Contact)
    6. -
    7. Content creation in SaaS systems (e.g. Eventbrite, Evernote, GoFundMe, Zendesk)
    8. -
    +

    TinyMCE Logo

    +

    Welcome to the TinyMCE editor demo!

    +

    A simple table to play with

    + + + + + + + + + + + + + + + + + + + + +
    ProductCostReally?
    TinyMCEFreeYES!
    PluploadFreeYES!
    +

    Found a bug?

    +

    If you think you have found a bug please create an issue on the GitHub repo to report it to the developers.

    +

    Finally ...

    +

    Don't forget to check out our other product Plupload, your ultimate upload solution featuring HTML5 upload support.

    +

    Thanks for supporting TinyMCE! We hope it helps you and your users create great content.
    All the best from the TinyMCE team.

    `, }, { - revisionId: '3', + revisionId: '2', createdAt: '2023-11-25T08:30:21.578Z', + author: { + id: 'tiny.user', + name: 'A Tiny User', + avatar: '{{imagesdir}}/logos/android-chrome-192x192.png', + }, content: ` -

    The world’s first rich text editor in the cloud

    -

     

    -
    Have you heard about Tiny Cloud? It’s the first step in our journey to help you deliver great content creation experiences, no matter your level of expertise. 50,000 developers already agree. They get free access to our global CDN, image proxy services and auto updates to the TinyMCE editor. They’re also ready for some exciting updates coming soon.
    -

     

    -

    An editor for every project

    -

    Here are some of our customer’s most common use cases for TinyMCE:

    +

    TinyMCE Logo

    +

    Welcome to the TinyMCE editor demo!

    +

    Got questions or need help?

      -
    1. Content Management Systems (e.g. WordPress, Umbraco)
    2. -
    3. Learning Management Systems (e.g. Blackboard)
    4. -
    5. Customer Relationship Management and marketing automation (e.g. Marketo)
    6. -
    7. Email marketing (e.g. Constant Contact)
    8. -
    9. Content creation in SaaS systems (e.g. Eventbrite, Evernote, GoFundMe, Zendesk)
    10. +
    11. Our documentation is a great resource for learning how to configure TinyMCE.
    12. +
    13. Have a specific question? Try the tinymce tag at Stack Overflow.
    14. +
    15. We also offer enterprise grade support as part of TinyMCE premium plans.
    -

     

    -

    And those use cases are just the start. TinyMCE is incredibly flexible, and with hundreds of APIs there’s likely a solution for your editor project. If you haven’t experienced Tiny Cloud, get started today. You’ll even get a free trial of our premium plugins – no credit card required!

    +

    A simple table to play with

    + + + + + + + + + + + + + + + + + + + + +
    ProductCostReally?
    TinyMCEFreeYES!
    PluploadFreeYES!
    +

    Found a bug?

    +

    If you think you have found a bug please create an issue on the GitHub repo to report it to the developers.

    +

    Finally ...

    +

    Don't forget to check out our other product Plupload, your ultimate upload solution featuring HTML5 upload support.

    +

    Thanks for supporting TinyMCE! We hope it helps you and your users create great content.
    All the best from the TinyMCE team.

    `, }, { - revisionId: '2', - createdAt: '2023-11-24T22:26:21.578Z', + revisionId: '1', + createdAt: '2023-11-29T10:11:21.578Z', + author: { + id: 'tiny.user', + name: 'A Tiny User', + avatar: '{{imagesdir}}/logos/android-chrome-192x192.png', + }, content: ` -

    The world’s first rich text editor in the cloud

    -

     

    -
    Have you heard about Tiny Cloud? It’s the first step in our journey to help you deliver great content creation experiences, no matter your level of expertise. 50,000 developers already agree. They get free access to our global CDN, image proxy services and auto updates to the TinyMCE editor. They’re also ready for some exciting updates coming soon.
    -

     

    -

    One of these enhancements is Tiny Drive: imagine file management for TinyMCE, in the cloud, made super easy. Learn more at Tiny Cloud - Tiny Drive, where you’ll find a working demo and an opportunity to provide feedback to the product team.

    -

    An editor for every project

    -

    Here are some of our customer’s most common use cases for TinyMCE:

    +

    TinyMCE Logo

    +

    Welcome to the TinyMCE editor demo!

    +

    Got questions or need help?

      -
    • Content Management Systems (e.g. WordPress, Umbraco)
    • -
    • Learning Management Systems (e.g. Blackboard)
    • -
    • Customer Relationship Management and marketing automation (e.g. Marketo)
    • -
    • Email marketing (e.g. Constant Contact)
    • -
    • Content creation in SaaS systems (e.g. Eventbrite, Evernote, GoFundMe, Zendesk)
    • +
    • Our documentation is a great resource for learning how to configure TinyMCE.
    • +
    • Have a specific question? Try the tinymce tag at Stack Overflow.
    • +
    • We also offer enterprise grade support as part of TinyMCE premium plans.
    -

     

    -

    And those use cases are just the start. TinyMCE is incredibly flexible, and with hundreds of APIs there’s likely a solution for your editor project. If you haven’t experienced Tiny Cloud, get started today. You’ll even get a free trial of our premium plugins – no credit card required!

    - `, - }, - { - revisionId: '1', - createdAt: '2023-11-23T20:26:21.578Z', - content: ` - +

    A simple table to play with

    + + + + + + + + + + + + + + + + + + + + +
    ProductCostReally?
    TinyMCEFreeYES!
    PluploadFreeYES!
    +

    Found a bug?

    +

    If you think you have found a bug please create an issue on the GitHub repo to report it to the developers.

    +

    Finally ...

    +

    Don't forget to check out our other product Plupload, your ultimate upload solution featuring HTML5 upload support.

    +

    Thanks for supporting TinyMCE! We hope it helps you and your users create great content.
    All the best from the TinyMCE team.

    `, } ]; -const get_revisions = () => new Promise((resolve) => { +const revisionhistory_fetch_revision = (_editor, revision) => + new Promise((resolve, reject) => { setTimeout(() => { - resolve(revisions.sort((a, b) => new Date(a.createdAt) < new Date(b.createdAt) ? -1 : 1).reverse()); - }, 1000); + const newRevision = revisions.find((r) => r.revisionId === revision.revisionId); + if (newRevision === undefined) { + reject(`Revision ${revision.revisionId} is not found`); + } else { + resolve(newRevision); + } + }, getRandomDelay()); }); - tinymce.init({ selector: 'textarea#revisionhistory', height: 800, plugins: 'revisionhistory', toolbar: 'revisionhistory', - revisionhistory_fetch: get_revisions, - content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }' -}); \ No newline at end of file + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', + revisionhistory_fetch, + revisionhistory_fetch_revision, + revisionhistory_author: { + id: 'john.doe', + name: 'John Doe' + }, + revisionhistory_display_author: true +}); diff --git a/modules/ROOT/examples/live-demos/spellchecker/index.js b/modules/ROOT/examples/live-demos/spellchecker/index.js index 36843325fd..617b1a579d 100644 --- a/modules/ROOT/examples/live-demos/spellchecker/index.js +++ b/modules/ROOT/examples/live-demos/spellchecker/index.js @@ -3,17 +3,31 @@ tinymce.init({ plugins: 'code tinymcespellchecker link', toolbar: 'spellchecker language spellcheckdialog', height: 500, - spellchecker_language: 'en', + spellchecker_language: 'en_US', content_langs: [ - { title: 'English (US)', code: 'en_US' }, - { title: 'English (US Medical)', code: 'en_US', customCode: 'en_US-medical' }, - { title: 'English (UK)', code: 'en_UK' }, - { title: 'English (UK Medical)', code: 'en_UK', customCode: 'en_UK-medical' }, - { title: 'Spanish', code: 'es' }, + { 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: 'Finnish', code: 'fi' }, { title: 'French', code: 'fr' }, - { title: 'German', code: 'de' }, - { title: 'Portuguese', code: 'pt' }, - { title: 'Chinese', code: 'zh' } + { 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: 'Norwegian Nynorsk', code: 'nn' }, + { title: 'Polish', code: 'pl' }, + { 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' } ], content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }' -}); \ No newline at end of file +}); diff --git a/modules/ROOT/examples/live-demos/uploadcare/example.js b/modules/ROOT/examples/live-demos/uploadcare/example.js new file mode 100644 index 0000000000..8673194db0 --- /dev/null +++ b/modules/ROOT/examples/live-demos/uploadcare/example.js @@ -0,0 +1,20 @@ +tinymce.init({ + selector: "textarea", + plugins: [ "uploadcare", "code", "link", "preview", "lists" ], + uploadcare_public_key: '', + a11y_advanced_options: true, + toolbar: "undo redo | styles | bold italic underline | forecolor | bullist numlist| link uploadcare | code preview", + height: 700, + content_style: ` + body { max-width: 920px; margin: 1.5rem auto; padding: 0 2vw; } + h1 { font-size: 1.5em; } + h2 { font-size: 1.17em; } + h1, h2, h3, h4, h5, h6 { font-weight: 500; margin: 0 0 0.75rem; } + p + h1, p + h2, p + h3, p + h4, p + h5, p + h6 { margin-top: 2rem; } + p { line-height: 1.6; margin: 0; } + p + p { margin-top: 1rem; } + a { color: #2b70e3; } + blockquote { color: #4e5c73; font-weight: 200; font-size: 1.3rem; margin: 1rem 2rem; padding: 0 0 0 1rem; border-left: 2px solid #2b70e3 !important; } + figcaption {font-size: 0.875em;} + ` + }); \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/uploadcare/index.html b/modules/ROOT/examples/live-demos/uploadcare/index.html new file mode 100644 index 0000000000..6fb2c2d2e2 --- /dev/null +++ b/modules/ROOT/examples/live-demos/uploadcare/index.html @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/uploadcare/index.js b/modules/ROOT/examples/live-demos/uploadcare/index.js new file mode 100644 index 0000000000..06955b26b6 --- /dev/null +++ b/modules/ROOT/examples/live-demos/uploadcare/index.js @@ -0,0 +1,22 @@ +tinymce.init({ + selector: "textarea", + plugins: [ "uploadcare", "code", "link", "preview", "lists" ], + uploadcare_public_key: '630992ad50fe2291c406', + uploadcare_cdn_base_url: 'https://tiny.ucarecdn.com', + uploadcare_store_type: 'temporary', + a11y_advanced_options: true, + toolbar: "undo redo | styles | bold italic underline | forecolor | bullist numlist| link uploadcare | code preview", + height: 700, + content_style: ` + body { max-width: 920px; margin: 1.5rem auto; padding: 0 2vw; } + h1 { font-size: 1.5em; } + h2 { font-size: 1.17em; } + h1, h2, h3, h4, h5, h6 { font-weight: 500; margin: 0 0 0.75rem; } + p + h1, p + h2, p + h3, p + h4, p + h5, p + h6 { margin-top: 2rem; } + p { line-height: 1.6; margin: 0; } + p + p { margin-top: 1rem; } + a { color: #2b70e3; } + blockquote { color: #4e5c73; font-weight: 200; font-size: 1.3rem; margin: 1rem 2rem; padding: 0 0 0 1rem; border-left: 2px solid #2b70e3 !important; } + figcaption {font-size: 0.875em;} + ` +}); diff --git a/modules/ROOT/images/ai-plugin/ai-icon.svg b/modules/ROOT/images/ai-plugin/ai-icon.svg new file mode 100644 index 0000000000..00d8df3ec3 --- /dev/null +++ b/modules/ROOT/images/ai-plugin/ai-icon.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/modules/ROOT/images/ai-plugin/wand-icon.svg b/modules/ROOT/images/ai-plugin/wand-icon.svg new file mode 100644 index 0000000000..c0de6b4b35 --- /dev/null +++ b/modules/ROOT/images/ai-plugin/wand-icon.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/ROOT/images/color-picker/color-picker-error-message-hex.png b/modules/ROOT/images/color-picker/color-picker-error-message-hex.png new file mode 100644 index 0000000000..c53a598379 Binary files /dev/null and b/modules/ROOT/images/color-picker/color-picker-error-message-hex.png differ diff --git a/modules/ROOT/images/color-picker/color-picker-error-message-rbg.png b/modules/ROOT/images/color-picker/color-picker-error-message-rbg.png new file mode 100644 index 0000000000..343392ad49 Binary files /dev/null and b/modules/ROOT/images/color-picker/color-picker-error-message-rbg.png differ diff --git a/modules/ROOT/images/comment-add-comment.png b/modules/ROOT/images/comment-add-comment.png new file mode 100644 index 0000000000..23bbd04bd2 Binary files /dev/null and b/modules/ROOT/images/comment-add-comment.png differ diff --git a/modules/ROOT/images/comment-comment-created.png b/modules/ROOT/images/comment-comment-created.png new file mode 100644 index 0000000000..fb5bc11442 Binary files /dev/null and b/modules/ROOT/images/comment-comment-created.png differ diff --git a/modules/ROOT/images/comment-delete-all-conversations-file-menu.png b/modules/ROOT/images/comment-delete-all-conversations-file-menu.png new file mode 100644 index 0000000000..8f50ca819c Binary files /dev/null and b/modules/ROOT/images/comment-delete-all-conversations-file-menu.png differ diff --git a/modules/ROOT/images/comment-delete-all-conversations.png b/modules/ROOT/images/comment-delete-all-conversations.png new file mode 100644 index 0000000000..c8a7fa461d Binary files /dev/null and b/modules/ROOT/images/comment-delete-all-conversations.png differ diff --git a/modules/ROOT/images/comment-delete-comment-dialog.png b/modules/ROOT/images/comment-delete-comment-dialog.png new file mode 100644 index 0000000000..ad00c9f5de Binary files /dev/null and b/modules/ROOT/images/comment-delete-comment-dialog.png differ diff --git a/modules/ROOT/images/comment-delete-comment.png b/modules/ROOT/images/comment-delete-comment.png new file mode 100644 index 0000000000..fc1bebfca9 Binary files /dev/null and b/modules/ROOT/images/comment-delete-comment.png differ diff --git a/modules/ROOT/images/comment-delete-conversation-dialog.png b/modules/ROOT/images/comment-delete-conversation-dialog.png new file mode 100644 index 0000000000..e1ccddab1d Binary files /dev/null and b/modules/ROOT/images/comment-delete-conversation-dialog.png differ diff --git a/modules/ROOT/images/comment-delete-conversation.png b/modules/ROOT/images/comment-delete-conversation.png new file mode 100644 index 0000000000..63742fe952 Binary files /dev/null and b/modules/ROOT/images/comment-delete-conversation.png differ diff --git a/modules/ROOT/images/comment-edit-comment.png b/modules/ROOT/images/comment-edit-comment.png new file mode 100644 index 0000000000..41fb3542b4 Binary files /dev/null and b/modules/ROOT/images/comment-edit-comment.png differ diff --git a/modules/ROOT/images/comment-edit-existing-comment-ellipsis.png b/modules/ROOT/images/comment-edit-existing-comment-ellipsis.png new file mode 100644 index 0000000000..c9a31f34c8 Binary files /dev/null and b/modules/ROOT/images/comment-edit-existing-comment-ellipsis.png differ diff --git a/modules/ROOT/images/comment-edited-comment.png b/modules/ROOT/images/comment-edited-comment.png new file mode 100644 index 0000000000..a64709d2ad Binary files /dev/null and b/modules/ROOT/images/comment-edited-comment.png differ diff --git a/modules/ROOT/images/comment-reply-add-comment-focus.png b/modules/ROOT/images/comment-reply-add-comment-focus.png new file mode 100644 index 0000000000..ce04a5da0f Binary files /dev/null and b/modules/ROOT/images/comment-reply-add-comment-focus.png differ diff --git a/modules/ROOT/images/comment-reply-add-comment-pre-submit.png b/modules/ROOT/images/comment-reply-add-comment-pre-submit.png new file mode 100644 index 0000000000..97c238c719 Binary files /dev/null and b/modules/ROOT/images/comment-reply-add-comment-pre-submit.png differ diff --git a/modules/ROOT/images/comment-reply-add-comment-textarea.png b/modules/ROOT/images/comment-reply-add-comment-textarea.png new file mode 100644 index 0000000000..c31b30af2a Binary files /dev/null and b/modules/ROOT/images/comment-reply-add-comment-textarea.png differ diff --git a/modules/ROOT/images/comment-reply-add-comment.png b/modules/ROOT/images/comment-reply-add-comment.png new file mode 100644 index 0000000000..1294681363 Binary files /dev/null and b/modules/ROOT/images/comment-reply-add-comment.png differ diff --git a/modules/ROOT/images/comment-reply-to-comment-done.png b/modules/ROOT/images/comment-reply-to-comment-done.png new file mode 100644 index 0000000000..28d620ab95 Binary files /dev/null and b/modules/ROOT/images/comment-reply-to-comment-done.png differ diff --git a/modules/ROOT/images/comment-reply-to-comment-submitted.png b/modules/ROOT/images/comment-reply-to-comment-submitted.png new file mode 100644 index 0000000000..c38f55bed3 Binary files /dev/null and b/modules/ROOT/images/comment-reply-to-comment-submitted.png differ diff --git a/modules/ROOT/images/comment-resolve-conversation.png b/modules/ROOT/images/comment-resolve-conversation.png new file mode 100644 index 0000000000..3699408b8d Binary files /dev/null and b/modules/ROOT/images/comment-resolve-conversation.png differ diff --git a/modules/ROOT/images/comments-delete-comment.png b/modules/ROOT/images/comments-delete-comment.png deleted file mode 100644 index 243325fed1..0000000000 Binary files a/modules/ROOT/images/comments-delete-comment.png and /dev/null differ diff --git a/modules/ROOT/images/comments-delete-conversation.png b/modules/ROOT/images/comments-delete-conversation.png deleted file mode 100644 index 2cd3852de8..0000000000 Binary files a/modules/ROOT/images/comments-delete-conversation.png and /dev/null differ diff --git a/modules/ROOT/images/comments-delete-conversations.png b/modules/ROOT/images/comments-delete-conversations.png deleted file mode 100644 index e94d805b00..0000000000 Binary files a/modules/ROOT/images/comments-delete-conversations.png and /dev/null differ diff --git a/modules/ROOT/images/comments-edit.png b/modules/ROOT/images/comments-edit.png deleted file mode 100644 index 88bd128299..0000000000 Binary files a/modules/ROOT/images/comments-edit.png and /dev/null differ diff --git a/modules/ROOT/images/comments-resolve-conversation.png b/modules/ROOT/images/comments-resolve-conversation.png deleted file mode 100644 index 04ba2be992..0000000000 Binary files a/modules/ROOT/images/comments-resolve-conversation.png and /dev/null differ diff --git a/modules/ROOT/images/icons/add-file.svg b/modules/ROOT/images/icons/add-file.svg new file mode 100644 index 0000000000..18af2d8265 --- /dev/null +++ b/modules/ROOT/images/icons/add-file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/adjustments.svg b/modules/ROOT/images/icons/adjustments.svg new file mode 100644 index 0000000000..2079d17011 --- /dev/null +++ b/modules/ROOT/images/icons/adjustments.svg @@ -0,0 +1,3 @@ + + + diff --git a/modules/ROOT/images/icons/alt-text.svg b/modules/ROOT/images/icons/alt-text.svg new file mode 100644 index 0000000000..6e85a1f800 --- /dev/null +++ b/modules/ROOT/images/icons/alt-text.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/blur.svg b/modules/ROOT/images/icons/blur.svg new file mode 100644 index 0000000000..0cf6893a70 --- /dev/null +++ b/modules/ROOT/images/icons/blur.svg @@ -0,0 +1,3 @@ + + + diff --git a/modules/ROOT/images/icons/box.svg b/modules/ROOT/images/icons/box.svg new file mode 100644 index 0000000000..dce6de1685 --- /dev/null +++ b/modules/ROOT/images/icons/box.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/camera.svg b/modules/ROOT/images/icons/camera.svg new file mode 100644 index 0000000000..21c6164636 --- /dev/null +++ b/modules/ROOT/images/icons/camera.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/caption.svg b/modules/ROOT/images/icons/caption.svg new file mode 100644 index 0000000000..bbfa23cf7f --- /dev/null +++ b/modules/ROOT/images/icons/caption.svg @@ -0,0 +1,3 @@ + + + diff --git a/modules/ROOT/images/icons/dropbox.svg b/modules/ROOT/images/icons/dropbox.svg new file mode 100644 index 0000000000..61576ab6f5 --- /dev/null +++ b/modules/ROOT/images/icons/dropbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/evernote.svg b/modules/ROOT/images/icons/evernote.svg new file mode 100644 index 0000000000..a750417723 --- /dev/null +++ b/modules/ROOT/images/icons/evernote.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/exposure.svg b/modules/ROOT/images/icons/exposure.svg new file mode 100644 index 0000000000..fda78d4caf --- /dev/null +++ b/modules/ROOT/images/icons/exposure.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/fb.svg b/modules/ROOT/images/icons/fb.svg new file mode 100644 index 0000000000..5503a9b4c0 --- /dev/null +++ b/modules/ROOT/images/icons/fb.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/flickr.svg b/modules/ROOT/images/icons/flickr.svg new file mode 100644 index 0000000000..336b721bc4 --- /dev/null +++ b/modules/ROOT/images/icons/flickr.svg @@ -0,0 +1,3 @@ + + + diff --git a/modules/ROOT/images/icons/folder.svg b/modules/ROOT/images/icons/folder.svg new file mode 100644 index 0000000000..9bd6f4a888 --- /dev/null +++ b/modules/ROOT/images/icons/folder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/format-code.svg b/modules/ROOT/images/icons/format-code.svg new file mode 100644 index 0000000000..889a8848fc --- /dev/null +++ b/modules/ROOT/images/icons/format-code.svg @@ -0,0 +1,3 @@ + + + diff --git a/modules/ROOT/images/icons/google-drive.svg b/modules/ROOT/images/icons/google-drive.svg new file mode 100644 index 0000000000..3ca54f4325 --- /dev/null +++ b/modules/ROOT/images/icons/google-drive.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/google-photos.svg b/modules/ROOT/images/icons/google-photos.svg new file mode 100644 index 0000000000..33a6af34c5 --- /dev/null +++ b/modules/ROOT/images/icons/google-photos.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/grayscale.svg b/modules/ROOT/images/icons/grayscale.svg new file mode 100644 index 0000000000..21af08f8a8 --- /dev/null +++ b/modules/ROOT/images/icons/grayscale.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/huddle.svg b/modules/ROOT/images/icons/huddle.svg new file mode 100644 index 0000000000..b4755a1247 --- /dev/null +++ b/modules/ROOT/images/icons/huddle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/image-decorative.svg b/modules/ROOT/images/icons/image-decorative.svg new file mode 100644 index 0000000000..656cb0260c --- /dev/null +++ b/modules/ROOT/images/icons/image-decorative.svg @@ -0,0 +1,3 @@ + + + diff --git a/modules/ROOT/images/icons/image-enhancements.svg b/modules/ROOT/images/icons/image-enhancements.svg new file mode 100644 index 0000000000..f95c841695 --- /dev/null +++ b/modules/ROOT/images/icons/image-enhancements.svg @@ -0,0 +1,4 @@ + + + + diff --git a/modules/ROOT/images/icons/instagram.svg b/modules/ROOT/images/icons/instagram.svg new file mode 100644 index 0000000000..c46d3c45ec --- /dev/null +++ b/modules/ROOT/images/icons/instagram.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/math-equation.svg b/modules/ROOT/images/icons/math-equation.svg new file mode 100644 index 0000000000..eed6685658 --- /dev/null +++ b/modules/ROOT/images/icons/math-equation.svg @@ -0,0 +1,3 @@ + + + diff --git a/modules/ROOT/images/icons/onedrive.svg b/modules/ROOT/images/icons/onedrive.svg new file mode 100644 index 0000000000..9463e3cecf --- /dev/null +++ b/modules/ROOT/images/icons/onedrive.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/revert.svg b/modules/ROOT/images/icons/revert.svg new file mode 100644 index 0000000000..68854286fc --- /dev/null +++ b/modules/ROOT/images/icons/revert.svg @@ -0,0 +1,4 @@ + + + + diff --git a/modules/ROOT/images/icons/saturation.svg b/modules/ROOT/images/icons/saturation.svg new file mode 100644 index 0000000000..4ed121e860 --- /dev/null +++ b/modules/ROOT/images/icons/saturation.svg @@ -0,0 +1,3 @@ + + + diff --git a/modules/ROOT/images/icons/transform-image.svg b/modules/ROOT/images/icons/transform-image.svg new file mode 100644 index 0000000000..15e252c9cf --- /dev/null +++ b/modules/ROOT/images/icons/transform-image.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/vibrance.svg b/modules/ROOT/images/icons/vibrance.svg new file mode 100644 index 0000000000..63f83303ab --- /dev/null +++ b/modules/ROOT/images/icons/vibrance.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/vk.svg b/modules/ROOT/images/icons/vk.svg new file mode 100644 index 0000000000..3c24b20293 --- /dev/null +++ b/modules/ROOT/images/icons/vk.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/ROOT/images/icons/warmth.svg b/modules/ROOT/images/icons/warmth.svg new file mode 100644 index 0000000000..1694549adc --- /dev/null +++ b/modules/ROOT/images/icons/warmth.svg @@ -0,0 +1,3 @@ + + + diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc index a3b6d2ec15..4ebb4b58b9 100644 --- a/modules/ROOT/nav.adoc +++ b/modules/ROOT/nav.adoc @@ -30,6 +30,7 @@ ***** xref:blazor-pm.adoc[Using a package manager] ***** xref:blazor-zip.adoc[Using a .zip package] **** Svelte +**** TEST ***** xref:svelte-pm.adoc[Using a package manager] ***** xref:svelte-zip.adoc[Using a .zip package] **** Web Component @@ -123,7 +124,7 @@ ** xref:cloud-deployment-guide.adoc[Cloud deployment guide] *** xref:editor-and-features.adoc[Cloud deployment of editor & plugins] *** xref:features-only.adoc[Cloud deployment of plugins Only] -*** xref:editor-plugin-version.adoc[Specify editor & plugin versions] +*** xref:editor-plugin-version.adoc[Specify editor version & plugins] *** xref:plugin-editor-version-compatibility.adoc[Version compatibility reference] *** xref:cloud-troubleshooting.adoc[Cloud Troubleshooting] ** Premium server-side services guide @@ -136,6 +137,8 @@ **** Individually licensed plugin services ***** xref:individual-hyperlinking-container.adoc[Hyperlinking service] ***** xref:individual-spelling-container.adoc[Spelling service] +***** xref:individual-export-to-pdf-on-premises.adoc[Export to PDF] +***** xref:individual-import-from-word-and-export-to-word-on-premises.adoc[Import from Word and Export to Word] *** Configure the server-side components **** xref:configure-required-services.adoc[Required configuration] **** xref:configure-common-settings-services.adoc[Optional common settings] @@ -178,13 +181,12 @@ *** xref:creating-custom-notifications.adoc[Notifications] *** xref:customsidebar.adoc[Sidebars] *** xref:custom-view.adoc[Views] +*** xref:context.adoc[Context] *** xref:contextform.adoc[Context forms] *** xref:contextmenu.adoc[Context menus] *** xref:contexttoolbar.adoc[Context toolbar] *** xref:shortcuts.adoc[Keyboard Shortcuts] -*** Creating custom plugins -**** xref:creating-a-plugin.adoc[Create a plugin] -**** xref:yeoman-generator.adoc[Yeoman generator] +*** xref:creating-a-plugin.adoc[Creating custom plugins] *** xref:editor-command-identifiers.adoc[Available Commands] *** xref:events.adoc[Available Events] *** xref:editor-icon-identifiers.adoc[Available Icons] @@ -288,6 +290,10 @@ *** xref:a11ychecker.adoc[Accessibility Checker] *** xref:advanced-typography.adoc[Advanced Typography] *** xref:ai.adoc[AI Assistant] +**** xref:ai-openai.adoc[OpenAI ChatGPT integration guide] +**** xref:ai-azure.adoc[Azure AI integration guide] +**** xref:ai-bedrock.adoc[Amazon Bedrock integration guide] +**** xref:ai-gemini.adoc[Google Gemini integration guide] **** xref:ai-proxy.adoc[AI proxy server reference guide] *** xref:casechange.adoc[Case Change] *** xref:checklist.adoc[Checklist] @@ -297,7 +303,9 @@ **** xref:comments-callback-mode.adoc[Callback mode] **** xref:comments-embedded-mode.adoc[Embedded mode] **** xref:comments-toolbars-menus.adoc[Toolbar buttons and menu items] +**** xref:comments-access-options.adoc[Access Options] **** xref:comments-commands-events-apis.adoc[Commands, Events and APIs] +**** xref:comments-with-mentions.adoc[Comments with Mentions] *** xref:advcode.adoc[Enhanced Code Editor] *** Enhanced Media Embed **** xref:introduction-to-mediaembed.adoc[Enhanced Media Embed] @@ -305,13 +313,27 @@ **** xref:mediaembed-server-integration.adoc[Integrate Enhanced Media Embed Server] *** xref:advtable.adoc[Enhanced Tables] *** xref:exportpdf.adoc[Export to PDF] +**** xref:html-to-pdf-converter-api.adoc[HTML to PDF Converter API] +**** JWT Authentication +***** xref:export-to-pdf-with-jwt-authentication-nodejs.adoc[Node.js] +***** xref:export-to-pdf-with-jwt-authentication-php.adoc[PHP] *** xref:exportword.adoc[Export to Word] +**** xref:html-to-docx-converter-api.adoc[HTML to DOCX Converter API] +**** JWT Authentication +***** xref:export-to-word-with-jwt-authentication-nodejs.adoc[Node.js] +***** xref:export-to-word-with-jwt-authentication-php.adoc[PHP] *** xref:footnotes.adoc[Footnotes] *** xref:formatpainter.adoc[Format Painter] *** xref:importword.adoc[Import from Word] +**** xref:docx-to-html-converter-api.adoc[DOCX to HTML Converter API] +**** JWT Authentication +***** xref:import-from-word-with-jwt-authentication-nodejs.adoc[Node.js] +***** xref:import-from-word-with-jwt-authentication-php.adoc[PHP] *** xref:editimage.adoc[Image Editing] +*** xref:uploadcare.adoc[Image Optimizer Powered by Uploadcare] *** xref:inline-css.adoc[Inline CSS] *** xref:linkchecker.adoc[Link Checker] +*** xref:math.adoc[Math] *** xref:markdown.adoc[Markdown] *** xref:mentions.adoc[Mentions] *** xref:mergetags.adoc[Merge Tags] @@ -397,7 +419,71 @@ ** xref:tinymce-and-csp.adoc[Content Security Policies (CSP)] ** xref:tinymce-and-cors.adoc[Cross-Origin Resource Sharing (CORS)] * Release information -** xref:release-notes.adoc[Release notes for {productname} {productmajorversion}] +** xref:release-notes.adoc[Release notes for {productname}] +*** {productname} 7.6.0 +**** xref:7.6.0-release-notes.adoc#overview[Overview] +**** xref:7.6.0-release-notes.adoc#new-premium-plugin[New Premium plugin] +**** xref:7.6.0-release-notes.adoc#accompanying-premium-plugin-changes[Accompanying Premium plugin changes] +**** xref:7.6.0-release-notes.adoc#accompanying-enhanced-skins-and-icon-packs-changes[Accompanying Enhanced Skins & Icon Packs changes] +**** xref:7.6.0-release-notes.adoc#improvements[Improvements] +**** xref:7.6.0-release-notes.adoc#additions[Additions] +**** xref:7.6.0-release-notes.adoc#bug-fixes[Bug fixes] +**** xref:7.6.0-release-notes.adoc#known-issues[Known issues] +*** {productname} 7.5.1 +**** xref:7.5.1-release-notes.adoc#overview[Overview] +**** xref:7.5.1-release-notes.adoc#accompanying-premium-plugin-changes[Accompanying Premium Plugin changes] +*** {productname} 7.5 +**** xref:7.5-release-notes.adoc#overview[Overview] +**** xref:7.5-release-notes.adoc#accompanying-premium-plugin-changes[Accompanying Premium Plugin changes] +**** xref:7.5-release-notes.adoc#improvements[Improvements] +**** xref:7.5-release-notes.adoc#additions[Additions] +**** xref:7.5-release-notes.adoc#bug-fixes[Bug fixes] +**** xref:7.5-release-notes.adoc#known-issues[Known issues] +*** {productname} 7.4.1 +**** xref:7.4.1-release-notes.adoc#overview[Overview] +**** xref:7.4.1-release-notes.adoc#security-fix[Security fix] +*** {productname} 7.4 +**** xref:7.4-release-notes.adoc#overview[Overview] +**** xref:7.4-release-notes.adoc#accompanying-premium-plugin-changes[Accompanying Premium Plugin changes] +**** xref:7.4-release-notes.adoc#improvements[Improvements] +**** xref:7.4-release-notes.adoc#additions[Additions] +**** xref:7.4-release-notes.adoc#bug-fixes[Bug fixes] +**** xref:7.4-release-notes.adoc#known-issues[Known issues] +*** {productname} 7.3 +**** xref:7.3-release-notes.adoc#overview[Overview] +**** xref:7.3-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:7.3-release-notes.adoc#improvements[Improvements] +**** xref:7.3-release-notes.adoc#additions[Additions] +**** xref:7.3-release-notes.adoc#bug-fixes[Bug fixes] +*** {productname} 7.2.1 +**** xref:7.2.1-release-notes.adoc#overview[Overview] +**** xref:7.2.1-release-notes.adoc#bug-fixes[Bug fixes] +*** {productname} 7.2 +**** xref:7.2-release-notes.adoc#overview[Overview] +**** xref:7.2-release-notes.adoc#accompanying-premium-self-hosted-server-side-component-changes[Accompanying Premium self-hosted server-side component changes] +**** xref:7.2-release-notes.adoc#accompanying-premium-plugin-changes[Accompanying Premium plugin changes] +**** xref:7.2-release-notes.adoc#improvements[Improvements] +**** xref:7.2-release-notes.adoc#additions[Additions] +**** xref:7.2-release-notes.adoc#changes[Changes] +**** xref:7.2-release-notes.adoc#bug-fixes[Bug fixes] +**** xref:7.2-release-notes.adoc#security-fixes[Security fixes] +*** {productname} 7.1.2 +**** xref:7.1.2-release-notes.adoc#overview[Overview] +**** xref:7.1.2-release-notes.adoc#accompanying-premium-plugin-changes[Accompanying Premium Plugin changes] +**** xref:7.1.2-release-notes.adoc#bug-fixes[Bug fixes] +*** {productname} 7.1.1 +**** xref:7.1.1-release-notes.adoc#overview[Overview] +**** xref:7.1.1-release-notes.adoc#accompanying-premium-plugin-changes[Accompanying Premium Plugin changes] +**** xref:7.1.1-release-notes.adoc#bug-fixes[Bug fixes] +*** {productname} 7.1 +**** xref:7.1-release-notes.adoc#overview[Overview] +**** * xref:7.1-release-notes.adoc#accompanying-premium-self-hosted-server-side-component-changes[Accompanying Premium self-hosted server-side component changes] +**** * xref:7.1-release-notes.adoc#new-premium-plugin[New Premium plugin] +**** xref:7.1-release-notes.adoc#accompanying-premium-plugin-changes[Accompanying Premium plugin changes] +**** xref:7.1-release-notes.adoc#improvements[Improvements] +**** xref:7.1-release-notes.adoc#bug-fixes[Bug fixes] +**** xref:7.1-release-notes.adoc#security-fixes[Security fixes] *** {productname} 7.0.1 **** xref:7.0.1-release-notes.adoc#overview[Overview] **** xref:7.0.1-release-notes.adoc#accompanying-premium-plugin-changes[Accompanying Premium Plugin changes] @@ -419,3 +505,4 @@ * xref:invalid-api-key.adoc[Invalid API key] * xref:license-key.adoc[License key] * xref:support.adoc[Support] +* xref:usage-based-billing.adoc[Usage-Based Billing] diff --git a/modules/ROOT/pages/7.0-release-notes.adoc b/modules/ROOT/pages/7.0-release-notes.adoc index 6585b4dda3..99f52461d6 100644 --- a/modules/ROOT/pages/7.0-release-notes.adoc +++ b/modules/ROOT/pages/7.0-release-notes.adoc @@ -543,9 +543,9 @@ Previously, the bespoke `styles` select toolbar button in {productname} defaulte === Removed `force_hex_color` option, with the default now being all colors are forced to HEX format and as lower case. // #TINY-10436 -Previously in {productname} 6, all colors in the content HTML were set to use `rgb` values by default. As the common practice is using `hex` values this change has been **reverted**. +Previously in {productname} 6, all colors in the content HTML were set to use `rgb` values by default. As the common practice is using `hex` values, this change has been **reverted**. -As a result, in {productname} 7, all colors are converted to use `hex` values and the `forced_hex_color` option is removed. The exception being `rgba` color values, they are left as is. +As a result, in {productname} 7, only RGB values in absolute value like `rgb(255, 255, 255)` are converted to HEX values. Other RGB formats such as those with non-absolute values, and color options such as RGBA and HSL remain unchanged. The `forced_hex_color` option has been removed. For more information, see xref:migration-from-6x.adoc#force-hex-color[Migrating from {productname} 6 to {productname} 7]. diff --git a/modules/ROOT/pages/7.1-release-notes.adoc b/modules/ROOT/pages/7.1-release-notes.adoc new file mode 100644 index 0000000000..8233fd6121 --- /dev/null +++ b/modules/ROOT/pages/7.1-release-notes.adoc @@ -0,0 +1,395 @@ += {productname} {release-version} +:release-version: 7.1 +:navtitle: {productname} {release-version} +:description: Release notes for {productname} {release-version} +:keywords: releasenotes, new, changes, bugfixes +:page-toclevels: 1 + +include::partial$misc/admon-releasenotes-for-stable.adoc[] + +[[overview]] +== Overview + +{productname} {release-version} was released for {enterpriseversion} and {cloudname} on Wednesday, May 08^th^, 2024. + +These release notes provide an overview of the changes for {productname} {release-version}, including: + +* xref:accompanying-premium-self-hosted-server-side-component-changes[Accompanying Premium self-hosted server-side component changes] +* xref:new-premium-plugin[New Premium plugin] +* xref:accompanying-premium-plugin-changes[Accompanying Premium plugin changes] +* xref:improvements[Improvements] +* xref:bug-fixes[Bug fixes] +* xref:security-fixes[Security fixes] + + +[[accompanying-premium-self-hosted-server-side-component-changes]] +== Accompanying Premium self-hosted server-side component changes + +The {productname} {release-version} release includes accompanying changes affecting the {productname} **self-hosted** services for the following plugins: + +* **Enhanced Media Embed** plugin `mediaembed`. +* **Image Editing** plugin `editimage`. +* **Link Checker** plugin `linkchecker`. +* **Spell Checker** plugin `tinymcespellchecker`. +* **Spelling Autocorrect** plugin `autocorrect`. + +For information on: + +* The **Enhanced Media Embed** plugin, see: xref:introduction-to-mediaembed.adoc[Enhanced Media Embed plugin]. +* The **Image Editing** plugin, see: xref:editimage.adoc[Image Editing plugin]. +* The **Link Checker** plugin, see: xref:linkchecker.adoc[Link Checker plugin]. +* The **Spell Checker** plugin, see: xref:introduction-to-tiny-spellchecker.adoc[Spell Checkerplugin]. +* The **Spelling Autocorrect** plugin, see: xref:autocorrect.adoc[Spelling Autocorrect plugin]. +* Deploying the **server-side** components, see: xref:introduction-to-premium-selfhosted-services.adoc[Server-side component installation]. + +The Java server-side components have been updated to the following versions: + +* `ephox-hyperlinking.war`: 2.105.25 +* `ephox-image-proxy.war`: 2.106.12 +* `ephox-spelling.war`: 2.118.21 + + +=== Updating the self-hosted server-side components + +The new versions of the server-side services provide updates for the Java-based server-side components. To deploy the updated version of the server-side components: + +. Update your Java Application Server to the minimum required version: + +include::partial$misc/supported-application-servers.adoc[] + +. Replace the existing server-side `.war` files with the `.war` files bundled with {productname} {release-version} or later. + +For information on: + +* Deploying the server-side components, see: xref:introduction-to-premium-selfhosted-services.adoc[Server-side component installation]. +* Deploying the server-side components using Docker, see: xref:bundle-intro-setup.adoc[Containerized service deployments]. + +include::partial$misc/admon-no-functionality-changes-in-updated-server-side-components.adoc[] + +[[new-premium-plugin]] +== New Premium plugin + +The following new Premium plugin was released alongside {productname} 7.1. + +[[math]] +=== Math + +The new Premium plugin, **Math**, provides a way for users to insert complex formulas. + +For information on the **Math** plugin, see: xref:math.adoc[Math]. + +[[accompanying-premium-plugin-changes]] +== Accompanying Premium plugin changes + +The following premium plugin updates were released alongside {productname} {release-version}. + +=== Mentions + +The {productname} {release-version} release includes an accompanying release of the **Mentions** premium plugin. + +This **Mentions** release includes the following fix. + +==== Inline editor no longer grabs focus when it has a mention in it. +// #TINY-10725 + +Previously in **Mentions**, when using an inline editor where the initial content included a mention, the editor automatically grabbed input focus. This unexpected behavior occurred due to the adjustment of the selection range upon initialization. + +{productname} {release-version} resolves this issue, now, the selection range is only adjusted if the editor has focus. As a result, the inline editor no longer grabs focus on initialization when it has a mention in it. + +For information on the **Mentions** plugin, see: xref:mentions.adoc[Mentions]. + +=== Enhanced Code Editor + +The {productname} {release-version} release includes an accompanying release of the **Enhanced Code Editor** premium plugin. + +The **Enhanced Code Editor** includes the following fix: + +==== Inline mode didn't have tab navigation. +// #TINY-10780 + +Previously in {productname} 7.0, the **Enhanced Code Editor** was updated to codemirror 6, but the tab navigation was not implemented for the code editor view when `advcode_inline` was set. As a result, users who rely on keyboard navigation found it difficult to navigate the UI elements in the code editor view. + +In {productname} {release-version}, this issue has been fixed. Now, the tab navigation is implemented for the code editor view when `advcode_inline` is set. As a result, the code editor view UI elements can be navigated using the `tab` and `shift+tab` keys. + +For information on the **Enhanced Code Editor** plugin, see: xref:advcode.adoc[Enhanced Code Editor]. + +=== Accessibility Checker + +The {productname} {release-version} release includes an accompanying release of the **Accessibility Checker** premium plugin. + +**Accessibility Checker** includes the following improvement. + +==== Added new `A11ycheckStart`, `A11ycheckStop`, `A11ycheckIgnore`, `A11ycheckRepair` and `A11ycheckShowDetails` events. +// #TINY-10777 + +{productname} {release-version} introduces five new events within the **Accessibility Checker** premium plugin. These events capture usage statistics, offering valuable insights into the tool's internal usage for customers. + +The events include: + +[cols="1,2",options="header"] +|=== +|Name |Description +|A11ycheckStart |Fired when the Accessibility Checker is `opened` +|A11ycheckStop |Fired when the Accessibility Checker is `closed` +|A11ycheckIgnore |Fired when the `Ignore` button is pressed +|A11ycheckRepair |Fired when the `Repair` button is pressed +|A11ycheckShowDetails |Fired when the `Click for more info` button is pressed +|=== + +For information on the **Accessibility Checker** plugin, see: xref:a11ychecker.adoc[Accessibility Checker]. + +For information on handling events in {productname}, see: xref:events.adoc[Events]. + +=== Revision History + +The {productname} {release-version} release includes an accompanying release of the **Revision History** premium plugin. + +**Revision History** includes the following improvement. + +{productname} {release-version} introduces a new xref:revisionhistory.adoc#diff[diff] API from the **Revision History** plugin. This API allows the the user to compare two HTML strings. It does this by marking changes with annotations, so you can easily identify what's been added, removed, or changed. + +For information on the **Revision History** plugin, see: xref:revisionhistory.adoc[Revision History]. + + +[[improvements]] +== Improvements + +{productname} {release-version} also includes the following improvements: + +=== Included itemprop, itemscope, itemtype as valid HTML5 attributes in the core schema. +// #TINY-9932 + +Previously, using `itemprop`, `itemscope` and `itemtype` as valid HTML5 attributes within the editor was not supported. + +As a consequence, users faced difficulties in effectively working with content that used these attributes resulting in compatibility issues or data misrepresentation. + +{productname} {release-version} addresses this issue, now, the missed attributes have been added to the HTML5 schema, ensuring that users can now use content containing these attributes such as; + +[source, html] +---- +
    +

    Avatar

    + Director: James Cameron (born August 16, 1954) Science fiction Trailer +
    +---- + +As a result, `itemprop`, `itemscope` and `itemtype` are now considered valid HTML5 attributes within {productname}. + +=== Notification accessibility improvements: added tooltips, keyboard navigation and shortcut to focus on notifications. + +In previous versions of {productname}, an accessibility issue was identified that affected keyboard-only, specifically when a user receives a notification and they where unable to close it using the keyboard. + +As a consequence, users who rely on keyboard navigation or screen readers could only close the notifications via mouse "Click". + +{productname} {release-version} addressed this issue with the following changes: + +* Keyboard Shortcut: keyboard shortcut *Alt+F12* (or *⌥+F12*) was added, that allows users to now focus on notifications, providing a way for keyboard-only users to access and interact with them. +* Keyboard Navigation: allows keyboard navigation within the focusable elements in a notification, such as links and buttons, with *Tab* or *Shift+Tab*. +* Tooltip: added a tooltip to the `close` button of the notification, providing additional context for users who may need it. +* Link Styles: improved the styles of links within notifications, including `hover`, `focus`, `active`, and `focus-visible` states, to ensure that they are easily distinguishable and navigable. +* Screen Reader Announcement: content of a notification is announced by screen readers, making it easier for visually impaired users to access and understand the information. + +As a result of these changes notifications now more accessible for all users. + +=== New `index.js` file that includes all plugin resources. +// #TINY-10778 + +Previously, integrating {productname} and its premium plugins necessitated the separate inclusion of the `plugin.js` file along with the corresponding resource API-loaded CSS files. This approach often led to complications due to inconsistent naming conventions for our CSS files, making bundling a cumbersome process. + +To address this, {productname} {release-version} has included `index.js` files to each premium plugin, which will consolidate all necessary resources. + +As a result, when bundling from a distribution bundle or `.zip` build, by including all the {productname} imports for each plugin such as in a `all.js` file for example; + +[source, js] +---- +import './plugins/a11ychecker'; +import './plugins/advcode'; +import './plugins/advtable'; +import './plugins/advtemplate'; +---- +all the specific plugins will load without the need of any additional resources. + +For more information on bundling with {productname}, see xref:bundling-plugins.adoc[bundling plugins] + + +[[bug-fixes]] +== Bug fixes + +{productname} {release-version} also includes the following bug fixes: + +=== Fixed accessibility issue by removing duplicate `role="menu"` attribute from color swatches. +// #TINY-10806 + +The color swatch menu item, which is accessible via **Format** > **Text color** menu, previously contained nested block elements with the same ARIA role ('menu') in its HTML structure, which violated ARIA standards. + +{productname} {release-version} addresses this issue, by removing the duplicated role attribute, ensuring that the structure now aligns with ARIA guidelines and enhances usability for all users. + +=== Custom block elements with colon characters would throw errors. +// #TINY-10813 + +Previously, when `custom_elements` contained special characters such as colons, and these elements included a nested anchor element, an error would be thrown in the dev-console as the corresponding CSS selector was invalid due to the unescaped colon character. + +{productname} {release-version} addresses this issue, now, the CSS selector properly escapes special characters like colons, ensuring its validity. + +As a result, the error in the console is no longer displayed. + +=== Styles were not retained when toggling a list on and off. +// #TINY-10837 + +Previously, toggling a list into a paragraph that had a specific alignment style, did not retain the alignment state when the list was converted to the paragraph. + +{productname} {release-version} addresses this issue, by ensuring that the style attribute of the list item being transformed into a paragraph is carried over to the new paragraph. + +As a result, style attributes are now properly applied to the new paragraph after conversion when toggling lists. + +=== Improved the responsiveness of the custom view on small screens +// #TINY-10741 + +Previously, when opening a custom view on small screens or mobile devices, like the Revision History view, some header buttons and UI components were not completely visible, and in some cases, they were not accessible. For example, users might not have been able to close the view because the Close button was obscured on smaller screens. + +{productname} {release-version} addresses this issue by improving the layout's responsiveness to maximize usability. + +As a result, header buttons and UI components are more accessible and visible on small screens and mobile devices, ensuring that users can interact with the custom view without issues. + +For more information, see the xref:custom-view.adoc[Custom views] documentation. + +=== Video and audio elements could not be played on Safari. +// #TINY-10774 + +In earlier versions of {productname}, a problem occurred when users inserted a video or media element into a {productname} document while using Safari as the host browser. The issue caused media files to be unplayable in Safari. + +{productname} {release-version} resolves this problem by preventing events from propagating outside of the video element, which previously caused the playback issue. + +With this fix, users can now play video and audio elements on Safari without any issues. + +=== Open link context menu action did not work with selection surrounding a link. + +In earlier versions of {productname}, the `Open link` context menu action did not work when a link was part of a larger text selection. This meant that selecting a text block containing a link and then choosing `Open link` from the context menu would not result in any action. + +With {productname} {release-version}, this issue has been addressed. Now, when you select a block of text that includes a link and choose `Open link` from the context menu, the link will open in a new tab as expected. + +=== Open link context menu action was not enabled when an image with a link was selected. + +In previous versions of {productname}, the "Open link" context menu action wasn't available for links embedded in images. This limitation prevented users from using the context menu to open links directly from images, disrupting the usual workflow. + +With {productname} {release-version}, this issue has been resolved. The "Open link" context menu action is now enabled for links on images, allowing users to easily open them with a right-click. + +=== Improved support for Windows High Contrast themes in {productname}. +// #TINY-9810 / #TINY-9811 / #TINY-9873 / #TINY-10781 / #TINY-10782 + +Previously, in Windows High Contrast Mode, the colors of various elements in {productname}, such as toolbar icons, toolbar border, icon hover, focus, and active stage, were not correctly configured. This resulted in low to no color/contrast for the editor elements, leading to a poor user experience. + +In this fix, the following elements have been given the correct configuration to be visible and display high contrast when Windows High Contrast mode is enabled: + +* Checkbox border +* Dialog items +* Dropdown items +* Editor textarea border +* Floating toolbar outline +* Buttons and dropdown items (hover, focus, active state) +* Keyboard focus highlight +* Status bar items +* Toolbar border +* Toolbar icon +* Toolbar number input +* Tooltip +* Table picker UI + +The following item has been disabled when Windows High Contrast mode is enabled: + +* Table context menu arrow (cosmetic change only) + +The following items now maintain their color when Windows High Contrast mode is enabled: + +* Color picker, hue slider, RGBA preview, color swatch + +Additionally, the fix addresses the issue where the black background added to the placeholder text in Windows High Contrast mode was blocking the caret. The fix includes applying a `z-index` to the placeholder to unblock the caret and adding a specific color to the placeholder text when high contrast mode is enabled. This ensures that both the caret and placeholder text are now visible. + +These changes improve the user experience in {productname} by making UI elements, icons, texts, and user actions clearly visible in Windows High Contrast mode. + +=== Firefox not announcing the iframe title when `iframe_aria_text` was set. +// #TINY-10718 + +Previously, there was inconsistencies across browsers in announcing the `aria-label` for the editor body when the host browser was Firefox. + +As a consequence, the `aria-label` of the editor body was not announced. It was intended to be conveyed by the `iframe_aria_text` option but in this case, it was not being announced in Firefox, while Chrome and Safari functioned correctly. + +{productname} {release-version} addresses this issue. Now, the `iframe_aria_text` option is set to the **title** of the iframe specifically in Firefox, to ensure screen readers announce the option across all browsers. + +As a result, when navigating into the editor, screen readers in all supported browsers will now announce the correct label for the editor body. + +=== `ToggleToolbarDrawer` command did not toggle the toolbar in `sliding` mode when `+{skipFocus: true}+` parameter was passed. +// #TINY-10726 + +In link:https://www.tiny.cloud/docs/tinymce/6/6.4.1-release-notes/#added-skip_focus-check-to-the-toggletoolbardrawer-command[{productname} 6.4.1], a boolean `skipFocus` parameter for the `ToggleToolbarDrawer` command was introduced. This parameter manages whether the focus should be set on the overflow toolbar after it is toggled. However, a bug was identified with the `ToggleToolbarDrawer` command when used with `+{skipFocus: true}+`, specifically as `+editor.execCommand('ToggleToolbarDrawer', false, { skipFocus: true })+`. + +As a result, the bug caused the command to behave inconsistently based on the toolbar mode: + +* In `toolbar_mode: floating`, the command correctly preserved focus. +* In `toolbar_mode: sliding`, the command did not toggle the toolbar drawer at all. + +{productname} {release-version} addresses this issue. Now, when using the `ToggleToolbarDrawer` command with the `+{ skipFocus: true }+` argument in both `toolbar_mode: floating` and `toolbar_mode: sliding`, the command will toggle the toolbar drawer as expected while preserving focus. + +=== Dialog title was not announced in macOS VoiceOver, dialogs now use `aria-label` instead of `aria-labelledby` on macOS. +// #TINY-10808 + +In previous versions of {productname}, an issue was identified where **VoiceOver** was not announcing the dialog title when using the `+aria-labelledby+` attribute. + +As a consequence, without announcing the dialog title, users who rely on screen readers would not be informed about the purpose of the dialog. + +{productname} {release-version} addresses this issue. Now, {companyname}'s approach to announcing dialog titles is by switching from using `+aria-labelledby+` to using `+aria-label+` directly on the dialog title element itself. + +As a result, the `+aria-label+` attribute, **VoiceOver** will now announce the dialog title as expected. + +=== Notification width was not constrained to the width of the editor. +// #TINY-10886 + +Previously, when opening a notification containing a large amount of text or when one was displayed by the editor, the notification was not constrained to the width of the editor. + +As a consequence, the notification popup would exceed the fixed width of the editor window. + +In {productname} {release-version}, this issue is resolved by ensuring that notifications do not exceed the width of the editor. + +=== Dialog title markup changed to use an `h1` element instead of `div`. +// #TINY-10800 + +Previously, the dialog component's title was wrapped in a `
    ` element, visually appearing as a heading and functioning as the main heading for the dialog. However, without the title being semantically marked up as a heading element, screen reader users may struggle to understand the purpose of the dialog box and navigate its content. + +{productname} {release-version} addresses this issue by updating the dialog title markup to use an `

    ` element, ensuring that the title is semantically identified as a heading. This improves the accessibility experience for users by helping screen readers and other assistive technologies understand the structure of the page and navigate its content more easily. + +=== Removed `aria-pressed` from the `More` button in sliding toolbar mode and replaced it with `aria-expanded` +// #TINY-10795 + +Previously, an issue was identified with the toolbar overflow button **More** button specifically in `+toolbar_mode: 'sliding'+` mode. The button uses the aria-pressed attribute, which is not appropriate for this scenario. + +As a consequence, the aria-pressed attribute was set incorrectly, which prevented screen readers from announcing whether the additional toolbar was in either a expanded or collapsed state. + +{productname} {release-version} addresses this issue. Now, the `aria-pressed` attribute has been replaced with `aria-expanded` attribute. This attribute will be set to `+true+` when the overflow content is visible and `+false+` when it's hidden. + +As a result, screen readers will now announce the expanded/collapsed state of the overflow toolbar correctly. + +[NOTE] +This fix only applies to toolbars configured with `+toolbar_mode: 'sliding'+`. + +=== Fullscreen mode now prevents focus from leaving the editor. +// #TINY-10597 + +Previously, when using the editor in full screen with the xref:fullscreen.adoc[Full Screen] plugin active, users were still able to tab out of the editor window and access content behind it. This created an accessibility issue for keyboard-only users as the editor window could lose focus unintentionally, shifting it to elements outside the editor. Since these elements are hidden in fullscreen mode, keyboard users might have struggled to navigate back to the editor. + +In {productname} {release-version}, the Full Screen plugin has been modified to prevent users from tabbing out of the editor window while in full screen mode. Users are now confined to the editor window while in full screen mode, ensuring focus remains on the editor content and preventing accidental navigation away from the editing area. + +[[security-fixes]] +== Security fixes + + +{productname} {release-version} includes one fix for the following security issue: + +The following server-side component has been updated to include dependency updates addressing the following security issues. + +* https://nvd.nist.gov/vuln/detail/CVE-2024-29025[CVE-2024-29025] + +This update is considered as a **Medium** severity vulnerability fix. + +For information on the server-side components updates, see: xref:#accompanying-premium-self-hosted-server-side-component-changes[Accompanying Premium self-hosted server-side component changes]. + +include::partial$misc/admon-no-functionality-changes-in-updated-server-side-components.adoc[] \ No newline at end of file diff --git a/modules/ROOT/pages/7.1.1-release-notes.adoc b/modules/ROOT/pages/7.1.1-release-notes.adoc new file mode 100644 index 0000000000..dcfed4d2dc --- /dev/null +++ b/modules/ROOT/pages/7.1.1-release-notes.adoc @@ -0,0 +1,122 @@ += {productname} {release-version} +:release-version: 7.1.1 +:navtitle: {productname} {release-version} +:description: Release notes for {productname} {release-version} +:keywords: releasenotes, new, changes, bugfixes +:page-toclevels: 1 + +include::partial$misc/admon-releasenotes-for-stable.adoc[] + + +[[overview]] +== Overview + +{productname} {release-version} was released for {enterpriseversion} and {cloudname} on Wednesday, May 22^nd^, 2024. + +These release notes provide an overview of the changes for {productname} {release-version}, including: + +* xref:accompanying-premium-plugin-changes[Accompanying Premium plugin changes] +* xref:bug-fixes[Bug fixes] + + +[[accompanying-premium-plugin-changes]] +== Accompanying Premium plugin changes + +The following premium plugin updates were released alongside {productname} {release-version}. + + +=== Math Plugin + +The {productname} {release-version} release includes an accompanying release of the **Math** premium plugin. + +This **Math** premium plugin release includes the following fix: + +==== Clearing the formula input and then saving didn't remove the element. + +In the initial release of the Math Plugin, {productname} did not remove the selected formula and element when the user saved an empty formula. + +As a consequence, when the user cleared the formula and clicked "save", the selected formula and element remained in the editor. + +{productname} {release-version} addresses this issue. Now, when a user has a formula selected, clears it, and clicks "save", the selected formula and element are properly removed from the editor. + +For information on the **Math** plugin, see: xref:math.adoc[Math]. + +=== Enhanced Tables + +The {productname} {release-version} release includes an accompanying release of the **Enhanced Tables** premium plugin. + +This **Enhanced Tables** plugin release includes the following fix: + +==== The sort algorithm would sometimes incorrectly compare words that start with a digit. +// #TINY-10421 + +Previously in **Enhanced Tables**, when trying to sort a table where the cells contained text that started with numbers followed by words, the table would only consider the number part of the text when sorting. This would cause the table to incorrectly sort the words. + +For example, when trying to sort the following table by column ascending (A-Z): + +[cols="1", options="header"] +|=== +| Column 1 + +| 3banana +| 3apple +|=== + +The table would not sort them correctly due to it only considering the number part, so `3banana` would remain above `3apple`, even though `3apple` should come before `3banana` alphanumerically. + +This has been fixed in {productname} {release-version}. Now, when sorting a table with text that starts with a digit, the table considers the whole word not just the digits part. As a result, the table now correctly sorts words that start with a digit. + +For information on the **Enhanced Tables** plugin, see: xref:advtable.adoc[Enhanced Tables]. + + +[[bug-fixes]] +== Bug fixes + +{productname} {release-version} also includes the following bug fixes: + +=== Insert/Edit image dialog lost focus after the image upload completed. +// #TINY-10885 + +Previously, when using the {productname} editor's `Insert/Edit Image` dialog and uploading an image from the 'Upload' tab, the focus would move outside of the dialog after the image was successfully uploaded. + +As a consequence, users were unable to navigate within the dialog using the tab key. + +In {productname} {release-version}, this issue has been addressed. Now, the focus remains inside the `Insert/Edit Image` dialog after uploading an image, allowing users to navigate within the dialog using the keyboard as expected. + +=== Deleting into a list from a paragraph that has an `img` tag could cause extra inline styles to be added. +// #TINY-10892 + +Previously in {productname}, there was an issue with lists when the host browser was Google Chrome. The issue occurred when there was content with a list followed by a paragraph that contained an `img` element. If the cursor was placed at the start of the paragraph and the backspace key was pressed, the content of the paragraph would be merged into the list item, but the `img` element and other neighboring elements would get undesired inline font styles. + +This issue has been fixed in {productname} {release-version}. Now, a check has been added to prevent the inline styles from being added following this action. As a result, the resulting HTML no longer gets undesired inline styles, and the behavior is as expected. + +=== Resolved an issue where emojis configured with the `emojiimages` database were not loading correctly due to a broken CDN. +// #TINY-10878 + +Recently, the original CDN url {productname} used for the twitter emoji database was discontinued. + +As a consequence, all emoji's would not render, however this issue was resolved by the CDN owner by a redirect to an active link + +{productname} {release-version} addresses this issue. Now, {productname} has set the default CDN link to the actively maintained one. + +As a result, emoji's now render in all occasion without redirecting. + +For more information about these changes, see xref:emoticons.adoc#emoticons_images_url[Emoticons (emoticons_images_url)]. + +=== Iframes in dialogs were not rendering rounded borders correctly. +// #TINY-10901 + +Previously, when opening a dialog with an `iframe` element that had a different background color than the dialog, the corners of the dialog did not round off as expected as the border radius was applied to the `iframe` parent element and not the `iframe`. + +{productname} {release-version} addresses this issue by additionally applying the border radius to the `iframe` itself, ensuring that it renders correctly. + +As a result, borders now render properly, and the background of the `iframe` is no longer visible through to the parent dialog. + +=== Autocompleter possible values are no longer capped at a length of 10. +// #TINY-10942 + +Previously in {productname}, the Autocompleter option values were constrained to lengths of less than 10. + +As a consequence, the Autocompleter popover would close after only one value being selected if the selected value was greater than or equal to 10. This created a limitation for users who needed to select multiple values consecutively with lengths greater than 10. + +In {productname} {release-version}, this hardcoded limit of 10 has been removed. The Autocompleter now allows selection of multiple options consecutively with values of any length, while keeping the same popover open. \ No newline at end of file diff --git a/modules/ROOT/pages/7.1.2-release-notes.adoc b/modules/ROOT/pages/7.1.2-release-notes.adoc new file mode 100644 index 0000000000..a60fcae1bb --- /dev/null +++ b/modules/ROOT/pages/7.1.2-release-notes.adoc @@ -0,0 +1,57 @@ += {productname} {release-version} +:release-version: 7.1.2 +:navtitle: {productname} {release-version} +:description: Release notes for {productname} {release-version} +:keywords: releasenotes, new, changes, bugfixes +:page-toclevels: 1 + +include::partial$misc/admon-releasenotes-for-stable.adoc[] + +[[overview]] +== Overview + +{productname} {release-version} was released for {enterpriseversion} and {cloudname} on Wednesday, June 05^th^, 2024. These release notes provide an overview of the changes for {productname} {release-version}, including: + +* xref:accompanying-premium-plugin-changes[Accompanying Premium plugin changes] +* xref:bug-fixes[Bug fixes] + + +[[accompanying-premium-plugin-changes]] +== Accompanying Premium plugin changes + +The following premium plugin updates were released alongside {productname} {release-version}. + +=== Math Plugin + +The {productname} {release-version} release includes an accompanying release of the **Math** premium plugin. + +This **Math** premium plugin release includes the following fix: + +==== Math icon state was not set to active on math element selection. +// #TINY-10931 + +Previously, the Math icon was not set to active when a math element was selected within the editor. As a consequence, users had no visual indication that a math element was selected or that it could be edited by selecting it and then clicking the toolbar button. + +{productname} {release-version} addresses this issue. Now, when any Math element is selected, the button's active state is triggered. + +For more information on the **Math** plugin, see: xref:math.adoc[Math]. + + +[[bug-fixes]] +== Bug fixes + +{productname} {release-version} also includes the following bug fixes: + +=== CSS color values set to `transparent` were incorrectly converted to `+#000000+`. +// #TINY-10916 + +Previously, transparent color values were incorrectly converted to `+#000000+`, deviating from the behavior observed in earlier major versions. Additionally, {productname} did not export the last two digits of the hex string, so the alpha value was lost, causing transparent to be converted to `+#000000+`. + +{productname} {release-version} addresses this issue by removing the check that handles transparency, therefore retaining the alpha component. As a result, the transparent property will be retained as a transparent string instead of being converted to other values. This change is consistent with the behavior in {productname} v5 and v6. + +=== Acronyms were not managed correctly. +// #TINY-10904 + +Previously, acronyms were not managed correctly, which caused false positive results with the Spell Checker premium plugin. In this case, the check was excluding the period at the end when separating words, even when checking acronyms. As a consequence, the Spell Checker Premium plugin would identify acronyms without the trailing period, therefore highlighting them as errors. + +{productname} {release-version} addresses this issue. Now, if the word is an acronym, {productname} includes the next character if it is a period. As a result, acronyms are now managed correctly, and the Spell Checker retrieves the correct word (with the period included) and provides accurate results. \ No newline at end of file diff --git a/modules/ROOT/pages/7.2-release-notes.adoc b/modules/ROOT/pages/7.2-release-notes.adoc new file mode 100644 index 0000000000..49e7b4eec5 --- /dev/null +++ b/modules/ROOT/pages/7.2-release-notes.adoc @@ -0,0 +1,386 @@ += TinyMCE {release-version} +:release-version: 7.2 +:navtitle: TinyMCE {release-version} +:description: Release notes for TinyMCE {release-version} +:keywords: releasenotes, new, changes, bugfixes +:page-toclevels: 1 + +include::partial$misc/admon-releasenotes-for-stable.adoc[] + + +[[overview]] +== Overview + +{productname} {release-version} was released for {enterpriseversion} and {cloudname} on Wednesday, June 19^th^, 2024. These release notes provide an overview of the changes for {productname} {release-version}, including: + +* xref:accompanying-premium-self-hosted-server-side-component-changes[Accompanying Premium self-hosted server-side component changes] +* xref:accompanying-premium-plugin-changes[Accompanying Premium plugin changes] +* xref:improvements[Improvements] +* xref:additions[Additions] +* xref:changes[Changes] +* xref:bug-fixes[Bug fixes] +* xref:security-fixes[Security fixes] + + +[[accompanying-premium-self-hosted-server-side-component-changes]] +== Accompanying Premium self-hosted server-side component changes + +The {productname} {release-version} release includes accompanying changes affecting the {productname} **self-hosted** services for the following plugin: + +* **Spell Checker** plugin `tinymcespellchecker`. + +For information on: + +* The **Spell Checker** plugin, see: xref:introduction-to-tiny-spellchecker.adoc[Spell Checker plugin]. +* Deploying the **server-side** components, see: xref:introduction-to-premium-selfhosted-services.adoc[Server-side component installation]. + +The Java server-side component has been updated to the following version: + +* `ephox-spelling.war`: 2.119.6 + +=== Updating the self-hosted server-side components + +The new versions of the server-side services provide updates for the Java-based server-side components. To deploy the updated version of the server-side components: + +. Update your Java Application Server to the minimum required version: + +include::partial$misc/supported-application-servers.adoc[] + +. Replace the existing server-side `.war` files with the `.war` files bundled with {productname} {release-version} or later. + +For information on: + +* Deploying the server-side components, see: xref:introduction-to-premium-selfhosted-services.adoc[Server-side component installation]. +* Deploying the server-side components using Docker, see: xref:bundle-intro-setup.adoc[Containerized service deployments]. + +include::partial$misc/admon-no-functionality-changes-in-updated-server-side-components.adoc[] + + +[[accompanying-premium-plugin-changes]] +== Accompanying Premium plugin changes + +The following premium plugin updates were released alongside {productname} {release-version}. + +=== Accessibility Checker + +The {productname} {release-version} release includes an accompanying release of the **Accessibility Checker** premium plugin. + +**Accessibility Checker** includes the following fix. + +==== Temporary elements such as incorrect spelling highlights were interfering with accessibility checking. +// #TINY-10771 + +Previously, elements with certain attributes, such as highlights from the xref:introduction-to-tiny-spellchecker.adoc[Spell Checker] plugin, were not being ignored by some checks in the Accessibility Checker plugin. + +As a consequence, these checks were not functioning correctly and were missing accessibility failures that should have been detected by the Accessibility Checker plugin. + +{productname} {release-version} addresses this issue. Now, the checks have been modified to ignore all elements that should be excluded, such as those with specific attributes added by the Spell Checker plugin. + +As a result, the Accessibility Checker now accurately identifies the accessibility issues in the content, even when temporary elements are present. + +For information on the **Accessibility Checker** premium plugin, see: xref:a11ychecker.adoc[Accessibility Checker]. + +=== Image Editing + +The {productname} {release-version} release includes an accompanying release of the **Image Editing** premium plugin. + +**Image Editing** includes the following improvement. + +==== Dialog slider components now emit an onChange event when using arrow keys. +// #TINY-10428 + +Previously in the Edit Image dialog, when using the left/right arrow keys to adjust settings with sliders, the slider component did not properly update the image preview. As a consequence, users were unable to use the keyboard to update image properties controlled by sliders such as Brightness, Contrast, Color Levels, and Gamma settings. + +In {productname} {release-version}, this issue has been resolved. Now, the slider component emits an `onChange` event when the slider value is adjusted using the left/right arrow keys. As a result, users can now update the Edit Image dialog sliders using the keyboard. + +For information on the **Image Editing** premium plugin, see: xref:editimage.adoc[Image Editing]. + +=== Math + +The {productname} {release-version} release includes an accompanying release of the **Math** premium plugin. + +**Math** includes the following fix. + +==== Math preview was not rendered with the colors from the current skin. +// #TINY-10900 + +Previously, the **Math** preview did not follow the editor skin UI colors. As a consequence, the equation preview dialog was always rendered with black text on white background even if the UI skin was a dark skin. + +This has been addressed in {productname} {release-version}. Now, the editor renders the equation preview inline with the **Math** dialog, and not using an iframe, so that the preview container's colors are inherited from the dialog. As a result, the text color and background color of the equation preview container now follows the editor skin UI colors. + +For information on the **Math** premium plugin, see: xref:math.adoc[Math]. + +=== PowerPaste + +The {productname} {release-version} release includes an accompanying release of the **PowerPaste** premium plugin. + +**PowerPaste** includes the following addition. + +==== New option to disable the auto-linking feature in PowerPaste. +// #TINY-10962 + +Previously in {productname}, it was not possible to configure PowerPaste to exclude converting text that resembles a URL into a hyperlink. As a consequence, all text that resembled a URL was automatically converted into a hyperlink when pasting plain text or rich text from HTML. + +In {productname} {release-version}, the `powerpaste_autolink_urls` option has been introduced. This option allows users to customize the auto-linking behavior on paste. As a result, users can now disable the auto-linking feature in PowerPaste. + +NOTE: This option is enabled by default and does not exhibit any change in behavior when upgrading to {productname} {release-version}. + +For more information on the `powerpaste_autolink_urls` option, refer to: xref:powerpaste-options.adoc#powerpaste_autolink_urls[PowerPaste - powerpaste_autolink_urls]. + +For information on the **PowerPaste** premium plugin, see: xref:introduction-to-powerpaste.adoc[PowerPaste]. + +=== Revision History + +The {productname} {release-version} release includes an accompanying release of the **Revision History** premium plugin. + +**Revision History** includes the following addition. + +==== New `revisionhistory_fetch_revision` option to support updating a revision. +// #TINY-10362 + +In {productname} {release-version}, a new `revisionhistory_fetch_revision` option has been added to enable updating a revision after the initial fetch. If configured, when a revision is selected, the plugin uses this option to update the selected or closest revision that has no content. + +NOTE: As part of this addition, the `content` property is now optional. For the fetched revisions, an empty string is considered as valid content. + +IMPORTANT: The `revisionhistory_fetch` option must be configured when using the new `revisionhistory_fetch_revision` option, as it is required to provide the initial revisions. + +For more information on the `revisionhistory_fetch_revision` option, see: xref:revisionhistory.adoc#revisionhistory_fetch_revision[Revision History - revisionhistory_fetch_revision]. + +This option is useful for handling revisions with large content or for loading content only when needed. + +For information on the **Revision History** premium plugin, see: xref:revisionhistory.adoc[Revision History]. + +=== Spell Checker + +The {productname} {release-version} includes an accompanying release of the **Spell Checker** premium plugin. + +**Spell Checker** includes the following improvement. + +==== Enhanced spelling service to support spellchecking for additional languages using customer-provided Hunspell dictionaries. +// #TCLOUD-4297 + +{productname} {release-version} introduces the following improvements for specified languages: + +* Medical English (US) was updated from `"en_US-medical"` to include `"en-medical"` as an additional code. +* Dutch was updated from `"nl"` to `"nl, nl_NL"`. +* German was updated from `"de"` to `"de, de_DE"`. +* Italian was updated from `"it"` to `"it, it_IT"`. +* Norwegian Bokmål was updated from `"nb"` to `"nb, nb_NO"`. +* Portuguese (Brazil) was updated from `"pt"` to `"pt, pt_BR"`. +* Swedish was updated from `"sv"` to `"sv, sv_SE"`. + +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]. + + +[[improvements]] +== Improvements + +{productname} {release-version} also includes the following improvements: + +=== Accessibility for element path buttons, added tooltip to describe the button and removed incorrect `aria-level` attribute. +// #TINY-10891 + +In previous versions of {productname}, Axe-DevTools (web accessibility testing extension) identified that the element path buttons contained an invalid `aria-level` attribute that is not permitted on `role="button"` elements. As a consequence, screen readers were unable to describe the purpose of these buttons to visually impaired users. + +{productname} {release-version} addresses this issue by adding tooltips to the buttons in the element path which now provides a description of the button's functionality. In addition, the `aria-describedby` attribute has been added when the tooltip is focused, allowing screen readers to announce and describe the purpose of the button when in-focus. Now, a tooltip appears when hovering over an element path button with the mouse or focusing on it using the keyboard. + +[NOTE] +With this change {productname} also removed of the incorrect `aria-level` attribute that was added to these buttons previously. This change ensures that the editor complies with the "Elements must only use supported ARIA attributes" rule. + +=== Improve merging of inserted inline elements by removing nodes with redundant inheritable styles. +// #TINY-10869 + +In previous versions of {productname}, when inserting inline elements into existing inline elements, the editor would attempt to merge the contents of identical inline elements. Inserted inline elements would only be removed if they were identical to inline parents of the element being inserted into, and this check would only occur until it found a non-inheritable style or a conflict. + +In {productname} {release-version}, this behavior has been improved. Now, inserted inline elements are removed when they contain no non-inheritable styles, have only one child element, and either: + +* Contain no styles which are inherited in a child element, or +* Are identical to any inline parent of the selected element and don't contain any styles which conflict with another inserted parent's styles. + +As a result, many redundant inline elements are automatically stripped when inserted into the editor, while maintaining their appearance and overall element structure. + +=== Improved Search & Replace dialog accessibility by changing placeholders to labels. +// #TINY-10871 + +In previous versions of {productname}, the Search & Replace dialog inputs were initially implemented with placeholders. + +As a consequence, the dialog was less accessible because the input placeholders were hidden once the user started typing. This posed difficulties for users who rely on consistent visual cues for context. + +{productname} {release-version} addresses this issue. Now, placeholders have been replaced by input labels located above the input fields. + +As a result, the Search & Replace dialog is now more accessible and there are input labels that remain visible at all times. + + +[[additions]] +== Additions + +{productname} {release-version} also includes the following additions: + +=== Added `options.debug` API that logs the initial raw editor options to console. +// #TINY-10605 + +This release introduces a new `options.debug` API that logs the initial raw editor options passed to `tinymce.init` to the console. This API is useful for debugging and troubleshooting issues with the editor, especially when dynamically composing many editor options from different sources. + +Usage: + +[source,js] +---- +tinymce.activeEditor.options.debug(); +---- + +The following data types are logged exactly as they are passed to `tinymce.init`: + +* `string` +* `number` +* `boolean` +* `object` +* `array` +* `null` + +All other data types not mentioned above are logged as `[object X]` where "X" is the type of the object, such as: + +* `Function` +* `Undefined` +* `RegExp` +* `Promise` +* and more + +==== Example: using the `options.debug` API: + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + height: 500, + paste_as_text: true, + context_menu: [ 'image', 'lists' ], + menu: { insert: { title: 'Insert', items: 'table | image | accordion' }}, + inline: null, + myUndefined: undefined, + init_instance_callback: (editor) => editor.options.debug(), +}); +---- + +The above code will log the following to the console: + +[source,js] +---- +{ + selector: 'textarea', + height: 500, + paste_as_text: true, + context_menu: [ 'image', 'lists' ], + menu: { insert: { title: 'Insert', items: 'table | image | accordion' }}, + inline: null, + myUndefined: [object Undefined], + init_instance_callback: [object Function], +} +---- + +=== Added `referrerpolicy` as a valid attribute for an iframe element. +// #TINY-10374 + +Previously in {productname}, the `referrerpolicy` attribute was not considered as valid for iframe elements. In {productname} {release-version}, this attribute has been added to the schema, allowing users to include the `referrerpolicy` attribute in iframes. + +=== Added support for querying the state of the `mceTogglePlainTextPaste` command. +// #TINY-10938 + +In {productname} {release-version}, the `mceTogglePlainTextPaste` command has been updated to support querying its state. This allows users to determine whether the paste-as-text mode is currently active. + +The `mceTogglePlainTextPaste` command can be queried using the following API: + +[source,js] +---- +tinymce.activeEditor.queryCommandState('mceTogglePlainTextPaste'); +---- + + +[[changes]] +== Changes + +{productname} {release-version} also includes the following change: + +=== Replaced {companyname} branding logo with `Build with TinyMCE` text and logo. +// #TINY-11001 + +Previously, the branding logo in the {productname} status bar was set to the {companyname} logo. + +Now, the branding logo in the {productname} status bar is set to `Build with` and the {productname} logo. + + +[[bug-fixes]] +== Bug fixes + +{productname} {release-version} also includes the following bug fixes: + +=== Deleting in a `div` with preceding `br` elements would sometimes throw errors. +// #TINY-10840 + +Previously, when deleting the last character in a `
    ` element with preceding `
    ` elements, an error _(Uncaught DOMException: Failed to execute 'setStart' on 'Range': There is no child at offset)_ was thrown to the console, and the `
    ` element was incorrectly converted to a `

    ` element. + +{productname} {release-version} addresses this issue. The delete logic has been modified to properly handle this situation. After the fix, the `

    ` element remains a `
    `, and no error is thrown to the console when deleting the last character. + +=== `autoresize_bottom_margin` was not reliably applied in some situations. +// #TINY-10793 + +In {productname} 6.4.1, a link:https://www.tiny.cloud/docs/tinymce/6/6.4.1-release-notes/#editor-increases-the-height-indefinitely-when-using-autoresize-with-content_css-document[fix] addressed an issue where the editor's height would increase indefinitely when using the xref:autoresize.adoc[Autoresize] plugin with `content_css` set to `document`. This fix inadvertently caused a regression, resulting in the editor occasionally failing to apply bottom padding correctly. + +As a result, the `autoresize_bottom_margin` was not consistently applied in certain scenarios. + +In {productname} {release-version}, this issue has been resolved, and the `autoresize_bottom_margin` is now reliably applied. + +=== Fixed cases where adding a newline around a br, table or img would not move the cursor to a new line. +// #TINY-10384 + +In previous versions of {productname}, an issue affecting cursor positioning was identified when adding new lines around specific HTML elements such as `
    `, ``, and `` tags. + +As a consequence, the cursor failed to move to a new line when adding a newline around these elements, resulting in unexpected behavior while editing content within the editor. + +With the release of {productname} {release-version}, this issue has been addressed. The editor now accurately interprets the presence of spaces or newlines after certain HTML elements. As a result, cursor movement behaves as expected when adding new lines around `
    `, `
    `, and `` tags. + +=== Focusing on `contenteditable="true"` element when using `editable_root: false` and inline mode caused selection to be shifted. +// #TINY-10820 + +Previously in {productname}, there was an issue where focusing on `contenteditable="true"` elements, such as media elements, while using `editable_root: false` and inline mode would cause the selection to be shifted. When saving the media dialog, the focus would first shift to the editor to ensure the changes are inserted into the editor. However, this caused the selection to change, leading to a duplicated element being inserted into the editor. + +This issue has been resolved in {productname} {release-version}. Now, after focusing on the `contenteditable="true"` root, the editor bookmark is restored, ensuring that the selection remains at the correct location when saving the media. + +As a result, when focusing on `contenteditable="true"` elements in inline mode with `editable_root: false`, the selection will remain correct after saving the media dialog. This prevents the duplication of elements and ensures that the changes are inserted at the intended location within the editor. + +=== Corrected the `role` attribute on listbox dialog components to `combobox` when there are no nested menu items. +// #TINY-10807 + +Previously in {productname}, the `role` attribute on listbox dialog components was set to `menu` when there were no nested menu items. This caused confusion for users, as screen readers would announce non-hierarchical listboxes as menu buttons. + +In {productname} {release-version}, this issue has been addressed by setting the `role` attribute to `combobox` when there are no nested menu items. + +As a result, screen readers now announce the listbox as a combobox and the menu it opens as a listbox. This improvement ensures that the currently selected value is announced when tabbing to the select box, and the selected items are announced as a listbox. + +[[security-fixes]] +== Security fixes + +{productname} {release-version} includes two fixes for the following security issues: + +=== HTML entities that were double decoded in `noscript` elements caused an XSS vulnerability. +// #TINY-11019 + +A https://owasp.org/www-community/attacks/xss/[cross-site scripting] (XSS) vulnerability was discovered in {productname}'s content parsing code. This allowed specially crafted `noscript` elements containing malicious code to be executed when that content was loaded into the editor. + +This vulnerability has been patched in {productname} {release-version}, {productname} 6.8.4 and {productname} 5.11.0 LTS by ensuring that content within `noscript` elements are properly parsed. + +GHSA: link:https://github.com/tinymce/tinymce/security/advisories/GHSA-w9jx-4g6g-rp7x[GitHub Advisory]. + +CVE: link:https://www.cve.org/CVERecord?id=CVE-2024-38357[CVE-2024-38357]. + +NOTE: Tiny Technologies would like to thank link:https://malavkhatri.com/[Malav Khatri (devilbugbounty)] and another reporter for discovering this vulnerability. + +=== It was possible to inject XSS HTML that was not matching the regexp when using the `noneditable_regexp` option. +// #TINY-11022 + +A https://owasp.org/www-community/attacks/xss/[cross-site scripting] (XSS) vulnerability was discovered in {productname}'s content extraction code. When using the `noneditable_regexp` option, specially crafted HTML attributes containing malicious code were able to be executed when content was extracted from the editor. + +This vulnerability has been patched in {productname} {release-version}, {productname} 6.8.4 and {productname} 5.11.0 LTS by ensuring that, when using the `noneditable_regexp` option, any content within an attribute is properly verified to match the configured regular expression before being added. + +GHSA: link:https://github.com/tinymce/tinymce/security/advisories/GHSA-9hcv-j9pv-qmph[GitHub Advisory]. + +CVE: link:https://www.cve.org/CVERecord?id=CVE-2024-38356[CVE-2024-38356]. \ No newline at end of file diff --git a/modules/ROOT/pages/7.2.1-release-notes.adoc b/modules/ROOT/pages/7.2.1-release-notes.adoc new file mode 100644 index 0000000000..da60dc9cc3 --- /dev/null +++ b/modules/ROOT/pages/7.2.1-release-notes.adoc @@ -0,0 +1,84 @@ += {productname} {release-version} +:release-version: 7.2.1 +:navtitle: {productname} {release-version} +:description: Release notes for {productname} {release-version} +:keywords: releasenotes, new, changes, bugfixes +:page-toclevels: 1 + +include::partial$misc/admon-releasenotes-for-stable.adoc[] + + +[[overview]] +== Overview + +{productname} {release-version} was released for {enterpriseversion} and {cloudname} on Wednesday, July 3^rd^, 2024. These release notes provide an overview of the changes for {productname} {release-version}, including: + +* xref:bug-fixes[Bug fixes] + + +[[bug-fixes]] +== Bug fixes + +{productname} {release-version} also includes the following bug fixes: + +=== Text content could move unexpectedly when deleting a paragraph. +// #TINY-10590 + +Previously, pressing backspace within specific block elements could cause the HTML structure to change unexpectedly. This issue arose because pressing the backspace key would merge content before and after a tag boundary, leading to unintended restructuring of elements within a `+
    +`. + +.Example of Original Content Structure +[source, html] +---- +
    Hi ,

    Thank you for contacting support.
    +

    Pasted text.

    +

    Best regards.
    +
    Bli ,

    Thank you for contacting support.
    +

    Pasted text.

    +

    Best regards.
    +---- + +after pressing backspace, the content was merged into a single `+
    +`, which resulted in a disrupted layout and structure such as the below. + +.Example of Unintended Merged Content Structure After Pressing Backspace +[source, html] +---- +
    +

    Pasted text.Hi ,

    Thank you for contacting support.

    +

    Best regards.
    +
    Bli ,

    Thank you for contacting support.
    +

    Pasted text.

    +

    Best regards.
    +---- + +As a consequence, the content before the `+

    +` tag was merged into the `+

    +` tag. + +In {productname} {release-version}, this issue has been addressed by preventing the merging of content across tag boundaries, ensuring the intended HTML structure is maintained. In addition to this change, adjustments were made to handle line breaks more effectively. + +As a result, pressing backspace no longer reduces the number of `+
    +` tags before `+

    +` tag, such as "Best regards," preserving the original HTML layout. + +=== Long translations of the bottom help text would cause minor graphical issues. +// #TINY-10961 + +Previously, resizing the editor caused the statusbar to render the help text incorrectly if it was too long. This was particularly problematic for long translations, as the statusbar did not handle extended text properly, leading to visual misalignment and hiding important elements. + +To fix this, the statusbar's CSS was updated to handle this by retaining the help text on one line and hiding any overflowing text. + +As a result, the help text now overflows without disrupting the statusbar layout, ensuring a consistent appearance and visibility. + +=== Open Link button was disabled when selection partially covered a link or when multiple links were selected. +// #TINY-11009 + +Previously, the “Open link” toolbar button and menu item were disabled when a link was partially selected or when the selection included multiple links. + +{productname} {release-version} addresses this issue. Now, the "Open link" toolbar button and menu item are enabled when any part of a link or multiple links are within the selection. + +=== Cursor would shift to the start of the editor body when focus was shifted to a noneditable cell of a table. +// #TINY-10127 + +Previously in {productname}, when the editor did not have focus and a non-editable cell of a table was clicked, the selection was set to the non-editable cell of the table instead of the offscreen element. + +As a consequence, placing the selection on the non-editable cell caused the cursor to be incorrectly placed in the editor body and unexpectedly scroll to the top of the editor. + +In {productname} {release-version}, the selection handling logic has been updated. Now, the selection is maintained on the offscreen div when necessary to prevent the selection from being changed. + +As a result, the selection correctly shifts to the offscreen element when required, maintaining the cursor position and no longer causing the editor to scroll unexpectedly. \ No newline at end of file diff --git a/modules/ROOT/pages/7.3-release-notes.adoc b/modules/ROOT/pages/7.3-release-notes.adoc new file mode 100644 index 0000000000..05929c129d --- /dev/null +++ b/modules/ROOT/pages/7.3-release-notes.adoc @@ -0,0 +1,370 @@ += {productname} {release-version} +:release-version: 7.3 +:navtitle: {productname} {release-version} +:description: Release notes for {productname} {release-version} +:keywords: releasenotes, new, changes, bugfixes +:page-toclevels: 1 + +include::partial$misc/admon-releasenotes-for-stable.adoc[] + + +[[overview]] +== Overview + +{productname} {release-version} was released for {enterpriseversion} and {cloudname} on Wednesday, August 7^th^, 2024. These release notes provide an overview of the changes for {productname} {release-version}, including: + +* 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] +* xref:additions[Additions] +* xref:bug-fixes[Bug fixes] + + +[[accompanying-premium-plugin-changes]] +== Accompanying Premium plugin changes + +The following premium plugin updates were released alongside {productname} {release-version}. + +=== AI Assistant + +The {productname} {release-version} release includes an accompanying release of the **AI Assistant** premium plugin. + +**AI Assistant** includes the following addition. + +==== Add "Translate" options to AI Assistant default shortcuts. + +The **AI Assistant** required an enhancement to support in-editor translation capabilities. + +{productname} {release-version} introduces a new translate dropdown, that has been added to the **AI Assistant's** default shortcuts. The dropdown includes language options: English, Spanish, Portuguese, German, French, Norwegian, Ukrainian, Japanese, Korean, Simplified Chinese, Hebrew, Hindi, and Arabic. + +As a result, users can seamlessly translate content within the editor into multiple languages with a single "click". + +For information on the **AI Assistant** premium plugin, see: xref:ai.adoc[AI Assistant]. + +=== Enhanced Code Editor + +The {productname} {release-version} release includes an accompanying release of the **Enhanced Code Editor** premium plugin. + +**Enhanced Code Editor** includes the following improvements. + +==== Added new option `advcode_prettify_getcontent` to Enhanced Code Editor. + +Previously, formatting HTML content within the **Enhanced Code Editor** view or retrieving formatted HTML from the `editor.getContent` API as not possible. + +To resolve this issue, {productname} {release-version} introduces a new `advcode_prettify_getcontent` option. When enabled (default: false), `editor.getContent` will return formatted HTML. Additionally, invoking `+editor.getContent({ prettify: true })+` will retrieve formatted HTML content regardless of the option's status. + +As a result, It is now possible to obtain formatted content through the editor API. + +==== By default, code is now formatted automatically when the Enhanced Code Editor view is opened. + +Previously, the Enhanced Code Editor plugin did not automatically format code with indentation, resulting in less readable source code for users. + +With {productname} {release-version}, the new `advcode_prettify_editor` option has been introduced. By default, this option is set to `true`, ensuring that HTML content is automatically formatted upon opening the Enhanced Code Editor view. + +Additionally, users can now format either all content within the Enhanced Code Editor or a specific context selection when clicking on the "Format Code" button. + +As a result, code within the Enhanced Code Editor is now more readable. + +For more information on the **Enhanced Code Editor** premium plugin, see: xref:advcode.adoc[Enhanced Code Editor]. + +=== Markdown + +The {productname} {release-version} release includes an accompanying release of the **Markdown** premium plugin. + +This **Markdown** premium plugin release includes the following improvement: + +==== Markdown will now respect the 'Paste as Text' menu option. +// #TINY-10939 + +In previous versions of the Markdown plugin, pasting text would always modify the content, even if the "Paste as Text" option was active. This caused HTML documents to be altered during paste operations, affecting elements like newlines. + +{productname} {release-version} resolves this issue. Now, pasting Markdown does not trigger conversion when the "Paste as Text" button is active. + +For information on the **Markdown** plugin, see xref:markdown.adoc[Markdown]. + +=== Math Plugin + +The {productname} {release-version} release includes an accompanying release of the **Math** premium plugin. + +This **Math** premium plugin release includes the following improvement: + +==== Double-clicking on a `math` element now opens the Edit Math dialog. +// #TINY-10964 + +In earlier versions of the Math plugin, the double-click handler was not implemented, preventing users from opening the Math dialog by double-clicking on a math element within the editor. This behavior was inconsistent with other plugins, such as the code sample dialog. + +To address this inconsistency, {productname} {release-version} introduced a double-click handler for the Math dialog. + +Now, users can open the Math dialog by double-clicking on a math element, aligning with the functionality of other plugins. + +For more information on the **Math** plugin, see: xref:math.adoc[Math]. + +=== Revision History + +The {productname} {release-version} release includes an accompanying release of the **Revision History** premium plugin. + +**Revision History** includes the following additions, changes, and improvements. + +==== An author is now shown for revisions. Revisions created without an author will show as "Anonymous". +// #TINY-11014 + +In {productname} {release-version}, the Revision History premium plugin now displays the author for each revision in the Revision History sidebar. Revisions without an author will be marked as "Anonymous" and accompanied by an auto-generated avatar. + +This feature enhancement aims to improve traceability and accountability for content revisions. + +==== New option `revisionhistory_author` for setting the current author. +// #TINY-11014 + +In {productname} {release-version}, the **Revision History** premium plugin includes a new option `revisionhistory_author` for setting the author for the `initial` and `draft` revisions. This option expects an xref:revisionhistory.adoc#author[Author] object as its value. + +[NOTE] +The `revisionhistory_display_author` option must be set to `true` to display the authors. + +.Example +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'revisionhistory', + toolbar: 'revisionhistory', + revisionhistory_fetch: () => Promise.resolve([]), // Required option for the plugin - replace with actual API request + revisionhistory_display_author: true, + revisionhistory_author: { + id: 'john.doe', + name: 'John Doe', + avatar: 'https://example.com/avatar.jpg' + } +}); +---- + +For more information on the `revisionhistory_author` option, see: xref:revisionhistory.adoc#revisionhistory_author[revisionhistory_author option]. + +==== New `revisionhistory_display_author` option that determines whether the author is displayed. +// #TINY-11079 + +In {productname} {release-version}, the **Revision History** premium plugin includes a new option `revisionhistory_display_author` that expects a boolean value. When set to `true`, the author is displayed on each revision in the Revision History sidebar. + +.Example +[source, js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'revisionhistory', + toolbar: 'revisionhistory', + revisionhistory_fetch: () => Promise.resolve([]), // Required option for the plugin - replace with actual API request + revisionhistory_display_author: true +}); +---- + +For more information on the `revisionhistory_display_author` option, see: xref:revisionhistory.adoc#revisionhistory_display_author[revisionhistory_display_author option]. + +==== Enhance the appearance of the Revision History sidebar. +// #TINY-11045 + +In {productname} {release-version}, the **Revision History** premium plugin features an enhanced design for the Revision History sidebar. The sidebar has been updated to align better with the new author information and the {productname} `oxide-dark` skin. + +==== Add a label to the `initial` and `draft` revisions. +// #TINY-11073 + +In {productname} {release-version}, the **Revision History** premium plugin now includes labels for the `initial` and `draft` revisions. These labels are displayed in the Revision History sidebar, providing users with a clear identification of the `initial` and `draft` revisions when present. + +==== It is easier to identify the selected revision. +// #TINY-11090 + +In {productname} {release-version}, the **Revision History** premium plugin now includes a check icon to improve identification of the selected revision. Additionally, improvements have been made to the layout of the selected revision for enhanced visibility and clarity. + +==== "Restore this version" button is now disabled when a draft or initial revision is selected. +// #TINY-11042 + +Previously in {productname}, the **Revision History** premium plugin allowed users to restore any revision. In {productname} {release-version}, the **Revision History** now disables the "Restore this version" button when a `draft` or `initial` revision is selected. + +For information on the **Revision History** premium plugin, see: xref:revisionhistory.adoc[Revision History]. + +=== Spell Checker + +The {productname} {release-version} includes an accompanying release of the **Spell Checker** premium plugin. + +**Spell Checker** includes the following improvement. + +==== Added success notification when all misspellings are resolved. +// #TINT-10999 + +Previously, when all misspelled words within the spelling dialog were resolved, the editor displayed a misleading notification: "No misspellings found." This message did not accurately reflect the user's actions. + +To address this issue, {productname} {release-version} introduces a new success notification. Now, when all misspelled words are resolved, the editor displays a success notification with the text "Spell check complete." + +As a result, users are now correctly informed when all misspellings have been resolved within the spelling dialog. + +For information on the **Spell Checker** premium plugin, see: xref:introduction-to-tiny-spellchecker.adoc[Spell Checker plugin]. + + +[[accompanying-enhanced-skins-and-icon-packs-changes]] +== Accompanying Enhanced Skins & Icon Packs changes + +The {productname} {release-version} release includes an accompanying release of the **Enhanced Skins & Icon Packs**. + +=== Enhanced Skins & Icon Packs + +The **Enhanced Skins & Icon Packs** release includes the following updates: + +The **Enhanced Skins & Icon Packs** were rebuilt to pull in the changes also incorporated into the default {productname} {release-version} skin, Oxide. + +For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-and-icon-packs.adoc[Enhanced Skins & Icon Packs]. + + +[[improvements]] +== Improvements + +{productname} {release-version} also includes the following improvements: + +=== When a full document was loaded as editor content the head elements were added to the body. +// #TINY-11053 + +When loading a full document as editor content, HTML, head, and body tags were wrapped within a body tag before parsing. Since these tags are not meant to be inside a body tag, they were unwrapped. + +As a consequence, this resulted in the unintended inclusion of head tag content within the editor. For example, `++` was treated as if it were just `++` during parsing. + +{productname} {release-version} addresses this issue by implementing detection for HTML, head, and body elements. This fix ensures that head content is appropriately wrapped in HTML tags instead of body tags, preventing it from appearing in the editor. + +As a result, the editor now correctly handles full document content without misplacing head elements into the body, ensuring cleaner and more accurate content loading. + + +[[additions]] +== Additions + +{productname} {release-version} also includes the following addition: + +=== Colorpicker number input fields now show an error tooltip and error icon when invalid text has been entered. +// #TINY-10799 / #TINY-11115 + +Previously, the color picker HEX value input field only displayed a red outline and an aria label reading "invalid data" when users entered invalid values. This lacked sufficient detail to help users correct their input. + +As a consequence, users experienced confusion due to the vague error indication and insufficient guidance, potentially leading to repeated input errors. + +In {productname} {release-version}, improvements were made to the color picker input field to enhance user feedback and accessibility. The input field now includes: + +* A red outline to indicate errors. +* An error icon for visual clarity. +* On `hover` and `focus`, tooltips provide clear instructions such as "Numbers only, 0 to 255" or "Hexadecimal only, 000000 to FFFFFF." +* Voice over reads aloud as example: "Number 256. Contents selected. Range from 0 to 255. Invalid data. Edit text." + +[NOTE] +Although there may be slight variations in pronunciation and phrasing across different operating systems or specific screen readers, most screen readers will convey similar messages, emphasizing numerical values and the status of the content. + +These enhancements improve user understanding and facilitate error correction. + +image::color-picker/color-picker-error-message-rbg.png[color picker error rbg] + +image::color-picker/color-picker-error-message-hex.png[color picker error message hex] + + +[[bug-fixes]] +== Bug fixes + +{productname} {release-version} also includes the following bug fixes: + +=== Unnecessary nbsp entities were inserted when typing at the edges of inline elements. +// #TINY-10854 + +Previously, the replacement mechanism for `+ +` did not account for nearby elements when converting non-breaking spaces to regular spaces. + +As a consequence, when typing a sequence like "a space b," the output was correct. However, if the "b" was wrapped in an inline element (such as bold), the `+ +` remained instead of being replaced. + +{productname} {release-version} addresses this issue. Now, the normalization process triggers when an inline format is applied, affecting the previous sibling element to ensure spaces are properly converted. + +As a result, non-breaking spaces between different inline elements are now normalized, preventing unnecessary `+ +` entities. + +=== Fixed JavaScript error when inserting a table using the context menu by adjusting the event order in `renderInsertTableMenuItem`. +// #TINY-6887 + +Previously in {productname}, a JavaScript warning would appear when attempting to insert a table from the context menu while using both the `table` and `autoresize` plugins. This warning was caused by the `onAction` event hiding the context menu, followed by an attempt to close the already hidden context menu, resulting in the warning message: + +[quote] +"Uncaught Error: The component must be in a context to send: triggerEvent is not in context." + +NOTE: This warning did not impact the functionality of table insertion, but it could be confusing for users. + +In {productname} {release-version}, this issue has been resolved by adjusting the order of function calls in the code. Now, the context menu is closed before the `onAction` event is triggered when inserting a table from the context menu. As a result, the table is now inserted as expected without any JavaScript warnings. + +=== Notifications didn't position and resize properly when resizing the editor or toggling views. +// #TINY-10894 + +Previously, the function responsible for recalculating the width of notifications only added a width if the notification's width exceeded the boundaries. + +As a consequence, when notifications were constrained by boundaries, an additional width was added. However, if the boundaries were later increased, the added width was not adjusted accordingly. + +{productname} {release-version} addresses this issue. Now, the function adds width when the notification's width exceeds the boundaries but also removes this width when necessary. + +As a result, notifications now resize correctly when the boundaries increase, ensuring their width adjusts as expected. + +=== The pattern commands would execute even if the command was not enabled. +// #TINY-10994 + +Previously in {productname}, the `text_patterns` commands would attempt to execute even if the functionality were not supported in the current editor context. As a consequence, the command would fail and the editor would display unexpected behavior. For example, typing "1. " without the `lists` plugin enabled would delete the text instead of converting it to a list. + +This issue has been resolved in {productname} {release-version}. The editor now filters `text_patterns` to only the supported commands. For example, typing "1. " without the `lists` plugin enabled will no longer fire a text pattern and instead retain the text as plain text. + +=== Split button popups were incorrectly positioned when switching to fullscreen mode if the editor was inside a scrollable container. +// #TINY-10973 + +Previously in {productname}, there was an issue where split button popups would be positioned incorrectly when opened within a scrollable container and the editor was in `fullscreen` mode. The behavior occurred because the box constraints for the split button popup did not take the `fullscreen` mode into account when calculating the position, resulting in an incorrect placement of the popup. + +In {productname} {release-version}, this issue has been fixed. The box constraints for the split button popup are now correctly calculated when the editor is in a scrollable container and in `fullscreen` mode. As a result, the split button popup is now positioned correctly. + +=== Sequential html comments would in some cases generate unwanted elements. +// #TINY-10955 + +Previously in {productname}, consecutive HTML comments would generate unwanted elements in the editor. For example, when inserting the following HTML into the editor: + +[source,html] +---- +

    a
    + + +
    b
    +---- + +The editor would generate a `+ +` paragraph between the comments, resulting in extra paragraphs being generated. + +[source,html] +---- +
    a
    + +

     

    + +
    b
    +---- + +In {productname} {release-version}, this issue has been resolved. The editor now correctly handles consecutive HTML comments by removing the whitespace before parsing. + +[source,html] +---- +
    a
    + +
    b
    +---- + +As a result, no extra paragraphs are generated. + +=== The listbox component had a fixed width and was not a responsive ui element. +// #TINY-10884 + +Previously, the listbox component was not responsive as a UI element, due to a fixed width being applied in the `CommonDropdown` component during dialog initialization. + +This issue has been resolved in {productname} {release-version} by removing the fixed width setting, allowing the listbox component to function as a responsive UI element. + +=== Prevent default mousedown on toolbar buttons was causing misplaced focus bugs. +// #TINY-10638 + +In previous versions of {productname}, the `preventDefault` on mousedown in the toolbar button component caused focus issues. As a consequence, when clicking on different toolbar buttons, the focus was not updated, leaving the initial button highlighted. + +{productname} {release-version} addresses this issue by removing the `preventDefault`, allowing the focus to change as expected when users click on the image controls (ie. zoom in and out). + +=== Attempting to use focus commands on an editor where the cursor had last been in certain `+contentEditable="true"+` elements would fail. +// #TINY-11085 + +Previously, when `+contentEditable="true"+` (CET) fields where not wrapped in `+contentEditable="false"+` (CEF) elements, the elements did not respond properly to focus commands. As a consequence, the focus was not given to the editor as expected, leading to disruptions in user interactions. + +{productname} {release-version} addresses this issue. Now, when (CET) fields are **not wrapped** in (CEF) elements, the editor directs the focus to the body of the editor first. + +As a result, the editor now correctly returns focus as expected, ensuring seamless user interactions. \ No newline at end of file diff --git a/modules/ROOT/pages/7.4-release-notes.adoc b/modules/ROOT/pages/7.4-release-notes.adoc new file mode 100644 index 0000000000..eab4f3916e --- /dev/null +++ b/modules/ROOT/pages/7.4-release-notes.adoc @@ -0,0 +1,380 @@ += {productname} {release-version} +:release-version: 7.4 +:navtitle: {productname} {release-version} +:description: Release notes for {productname} {release-version} +:keywords: releasenotes, new, changes, bugfixes +:page-toclevels: 1 + +include::partial$misc/admon-releasenotes-for-stable.adoc[] + + +[[overview]] +== Overview + +{productname} {release-version} was released for {enterpriseversion} and {cloudname} on Wednesday, October 9^th^, 2024. + +These release notes provide an overview of the changes for {productname} {release-version}, including: + +* xref:accompanying-premium-plugin-changes[Accompanying Premium plugin changes] +* xref:improvements[Improvements] +* xref:additions[Additions] +* xref:bug-fixes[Bug fixes] +* xref:known-issues[Known issues] + + +[[accompanying-premium-plugin-changes]] +== Accompanying Premium plugin changes + +The following premium plugin updates were released alongside {productname} {release-version}. + +=== AI Assistant + +The {productname} {release-version} release includes an accompanying release of the **AI Assistant** premium plugin. + +**AI Assistant** includes the following fix. + +=== Insert lists will no longer unexpectedly generate indented lists. +// #TINY-10920 + +The `+insertContent+` action previously did not handle pasting a list onto another list correctly, causing the **AI Assistant** Premium plugin to generate an unexpected indented list when inserting lists into existing ones. + +In {productname} {release-version}, this issue is resolved by adding a paste argument to the `+insertContent+` action, ensuring correct handling of list insertion. + +As a result, the **AI Assistant** Premium plugin will no longer create indented lists when inserting a list on top of an existing one. + +For information on the **AI Assistant** premium plugin, see: xref:ai.adoc[AI Assistant]. + +=== Document Converters (Import from Word, Export to Word, Export to PDF) +// #TINY-11265 + +==== Made `importword_service_url`, `exportword_service_url` and `exportpdf_service_url` option more fault tolerant + +Previously, If the integrator added a domain without a trailing slash `+/+`, a full URL to `exportword`, or just the domain to `exportpdf` or `importword`, it caused the plugins to not function. + +{productname} {release-version} addresses this issue, by normalizing the options to accept a wider variety of input formats. As a result, the plugins now function correctly, regardless of whether a full URL, just the domain, or a domain with a trailing slash is provided. + +[NOTE] +The handler will always return the **"latest"** versioned URL, regardless if configuration is correct or not. + +=== Enhanced Code Editor + +The {productname} {release-version} release includes an accompanying release of the **Enhanced Code Editor** premium plugin. + +**Enhanced Code Editor** includes the following fixes, and improvements. + +==== Format button would lose focus after action while navigating through keyboard. +// #TINY-11122 + +Previously, after using the **Format code** button to format code, the focus would shift to the code editor wrapper instead of remaining on the **Format code** button. This behavior was inconsistent for users who prefer to navigate through the keyboard. + +{productname} {release-version} implemented a fix that explicitly refocuses the **Format code** button after the formatting action. As a result, when pressing the **Format code** button, the focus now remains on the button as intended. + +=== Formatting indent size would be different than CodeMirror indent size. +// #TINY-11150 + +Previously, the indent sizes between CodeMirror and the formatter were inconsistent due to the use of default options for both. + +As a result, the formatted code did not match the indent settings in CodeMirror, causing discrepancies in code appearance. + +{productname} {release-version} addresses this issue. Now, the formatter's indent settings have been adjusted to "2" indent spaces to align with CodeMirror, ensuring consistent indent sizes and uniform code presentation. + +=== Formatter would not remove empty lines. +// #TINY-11146 + +In previous versions of Enhanced Code Editor, the HTML formatting function retained all line breaks, including unnecessary empty lines, resulting in more spaced-out code than desired. + +With {productname} {release-version}, the HTML formatting has been optimized to automatically remove empty lines during the formatting process. This results in cleaner, more compact HTML output. + +For information on the Enhanced Code Editor plugin, see: xref:advcode.adoc[Enhanced Code Editor]. + +=== Import from Word + +The {productname} {release-version} release includes an accompanying release of the **Import from Word** premium plugin. + +**Import from Word** includes the following improvement. + +=== New `importword_converter_options` option that allows customizing the conversion. + +{productname} {release-version} introduces the addition of `importword_converter_options` to the **Import from Word** plugin. This new option allows for greater customization when converting Word documents to HTML. + +==== Key Features + +* Three Customizable Options: +** `resets`: Minimize differences between Word and HTML default styles. +** `defaults`: Control inclusion of default formatting. +** `styles`: Manage Word style inclusion in the generated document. + +.Example: using `importword_converter_options` +[source, js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'importword', + toolbar: 'importword', + importword_converter_options: { + formatting: { + resets: 'inline', + defaults: 'inline', + styles: 'none' + } + } +}); +---- + +For information on the **Import from Word** plugin, see xref:importword.adoc[Import from Word]. + +=== Spell Checker + +The {productname} {release-version} includes an accompanying release of the **Spell Checker** premium plugin. + +**Spell Checker** includes the following fix. + +=== As you type spellchecking did not update when scrolling with the `autoresize` plugin active. +// #TINY-10567 + +An issue was identified that was caused by the plugin not listening to the all the expected scroll events. As a result, when users scrolled down, this action was not detected by the plugin, leading to no updates in spellchecking. + +{productname} {release-version} addresses this issue by changing the event listener to correctly monitor scroll events. + +As a result, the plugin now successfully detects when scrolling occurs, ensuring that spellcheck updates are made as intended. + +=== Cursor would jump to the previous line after pressing shift + enter if the annotation was applied. +// #TINY-10567 + +In the Chrome browser, a rendering glitch caused the cursor to unexpectedly jump to the previous line when applying an annotation. The optimization intended to prevent re-selection after annotations was found to be unreliable and contributed to this issue. + +{productname} {release-version} resolves this problem by removing the problematic optimization, which led to this regression. + +As a result, users will no longer encounter unexpected selection or cursor behavior after applying annotations in the editor. + +For information on the **Spell Checker** premium plugin, see: xref:introduction-to-tiny-spellchecker.adoc[Spell Checker plugin]. + +=== Templates + +The {productname} {release-version} release includes an accompanying release of the **Templates** premium plugin. + +**Templates** includes the following improvement. + +==== Categories can now be declared as locked, making them readonly. +// #TINY-11116 + +include::partial$misc/admon-requires-7.4v.adoc[] + +The {productname} release introduces readonly categories for improved template management. This feature allows administrators to lock down specific template categories, preventing users from modifying the category or its templates. + +=== Key Features + +- **Readonly Templates**: Templates within readonly categories are locked, preventing the user from renaming, editing, moving, or deleting them. These templates are marked with a lock image:icons/lock.svg[lock.svg] icon to indicate their status. +- **Readonly Categories**: Categories can be marked as readonly by setting `locked: true` in the configuration. Once locked, categories cannot be renamed or deleted, and users are prevented from moving templates into or out of the category. A lock icon visually distinguishes readonly categories. Readonly categories are marked with a lock image:icons/lock.svg[lock.svg] icon to indicate their status. +- **Client-Side Restrictions**: Attempts to modify readonly categories are blocked on the client side, and the UI reflects the readonly status to provide a seamless user experience. + +.Example: Locking a category +[source,js] +---- +// Template data with locked category +{ + title: 'Locked Templates', + locked: true, // Locks the category as readonly + items: [ + { + title: 'How to find model number', + content: '

    Hi {{Customer.FirstName}},

    \n

    ...

    ' + }, + { + title: 'Support escalation', + content: '

    Hi {{Customer.FirstName}},

    \n

    ...

    ' + } + ] +} +---- + +For information on the **Templates** plugin, see: xref:advanced-templates.adoc#read-only-categories[Read-only Categories]. + +[[improvements]] +== Improvements + +{productname} {release-version} also includes the following improvements: + +=== In read-only mode the editor now allows normal cursor movement and block element selection, including video playback. +// #TINY-11264 + +In read-only mode, the editor now allows normal cursor movement and block element selection, including video playback. This behavior is now the **default** when the `readonly` option is set to `+true+` or when switching to read-only mode. + +Prior to this improvement, the editor's body element was set to `+contentEditable="false"+`, which blocked cursor placement and all user inputs. In the new behavior, the body element is set to `+contentEditable="true"+`, and input blocking is handled by the editor. + +For more information, see xref:editor-important-options.adoc#readonly[Read-only option]. + +[NOTE] +In this mode, menu buttons, read-only menu items, and read-only buttons remain enabled. To revert to the old behavior, use `+tinymce.activeEditor.ui.setEnabled(false)+`. + +=== Pasting a table now places the cursor after the table instead of into the last table cell. +// #TINY-11082 + +Previously, when users copied and pasted a table, the cursor would remain in the last cell of the table, which differed from the behavior in popular word processing applications like Google Docs and Microsoft Word. + +{productname} {release-version} addresses this behavior. Now, after pasting a table, the cursor is automatically placed on a new line immediately following the table inside a '+

     

    +' tag. + +=== Dialog list dropdown menus now close when the browser window resizes. +// #TINY-11123 + +In previous versions of {productname} any listbox with a fixed-width dropdown would remain open when resizing the browser window, creating a visual discrepancy as other UI elements adjusted to the new window size. + +{productname} {release-version} addresses this issue. Now, dropdowns will now automatically close when a window resize event is triggered, preventing the need for resizing the dropdown list itself. + +[[additions]] +== Additions + +{productname} {release-version} also includes the following additions: + +=== New `context` property for all ui components. +// #TINY-11211 + +A new `context` property has been introduced for all UI components, allowing buttons and menu items to be dynamically enabled or disabled based on whether their context matches a given predicate. This feature ensures that components reflect the current editing context, improving the user interface's adaptability. + +The status of the UI components is updated on `init`, `NodeChange`, and `SwitchMode` events. For the `mode` context, updates occur **only** on `SwitchMode` and `init`. + +To register a new context, integrators can now use: + +==== Default Contexts: + +- `editable`: Checks if the current selection is editable. +- `mode`: Enables components based on the current mode (e.g., `mode:design`, `mode:!readonly`). +- `any`: Always enables the UI component. +- `formatting`: Verifies if a specific format can be applied at the current selection. +- `insert`: Determines if a specific element can be inserted at the current selection. + +[TIP] +Syntax for context usage is `key:value`, and negation is possible by prefixing the value with `!`. For instance, `mode:!readonly` enables a button unless the editor is in readonly mode. + +This enhancement allows for more context-sensitive UI components, improving user interaction by ensuring appropriate options are available based on the editor's state. + +For more information about the `context` property, see xref:context.adoc[Context]. + +=== New option `allow_mathml_annotation_encodings` to opt-in to keep math annotations with specific encodings. +// TINY-11166 + +In previous versions of {productname}, MathML annotation elements were inadvertently stripped during content processing. This caused compatibility issues with tools like Wiris that rely on these annotations. + +{productname} {release-version} introduces a new option, `allow_mathml_annotation_encodings`, to address this problem. This option accepts an array of strings, allowing users to specify which annotation encodings should be preserved. By configuring this option, users can ensure proper functionality of MathML-dependent tools while maintaining control over which annotations are retained. + +.Example +[source, js] +---- +tinymce.init({ + selector: "textarea", + allow_mathml_annotation_encodings: [ 'wiris', 'application/x-tex' ] +}); +---- + +For more information on the `allow_mathml_annotation_encodings` option, see xref:content-filtering.adoc#allow-mathml-annotation-encodings[allow_mathml_annotation_encodings]. + + +[[bug-fixes]] +== Bug fixes + +{productname} {release-version} also includes the following bug fixes: + +=== Mouse hover on partially visible dialog collection elements no longer scrolls +// #TINY-9915 + +Previously, an issue caused partially visible collection elements, such as those in the Character Map or Emojis dialog, to unexpectedly scroll into view with abrupt and unintended movement when hovered over, resulting in a disruptive user experience. + +{productname} {release-version} addresses this issue by preventing scrolling on hover. This ensures that the dialog remains in place and does not scroll when partially visible elements are hovered over. + +=== Caret would unexpectedly shift to the non-editable table row above when pressing Enter. +// #TINY-11077 + +Previously, an issue where pressing Enter in a table cell caused the selection to shift incorrectly when the row above was set to `contenteditable="false"`. This problem affected table editing functionality, leading to unexpected cursor placement and content modifications. + +{productname} {release-version} addresses this issue. Now, this fix ensures that the selection remains stable when adding new lines within editable cells, regardless of the content editable state of adjacent rows. + +As a result, users can now reliably edit table contents without experiencing unintended cursor movements. + +=== Deleting a selection in a list element would sometimes prevent the `input` event from being dispatched. +// #TINY-11100 + +In {productname}, certain delete actions, especially the native delete action event, were suppressing the input event. This suppression caused unexpected behavior when deleting items in lists, as the input event was not being fired as intended. + +{productname} {release-version} resolves this issue by implementing the following solution: + +. When deleting an item in a list, the system now checks if the input event was triggered. +. If the input event was not triggered automatically, the system manually fires the event. + +This enhancement ensures that an input event is consistently dispatched when deleting list elements, regardless of the deletion method used. As a result, list behavior during deletion operations is now more reliable. + +=== Placing the cursor after a table, but before a BR element would misplace added newlines before the table instead of after it. +// #TINY-11110 + +Previously, a `+
    +` element was incorrectly counted as content when the cursor was placed before it, resulting in newlines or elements being inserted at the start of the block rather than after the table. + +{productname} {release-version} addresses this issue by treating the `+
    +` element as the end of the block. As a result, newlines are now correctly added after the table, ensuring proper cursor placement and content insertion. + +=== Sidebar could not be toggled until the skin was loaded. +// #TINY-11155 + +In {productname} 6.8, the initialization of sidebars in the UI was moved to occur after the skin was loaded. As a consequence, an issue was identified where the sidebar could not be toggled during the init event because the skin is loaded asynchronously. + +This issue has been resolved in {productname} {release-version} by moving the sidebar initialization back to within the PostRender event. As a result, the sidebar can now be toggled as expected during the init event. + +=== The image dialog lost focus after closing an image upload error alert. +// #TINY-11159 + +Previously, when an image upload error alert was closed, the image dialog lost focus, impacting keyboard accessibility. + +{productname} {release-version} addresses this issue by making the dropzone component focusable and adding a callback to focus the dropzone button after the error alert is closed. + +As a result, keyboard users now experience improved accessibility, with the ability to focus on the dropzone using the dialog API. + +=== Copying tables to the clipboard did not correctly separate cells and rows for the "text/plain" MIME type. +// #TINY-10847 + +Previously, when copying rows from tables, the newline character `+\n+` was not returned correctly, causing cell and row data to be improperly formatted. However, using the "Select All" function before copying preserved the newline characters. + +{productname} {release-version} resolves this issue by enhancing the clipboard handling for text extraction from table elements, particularly for complex structures. + +These improvements ensure more consistent and correctly formatted text output when copying table content within the editor. + +=== The editor resize handle was incorrectly rendered when all components were removed from the status bar. +// #TINY-11257 + +Previously in {productname}, the resize handle in the editor's status bar was positioned relative to other elements. Consequently, if these elements were removed, the resize handle would incorrectly appear in the left corner of the editor's status bar. + +In {productname} {release-version}, this issue has been resolved by adjusting the CSS. The resize handle is now consistently placed in the right corner of the status bar, regardless of the presence of other elements. This ensures that the resize handle is always positioned correctly where users expect it to be. + +[[known-issues]] + +== Known issues + +=== Editor Focus after Deleting a Comment +// #TINY-11293 + +When deleting a comment from the Comments sidebar, the focus shifts from the comments sidebar to the editor content area, rather than switching to the "Add comment..." button in the conversation sidebar as expected. + +This behavior differs from the current stable version, where the focus is correctly returned to the "Add comment..." textbox. + +**Status**: Currently under investigation. + +=== Comments Not Functional with Empty tinycomments_author and tinycomments_author_name +// #TINY-11323 + +Comment functionality becomes non-operational when `tinycomments_author` and `tinycomments_author_name` are configured as empty strings `+''+`. + +.Example of affected configuration: +[source, js] +---- +tinycomments_author: '', +tinycomments_author_name: '', +---- + +Previously, instead of assigning default user/author values as in `7-stable` (7.3), the latest release {release-version} disables all comment features when these fields are empty. + +**Status**: This issue has been resolved in xref:7.5-release-notes.adoc#use-default-anon-value-for-tinycomments_author-and-tinycomments_author_name-options-when-the-provided-value-is-an-empty-string[{productname} 7.5.0]. + +=== Comment card not removed after deleting content +// #TINY-11366 + +Currently, after deleting content that has related comments, the corresponding comment card still exists and becomes stale within the Comments sidebar. + +This behavior is inconsistent with the expected behavior, where the comment card should be removed automatically after deleting the content. + +**Status**: This issue has been resolved in xref:7.5-release-notes.adoc#removing-annotated-content-now-removes-associated-conversation-card-from-the-sidebar[{productname} 7.5.0]. \ No newline at end of file diff --git a/modules/ROOT/pages/7.4.1-release-notes.adoc b/modules/ROOT/pages/7.4.1-release-notes.adoc new file mode 100644 index 0000000000..14c934852e --- /dev/null +++ b/modules/ROOT/pages/7.4.1-release-notes.adoc @@ -0,0 +1,42 @@ += {productname} {release-version} +:release-version: 7.4.1 +:description: Release notes for TinyMCE 7.4.1 +:keywords: releasenotes, new, changes, bugfixes +:page-toclevels: 1 + +include::partial$misc/admon-releasenotes-for-stable.adoc[] + + +[[overview]] +== Overview + +{productname} {release-version} was released for {enterpriseversion} and {cloudname} on Wednesday, October 10^th^, 2024. + +These release notes provide an overview of the changes for {productname} {release-version}, including: + +* xref:security-fix[Security fix] + + +[[security-fix]] +== Security fix + +{productname} 7.4.1 includes one fix for the following security issue: + +=== Invalid HTML elements within `SVG` elements were not removed +// TINY-11332 + +A https://owasp.org/www-community/attacks/xss/[cross-site scripting] (XSS) vulnerability was discovered in link:https://www.npmjs.com/package/dompurify[DOMPurify] that affects versions of {productname} prior to {release-version} release. The issue was a result of DOMPurify allowing some bypassing which lead to improper sanitization of invalid HTML elements within XML contexts, exploiting parsing inconsistencies between XML and HTML. + +=== Affected Versions + +DOMPurify versions prior to `+<3.1.7+` + +=== Vulnerabilities + +* **Invalid HTML Elements in SVG** (link:https://www.cve.org/CVERecord?id=CVE-2024-45801[CVE-2024-45801]): Allowed invalid HTML elements within `SVG` to bypass sanitization. +* **XML Processing Instruction Bypass**: Exploited differences in XML and HTML parsers regarding Processing Instructions, where XML parsed `+

    Hello

    ?>+` as a single node, allowing `h1` to bypass sanitization. +* **CDATA Section Bypass**: Leveraged differences in CDATA section handling between XML and HTML namespaces, with CDATA treated as bogus comments in HTML, bypassing end token rules for sanitization. + +GHSA: link:https://github.com/cure53/DOMPurify/security/advisories/GHSA-mmhx-hmjr-r674[GitHub Advisory] + +CVE: link:https://www.cve.org/CVERecord?id=CVE-2024-45801[CVE-2024-45801] \ No newline at end of file diff --git a/modules/ROOT/pages/7.5-release-notes.adoc b/modules/ROOT/pages/7.5-release-notes.adoc new file mode 100644 index 0000000000..76c40f7f96 --- /dev/null +++ b/modules/ROOT/pages/7.5-release-notes.adoc @@ -0,0 +1,272 @@ += {productname} {release-version} +:release-version: 7.5 +:navtitle: {productname} {release-version} +:description: Release notes for {productname} {release-version} +:keywords: releasenotes, new, changes, bugfixes +:page-toclevels: 1 + +include::partial$misc/admon-releasenotes-for-stable.adoc[] + + +[[overview]] +== Overview + +{productname} {release-version} was released for {enterpriseversion} and {cloudname} on Wednesday, November 06^th^, 2024. These release notes provide an overview of the changes for {productname} {release-version}, including: + +* xref:accompanying-premium-plugin-changes[Accompanying Premium plugin changes] +* xref:improvements[Improvements] +* xref:additions[Additions] +* xref:bug-fixes[Bug fixes] +* xref:known-issues[Known issues] + + +[[accompanying-premium-plugin-changes]] +== Accompanying Premium plugin changes + +The following premium plugin updates were released alongside {productname} {release-version}. + +=== Export to PDF + +The {productname} {release-version} release includes an accompanying release of the **Export to PDF** premium plugin. + +**Export to PDF** Premium plugin includes the following improvement. + +=== Added a default value for the `exportpdf_converter_options` option. +// #TINY-11396 + +As of {productname} {release-version}, the **Export to PDF** Plugin now defaults to U.S. letter page size and applies standard 1-inch margins, ensuring consistency in document formatting out of the box for integrators. The following settings have been applied: + +[source,js] +---- +exportpdf_converter_options: { + format: 'Letter', + margin_top: '1in', + margin_right: '1in', + margin_bottom: '1in', + margin_left: '1in' +} +---- + +For information on the **Export to PDF** plugin, see: xref:exportpdf.adoc[Export to PDF]. + +=== Export to Word + +The {productname} {release-version} release includes an accompanying release of the **Export to Word** premium plugin. + +**Export to Word** Premium plugin includes the following improvement. + +=== Added a default value for the `exportword_converter_options` option. +// #TINY-11396 + +As of {productname} {release-version}, the **Export to Word** Plugin has been updated to default to the U.S. letter page size, improving compatibility with standard document formats, providing a better out-of-the-box experience for integrators. The following setting has been applied: + +[source,js] +---- +exportword_converter_options: { + document: { + size: 'letter' + } +} +---- + +For information on the **Export to Word** plugin, see: xref:exportword.adoc[Export to Word]. + +=== Import from Word + +The {productname} {release-version} release includes an accompanying release of the **Import from Word** premium plugin. + +**Import from Word** Premium plugin includes the following improvement. + +=== Added a default value for the `importword_converter_options` option. +// #TINY-11396 + +As of {productname} {release-version}, the **Import from Word** Plugin now defaults to retaining as much original Word document styling as possible, using the following settings: + +[source,js] +---- +importword_converter_options: { + formatting: { + styles: 'inline', + resets: 'inline', + defaults: 'inline', + } +} +---- + +For information on the **Import from Word** plugin, see: xref:importword.adoc[Import from Word]. + +=== Markdown + +The {productname} {release-version} release includes an accompanying release of the **Markdown** premium plugin. + +This **Markdown** premium plugin release includes the following improvements: + +==== The command `MarkdownInsert` is now registered immediately and operates in an async manner, instead of waiting for resources before registering the command. +// #TINY-11280 + +In {productname} {release-version}, the `MarkdownInsert` command is now registered immediately and operates asynchronously upon execution, rather than waiting for resources to register during initialization. Previously, the command required loading external content, which delayed its availability. By making the command async on execution instead of on loading, it is now accessible at initialization, improving responsiveness without the need for additional loading time. + +==== Markdown command `MarkdownInsert` fires new event `MarkdownInserted` when completed. +// #TINY-11280 + +In {productname} {release-version}, the `MarkdownInsert` command now triggers a new event, `MarkdownInserted`, upon completion. This event provides a notification when the markdown insertion process has finished, enabling better tracking and handling of post-insertion actions within the editor. + +For information on the **Markdown** plugin, see xref:markdown.adoc[Markdown]. + +=== Comments + +The {productname} {release-version} release includes an accompanying release of the **Comments** premium plugin. + +**Comments** Premium plugin includes the following additions and fixes and improvement. + +==== Comments with Mentions +// EPIC-111 + +The **Comments** plugin now supports the use of mentions in comments, with the **Mentions** plugin enabled. + +In {productname} {release-version}, the **Comments** plugin has been enhanced to support xref:mentions.adoc[Mentions] in comments. Users can now mention other users in comments by typing the `+@+` symbol followed by the user's name. + +Additionally, the **Comments** plugin now includes a new `mentionedUids` property for events within the EventLog API when the Mentions plugin is enabled. This property provides an array of UIDs mentioned in the comment, allowing integrators to retrieve which users have been mentioned in comments. + +The **Comments** plugin now offers the `xref:comments-with-mentions.adoc#tinycomments_mentions_enabled[tinycomments_mentions_enabled]` option to enable or disable mentioning other users in comments when both plugins are included in the configuration. + +For information on the **Comments with Mentions** feature, see xref:comments-with-mentions.adoc[Configuring the Comments plugin with the Mentions plugin]. + +==== The `conversationAuthor` property was missing from `create` conversation events in the EventLog API. +// #TINY-11352 + +In previous versions of the tinycomments plugin, the `conversationAuthor` property was missing from 'create' events within the event log, which led to incomplete tracking of user interactions when retrieving data through the `+getEventLog()+` API. + +{productname} {release-version} addresses this issue. Now, the `conversationAuthor` property is included in 'create' events in the event log. + +==== Removing annotated content, now, removes associated conversation card from the sidebar. +// #TINY-11366 + +Previously, in xref:7.4-release-notes.adoc#comment-card-not-removed-after-deleting-content[{productname} 7.4.0], an issue was identified where deleting annotated content did not remove the corresponding conversation card from the sidebar, resulting in outdated or irrelevant cards persisting in the user interface. + +This behavior led to confusion and increased the risk of interacting with obsolete comments. + +In {productname} {release-version}, this issue has been resolved. Now, when annotated content is deleted, the associated conversation card is automatically removed from the sidebar. + +==== Use default 'Anon' value for `tinycomments_author` and `tinycomments_author_name` options when the provided value is an empty string. +// #TINY-11323 + +Previously in xref:7.4-release-notes.adoc#comments-not-functional-with-empty-tinycomments_author-and-tinycomments_author_name[{productname} 7.4.0], an issue was identified in **Embedded mode** where the commenting functionality became non-operational when either the `tinycomments_author` or the `tinycomments_author_name` options were configured as empty strings `""`. As a consequence, users were unable to create comments when these options were empty. + +In {productname} {release-version}, the `tinycomments_author` and `tinycomments_author_name` options now default to "Anon" when the provided value is an empty string. As a result, the commenting functionality is now operational even when these options are empty. + +For information on the **Comments** plugin, see: xref:introduction-to-tiny-comments.adoc[Introduction to {companyname} Comments]. + +=== PowerPaste + +The {productname} {release-version} release includes an accompanying release of the **PowerPaste** premium plugin. + +**PowerPaste** Premium plugin includes the following improvement. + +==== Pasting plain text with the `mceInsertClipboardContent` command is now a synchronous action, to match {productname}'s core behaviour. + +Previously in {productname}, when the Powerpaste plugin was enabled, the `mceInsertClipboardContent` command was executed asynchronously. This caused compatibility issues with the xref:markdown.adoc[Markdown] plugin, as the Markdown plugin relied on synchronous command execution. As a consequence, the Markdown plugin was effectively disabled when Powerpaste was active. + +{productname} {release-version} addresses this issue. The `mceInsertClipboardContent` command has been updated to be conditionally synchronous when the Powerpaste plugin is enabled. If the content is plaintext (e.g., `+editor.execCommand('mceInsertClipboardContent', false, { text: content })+`), the command is executed synchronously, aligning it with {productname}'s core functionality. If the content is HTML (e.g., `+editor.execCommand('mceInsertClipboardContent', false, { html: content })+`), the command remains asynchronous, as it requires async operations for HTML content. + +As a result, the `mceInsertClipboardContent` command now always executes synchronously when pasting plaintext, allowing both Powerpaste and Markdown plugins to operate together seamlessly, restoring full functionality for Markdown users. + +For information on the **PowerPaste** plugin, see: xref:introduction-to-powerpaste.adoc[Introduction to PowerPaste]. + +[[improvements]] +== Improvements + +{productname} {release-version} also includes the following improvement: + +=== Improved color picker aria support. +// #TINY-11291 + +In previous versions of {productname}, an issue was identified where screen readers would inconsistently announce the original R/G/B component string in the color picker, leading to a lack of context for visually impaired users. The root cause was an incorrect placement of the `aria-label` attribute, which was initially applied to the label element instead of the input field. + +{productname} {release-version} addresses this issue. Now, the `aria-label` attribute has been moved to the input field to ensure it is correctly associated. Additionally, the descriptive text was updated from "Red/Green/Blue component" to "Red/Green/Blue channel" to provide clearer information for assistive technologies. These changes ensure that screen readers consistently and accurately announce the relevant RGB channels, significantly improving accessibility. + +[[additions]] +== Additions + +{productname} {release-version} also includes the following addition: + +=== Added support for using raw CSS in the list of possible colours, using the `color_map_raw` property. +// #TINY-11385 + +In previous versions of {productname}, the `color_map` property allowed users to define a list of colors for the color picker dropdown. However, this property only supported predefined color names or hex values, limiting the customization options for users who wanted to include custom colors using raw CSS. + +{productname} {release-version} addresses this limitation by introducing the `color_map_raw` property. This new property allows users to define a list of colors using raw CSS values, providing greater flexibility and customization options for the color picker dropdown. + +As a result, users can now include custom colors, or other CSS properties in the color map. + +For more information on customizing the color picker, see xref:user-formatting-options.adoc#color_map_raw[`+color_map_raw+` option]. + +NOTE: {companyname} Technologies would like to thank link:https://github.com/andrewnicols[Andrew Nicols] for contributing to this feature. + +[[bug-fixes]] +== Bug fixes + +{productname} {release-version} also includes the following bug fixes: + +=== Closing a nested modal dialog would lose focus from the editor. +// #TINY-11153 + +Previously in {productname}, closing a nested dialog (such as the color picker dialog within the Table Properties dialog) would cause the editor to lose focus on the parent dialog and shift focus to the editor content in the background. + +This issue impacted keyboard users, preventing them from navigating or closing the parent dialog since the focus was no longer on the dialog. Additionally, in inline mode editors, the dialog UI would disappear entirely when focus shifted to the editor area, giving the impression that the dialog had closed unexpectedly. + +This issue has been resolved by ensuring focus returns to the parent dialog when a nested dialog is closed. As a result, keyboard users can now navigate and close dialogs as expected, and the dialog UI remains visible in inline mode editors. + +=== Autocompleter would not activate after applying an inline format like font size in some cases. +// #TINY-11273 + +Previously, when formatting was applied, a span with a zero-width no-break space `+U+FEFF+` was added to the editor. This character was not considered whitespace; as a result, the autocompleter did not trigger as expected. + +{productname} {release-version} addresses this issue by updating the function to include `+U+FEFF+` as a valid character. + +As a result, the autocompleter now triggers as expected after applying formatting. + +=== Forecolor and backcolor toolbar buttons were not completely greyed out while in readonly mode. +// #TINY-11313 + +In previous versions of {productname}, an issue was identified where the `backcolor` and `forecolor` toolbar buttons were not completely greyed out while in readonly mode due to an incorrect CSS selector. + +This led to a visual inconsistency in the readonly editor state. + +{productname} {release-version} addresses this issue. Now, the CSS selector has been corrected, ensuring that both `backcolor` and `forecolor` buttons are now completely greyed out, providing a consistent user experience when the editor is in readonly mode. + +=== The `toolbar-sticky-offset` would still be applied after entering fullscreen mode. +// #TINY-11137 + +In previous versions of {productname}, an issue was identified where the toolbar offset was incorrectly applied in fullscreen mode, causing the toolbar to overlap with the editor area. + +{productname} {release-version} addresses this issue, by implementing a check to verify that the editor is **not** in fullscreen mode before applying the toolbar offset. As a result, the toolbar now appears in the correct position when in fullscreen mode, even with the `toolbar_sticky_offset` option defined. + +=== Corrected focus highlight visibility in `Statusbar` path +// #TINY-11381 + +A visual bug introduced in {productname} version xref:7.2.1-release-notes.adoc#long-translations-of-the-bottom-help-text-would-cause-minor-graphical-issues[7.1.2] caused the focus highlight to appear behind the tag name in the statusbar path, making it difficult for users to visually track their focus. + +In {productname} {release-version}, this has been corrected. The focus highlight is now correctly displayed above the tag name when navigating through the statusbar path, ensuring a clear and visible focus indication. + +=== Inability to type `{` character on German keyboard layouts + +In previous versions of {productname}, an issue was identified on German Mac keyboard layouts where the `+Option+8+` keyboard combination, used to type the opening curved bracket `{`, conflicted with the `+Alt+F12+` shortcut, which is used to focus notifications in the {productname} editor. This conflict occurred because, on German Mac keyboards, `+Option+8+` generated a key code that overlapped with the `+Alt+F12+` function, preventing users from typing `{` in the editor. + +To address this, {productname} {release-version} updates the keyboard event handling, implementing the `event.key` property rather than relying on numeric key codes. This solution ensures that the `{` character can be typed using `+Option+8+` on German Mac keyboards without interfering with the `+Alt+F12+` notification focus shortcut. + +[[known-issues]] +== Known issues + +This section describes issues that users of {productname} {release-version} may encounter and possible workarounds for these issues. + +There is one known issue in {productname} {release-version}. + +=== Screenreader on safari has poor consistency of announcing aria-label +// #TINY-11291 & #TINY-11430 + +In Safari, when using a screen reader on the color picker, the focus is mistakenly placed on the content within the input field rather than the field itself. This causes the screen reader to bypass announcing the aria-label associated with the field. + +As a consequence, users who rely on screen readers may not hear the intended description provided by the aria-label, potentially causing confusion or reducing accessibility. + +**Status**: Currently under investigation. \ No newline at end of file diff --git a/modules/ROOT/pages/7.5.1-release-notes.adoc b/modules/ROOT/pages/7.5.1-release-notes.adoc new file mode 100644 index 0000000000..6c8eacba5f --- /dev/null +++ b/modules/ROOT/pages/7.5.1-release-notes.adoc @@ -0,0 +1,37 @@ += {productname} {release-version} +:release-version: 7.5.1 +:navtitle: {productname} {release-version} +:description: Release notes for {productname} {release-version} +:keywords: releasenotes, new, changes, bugfixes +:page-toclevels: 1 + +include::partial$misc/admon-releasenotes-for-stable.adoc[] + + +[[overview]] +== Overview + +{productname} {release-version} was released for {enterpriseversion} and {cloudname} on Wednesday, November 13^th^, 2024. These release notes provide an overview of the changes for {productname} {release-version}, including: + +* xref:accompanying-premium-plugin-changes[Accompanying Premium plugin changes] + + +[[accompanying-premium-plugin-changes]] +== Accompanying Premium plugin changes + +The following premium plugin updates were released alongside {productname} {release-version}. + +=== Comments + +The {productname} {release-version} release includes an accompanying release of the **Comments** premium plugin. + +**Comments** Premium plugin includes the following additions and fix. + +==== Conversations did not load when the comments sidebar was opened on editor load with `sidebar_show`. +// #TINY-11506 + +In the {productname} 7.5 release of the **Comments** Plugin, the sidebar would not display comments when conversations took longer than ~200ms to be fetched. This issue occurred when the comments sidebar was set to open on editor load, such as using the `sidebar_show` option. + +{productname} {release-version} addresses this issue, by ensuring that `conversationUids` are set on initialization, allowing the sidebar to properly display conversations as soon as they are retrieved. + +For information on the **Comments** plugin, see: xref:introduction-to-tiny-comments.adoc[Introduction to {companyname} Comments]. \ No newline at end of file diff --git a/modules/ROOT/pages/7.6.0-release-notes.adoc b/modules/ROOT/pages/7.6.0-release-notes.adoc new file mode 100644 index 0000000000..2ab01c4f07 --- /dev/null +++ b/modules/ROOT/pages/7.6.0-release-notes.adoc @@ -0,0 +1,441 @@ += {productname} {release-version} +:release-version: 7.6.0 +:navtitle: {productname} {release-version} +:description: Release notes for {productname} {release-version} +:keywords: releasenotes, new, changes, bugfixes +:page-toclevels: 1 + +include::partial$misc/admon-releasenotes-for-stable.adoc[] + + +[[overview]] +== Overview + +{productname} {release-version} was released for {enterpriseversion} and {cloudname} on Wednesday, December 11^th^, 2024. These release notes provide an overview of the changes for {productname} {release-version}, including: + +* xref:new-premium-plugin[New Premium plugin] +* 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] +* xref:additions[Additions] +* xref:changes[Changes] +* xref:bug-fixes[Bug fixes] +* xref:known-issues[Known issues] + + +[[new-premium-plugin]] +== New Premium plugin + +The following new Premium plugin was released alongside {productname} {release-version}. + +=== Image Optimizer (Powered by Uploadcare) + +{productname} {release-version} introduces the **Image Optimizer (Powered by Uploadcare)** plugin. + +The **Image Optimizer** plugin offers a range of powerful features for image hosting, serving, and editing. These include responsive image delivery, automatic image format selection, automatic compression, and non-destructive image transformations and adjustments, all powered by link:https://uploadcare.com[Uploadcare]. + +For information on the **Image Optimizer (Powered by Uploadcare)** plugin, see xref:uploadcare.adoc[Image Optimizer (Powered by Uploadcare)]. + +[[accompanying-premium-plugin-changes]] +== Accompanying Premium plugin changes + +The following premium plugin updates were released alongside {productname} {release-version}. + +=== Accessibility Checker + +The {productname} {release-version} release includes an accompanying release of the **Accessibility Checker** premium plugin. + +**Accessibility Checker** Premium plugin includes the following fixes and improvements. + +==== Introduced a new live region for screen readers to improve accessibility checker dialog announcements +// #TINY-11523 + +Previously, an issue was identified where screen reader announcements for the accessibility dialog were inconsistent across different browsers. This inconsistency resulted in a poor user experience with screen readers and accessibility dialogs. + +In {productname} {release-version}, this issue has been resolved by adding a dedicated hidden screen reader section within the dialog structure, ensuring more consistent and accurate announcements across browsers. + +==== Add detailed issue description to accessibility checker +// #TINY-11462 + +An issue was identified where users relying on screen readers did not receive sufficient context about the current content when navigating the accessibility checker. This limitation could cause confusion and make it challenging for users to understand or resolve accessibility issues effectively. + +To address this, {productname} {release-version} introduces a new section that clearly displays the content type and includes a snippet of the content. This enhancement provides users with better context and improves the overall navigation experience. By offering more comprehensive indicators, this update ensures screen reader users can efficiently identify and address accessibility issues within the content. + +==== Improve editor content highlighting when using accessibility checker +// #TINY-11463 + +Previously, an issue involving the accessibility checker was identified where the content area highlights did not properly meet accessibility standards. This issue caused users with vision impairments to encounter difficulty in identifying the currently focused element. + +In {productname} {release-version}, this issue has been resolved by unifying the color palette to meet accessibility color contrast standards, ensuring that all users can easily locate the currently focused element. + +For information on the **Accessibility Checker** plugin, see: xref:a11ychecker.adoc[Accessibility Checker]. + +=== Checklist + +The {productname} {release-version} release includes an accompanying release of the **Checklist** premium plugin. + +**Checklist** Premium plugin includes the following fix. + +==== Checklist items were unresponsive in `center` or `right` alignments +// #TINY-11357 + +In previous versions of {productname}, an issue was identified where users could not check checklist items when they were `center` or `right` aligned. This occurred because the logic for detecting clicks relied on the left-most position of the `+
  • +` element, which remains unchanged regardless of text alignment. + +As a result, clicks in center or right alignments would fail the logic check, leaving the items unresponsive. + +{productname} {release-version} addresses this issue. Now, the logic compares the click position against the left-most position of the aligned text, rather than the parent `+
  • +` element. This adjustment ensures that clicks are properly registered regardless of alignment, restoring expected functionality across all alignment settings. + +For information on the **Checklist** plugin, see: xref:checklist.adoc[Checklist]. + +=== Comments + +The {productname} {release-version} release includes an accompanying release of the **Comments** premium plugin. + +**Comments** includes the following fixes and improvements. + +==== The `commentAuthor` property is now included in reply events of the event log. +// #TINY-11489 + +In previous versions of the tinycomments plugin, the `commentAuthor` property was missing from 'reply' events within the event log, which led to incomplete tracking of user interactions when retrieving data through the `+getEventLog()+` API. + +{productname} {release-version} addresses this issue. Now, the `commentAuthor` property is included in 'reply' events in the event log. + +For more information on the `getEventLog`, see xref:comments-commands-events-apis.adoc#getEventLog[getEventLog]. + +==== Allow mentions in comments dropdown to flow freely outside of the editor container +// #TINY-11504 + +An issue was identified where the mentions in comments dropdown didn't freely expand to the available space alongside mentions in the editor. This was due to the dropdown being restricted within the sidebar area. + +In {productname} {release-version}, this issue has been resolved by allowing the mentions in comments dropdown to expand outside the sidebar area, making full use of the available space outside the editor and improving the overall user experience. + +==== Reduced the amount of scrolling when changing between conversations in the sidebar. +// #TINY-11401 + +Previously, the scrolling behavior for comment cards was inconsistent. When scrolling from top to bottom, the scrolling would stop at the top of a comment card, whereas scrolling from bottom to top would stop at the bottom of a comment card. This inconsistency could cause confusion when navigating through comments in the sidebar. + +In {productname} {release-version}, the sidebar scrolling behavior has been updated to ensure consistency. When a conversation is selected and is either partially or completely out of view, the sidebar now scrolls to position the top of the selected conversation just below the top of the sidebar. + +[NOTE] +An exception does apply if the selected conversation is already partially visible, with the top in view but the bottom out of view, and the comment card's height is smaller than the scrollable container. In this scenario, the sidebar will scroll to position the bottom of the selected card near the bottom of the container. + +==== Scroll to show action buttons when replying/editing a comment. +// #TINY-11402 + +Previously, if a selected conversation card was positioned near the bottom of the sidebar, the reply/edit input field would be below the bottom of the sidebar resulting in the comment input field not being visible to the user. + +{productname} {release-version} addresses this issue. Now, the sidebar scrolls to display the comment input field if the selected conversation card is positioned near the bottom of the sidebar. This ensures that the comment input field is always visible to the user. + +==== Pressing Shift+Enter in Mentions in Comments dropdown should accept the active menu item +// #TINY-11455 + +In previous versions of {productname}, the `Shift+Enter` key was not properly handled when used with mentions in comments. This led to a new line being inserted while the mentions dropdown remained open, resulting in inconsistent behavior compared to mentions within the editor. + +In {productname} {release-version}, mentions in comments now handle the `Shift+Enter` key by inserting the highlighted user into the comment text area and closing the dropdown, ensuring consistent functionality across the editor and comment areas. + +=== Adjust `tinycomments` UI font size to match the editor UI font size +// #TINY-11592 + +Previously, the **Comments** plugin used a `14px` font size for the comment body, which was inconsistent with the `16px` font size used in the rest of the Comments Sidebar and the editor UI. + +This issue has been resolved in {productname} {release-version} by setting the comment body font size to `16px`, ensuring font size consistency between the **Comments** plugin and the editor UI. + +==== Editor Focus after Deleting a Comment +// #TINY-11293 + +Previously, the focus behaviour in the comments sidebar was observed to be inconsistent. When a user deleted a comment, the focus exited the comments sidebar and returned to the editor instead of returning to the conversation card. This also occurred when a new comment was created inside an existing conversation, and when an entire new conversation was created. + +In {productname} {release-version}, the focus behaviour has now been improved in the following situations: + +* Deleting a comment now returns the focus to the conversation card that contained the deleted comment. +* Creating a new comment within an existing conversation now brings the focus to the corresponding conversation card. +* Starting a new conversation now brings the focus to the newly created conversation card. + +==== Added tooltips to conversation and comment kebab menus + +In previous versions of **Comments**, the kebab menu button in the comments sidebar was missing a tooltip for users relying on assistive technologies. + +{productname} {release-version} addresses this issue, by adding an `aria-label` with the description "Comment Actions" to the sidebar comment menu button, ensuring a tooltip is displayed on hover. This update improves accessibility and aligns the user experience across different menu buttons. + +==== The caret in comment textarea returned to its previous location before closing the mentions menu by selecting with the mouse. +// #TINY-11453 + +Previously, when closing the Mentions dropdown in a Comment textarea by clicking away, the caret would revert to its previous position, disregarding the user’s mouse-click location. This issue occurred because the logic for handling caret positioning did not account for mouse interactions, resulting in a disjointed and confusing user experience. + +In {productname} {release-version} this issue was addressed. Now, the caret now accurately reflects the user’s intended position when the Mentions dropdown is closed via a mouse-click. + +For information on the **Comments** plugin, see: xref:introduction-to-tiny-comments.adoc[Introduction to {companyname} Comments]. + +=== Enhanced Code Editor +// #TINY-11298 + +The {productname} {release-version} release includes an accompanying release of the **Enhanced Code Editor** premium plugin. + +**Enhanced Code Editor** Premium plugin includes the following fix. + +==== Spelling error in tooltip for `fullscreen` toggle button + +The tooltip for the `fullscreen` toggle button was incorrectly labeled as `Fullsceen`. {productname} {release-version} addresses this issue which has now been corrected to `Fullscreen`. + +For information on the **Enhanced Code Editor** plugin, see: xref:advcode.adoc[Enhanced Code Editor]. + +[[accompanying-enhanced-skins-and-icon-packs-changes]] +== Accompanying Enhanced Skins & Icon Packs changes + +The {productname} {release-version} release includes an accompanying release of the **Enhanced Skins & Icon Packs**. + +=== Enhanced Skins & Icon Packs + +The **Enhanced Skins & Icon Packs** release includes the following updates: + +The **Enhanced Skins & Icon Packs** were rebuilt to pull in the changes also incorporated into the default {productname} {release-version} skin, Oxide. + +For information on using Enhanced Skins & Icon Packs, see: xref:enhanced-skins-and-icon-packs.adoc[Enhanced Skins & Icon Packs]. + + +[[improvements]] +== Improvements + +{productname} {release-version} also includes the following improvements: + +=== Base64 data was not properly decoded due to unhandled URL-encoded characters. +// #TINY-9548 + +Previously, URL-encoded characters were not properly handled during base64 data decoding. This issue caused images to appear broken when using a base64 string as a source with URL-encoded characters. + +In {productname} {release-version}, this issue has been resolved by implementing logic to decode URL-encoded characters before processing the base64 string. As a result, images using base64 strings as a source will now appear correctly, even if URL-encoded characters are included. + +=== The `latin` list style type is now recognized as an alias for the `alpha` list style type. +// #TINY-11515 + +Previously, {productname} did not recognize `lower-latin` and `upper-latin` list style types, causing UI issues when importing documents with such lists. + +In {productname} {release-version}, this issue has been resolved. The editor now recognizes `lower-latin` and `upper-latin` as aliases for `lower-alpha` and `upper-alpha`, respectively, ensuring the correct list type is highlighted in the Numbered List dropdown. + +[[additions]] +== Additions + +{productname} {release-version} also includes the following additions: + +=== Add Labels and Groups for Context Toolbar Buttons +// #TINY-11095 + +The release of {productname} {release-version} introduces the ability to organize context toolbar buttons into groups with optional labels or titles. This enhancement improves toolbar usability by enabling clearer categorization of buttons. + +The `items` object structure now supports defining groups with an optional `name` property for titles or a `label` property for identifying the group. This feature allows developers to create more intuitive and accessible toolbars by visually segmenting functionality. + +Example of a context toolbar configuration with groups and labels: + +.Example +[source,js] +---- +items: [ + { + name: 'Formatting', // Optional, used as the group's title + items: [ 'bold', 'italic' ] // Array of registered button names + }, + { + label: 'History', // Optional, used as a label for the group + items: [ 'undo', 'redo' ] // Array of registered button names + }, +] +---- + +For more details on configuring context toolbar groups and labels, see: xref:contexttoolbar.adoc#add-labels-and-groups-for-context-toolbar-buttons[Context Toolbar]. + +// === New `contextsliderform` and `contextsizeinput` context form types. +// #TINY-11342 + +=== New `back` function in `ContextFormApi` to go back to the previous toolbar. +// #TINY-11344 + +{productname} {release-version} introduces the `+back+` function in the `ContextFormApi`, enabling users to navigate back to the previous toolbar. This enhancement fulfills the need for a back button in context forms, providing a seamless way to return to the previous toolbar configuration when required. + +.Example: Using the `back` function in a context form +[source,js] +---- +tinymce.init({ + selector: "textarea", + setup: (ed) => { + ed.ui.registry.addContextToolbar('toolbar-with-back-example', { + items: 'form-with-back-example undo redo', + position: 'node', + scope: 'node', + predicate: (node) => node.nodeName.toLowerCase() === 'p' + }); + ed.ui.registry.addContextForm('form-with-back-example', { + type: 'contextsizeinputform', + launch: { + type: 'contextformtogglebutton', + icon: 'resize', + tooltip: 'ABC' + }, + initValue: () => ({ width: '100', height: '200' }), + onInput: (formApi) => console.log(`input.${JSON.stringify(formApi.getValue())}`), + commands: [ + { + type: 'contextformbutton', + icon: 'chevron-left', + tooltip: 'Back', + align: 'start', + onAction: (formApi) => formApi.back() + } + ] + }); + } +}); +---- + +For more details on the `back` function, see xref:contextform.adoc#formapi[Context Form - ContextFormApi]. + +=== New `QuickbarInsertImage` command that is executed by the `quickimage` button. +// #TINY-11399 + +The **Quickbars** Plugin now allows integrators to overwrite the `+QuickbarInsertImage+` command, enabling customization of the quickimage button's behavior. + +.Example of how to override the `+QuickbarInsertImage+` command: +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'quickbars', + toolbar: false, + setup: (editor) => { + editor.addCommand('QuickbarInsertImage', () => { // Add a custom command to the editor named "QuickbarInsertImage" + const input = document.createElement('input'); // Create a new element for file selection + input.type = 'file'; // Set the input type to "file" for uploading files + input.accept = 'image/*'; // Restrict the input to accept only image files + input.onchange = (e) => { // Add an event listener to handle the file selection event + const file = (e.target).files?.[0]; // Get the selected file from the input element + if (file) { + console.log(file); + } + }; + input.click(); + }); + } +}); +---- + +=== New `onSetup` function for context forms +// #TINY-11494 + +A new `+onSetup+` API has been introduced for context forms, enabling integrators to execute a function when the form is rendered and handle cleanup when it is closed. This enhancement addresses the previous limitation of not being able to detect or trigger actions during the lifecycle of context forms. The `+onSetup+` API streamlines lifecycle management by supporting initialization at form rendering and providing a return function for cleanup, enhancing integration with plugins and applications. + +For more details on the `+onSetup+` function, see xref:contextform.adoc#form[Context Form]. + +=== Added placeholder support for context form input fields +// #TINY-11459 + +A new `placeholder` option has been introduced to the context form API, addressing the need for inline guidance within input fields. This feature enables developers to specify placeholder text that appears inside input fields until the field has a value. By providing contextual hints, this enhancement improves usability and enhances the user experience. + +.Example: Using a placeholder in a context form input field +[source,js] +---- +tinymce.init({ + selector: 'textarea', + setup: (editor) => { + editor.ui.registry.addContextForm('my-form', { + predicate: () => true, + placeholder: 'Placeholder goes here...', + commands: [] + }); + }, +}); +---- + +For more details on the `placeholder` option, see xref:contextform.adoc#form[Context Form]. + +=== New `+disabled+` option for disabling all user interactions + +A new `+disabled+` option has been introduced to {productname} in version {release-version}. This option allows integrators to disable all user interactions with the editor, including cursor placement, content modifications, and UI components. When set to `+true+`, the editor behaves similarly to the readonly mode changes introduced in {productname} 7.4.0 but ensures complete non-interactivity. + +.Example disabling all user interactions with the editor +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Specify the target HTML element + disabled: true // Disables all interactions with the editor +}); +---- + +For more information on the `+disabled+` option, see xref:editor-important-options.adoc#disabled[Disabled] option. + +[[bug-fixes]] +== Bug fixes + +{productname} {release-version} also includes the following bug fixes: + +=== Image selection was removed when calling nodeChanged while having focus inside the editor UI. +// #TINY-11437 + +Previously, executing a `nodeChange` event while an image was selected caused the image to lose its resize handles. This issue disrupted the user experience, requiring users to re-select the image to resize it. + +{productname} {release-version} addresses this issue. Now, resize handles are only removed when focus moves out of the editor or its UI components. + +As a result, the resize handles remain visible during `nodeChange` events, improving usability. + +=== Tooltip would not show for group toolbar button. +// #TINY-11391 + +Previously, an issue was identified where tooltips were not displayed when hovering over toolbar group buttons. This was due to replacing the `title` attribute with an `aria-label` attribute in xref:7.0-release-notes.adoc#improved-accessibility-for-interactive-elements-with-custom-tooltips[{productname} 7.0.0] without implementing the custom tooltip behavior for the toolbar group buttons. + +In {productname} {release-version}, this issue has been resolved by applying the custom tooltip behavior to the toolbar group buttons, ensuring that tooltips are now displayed on hover. + +=== Numbered table context menu not properly applying changes +// #TINY-11383 + +Previously, there was an issue where changes to the row type in numbered tables were not properly applied. This occurred because the action of modifying the row type from a `+contentEditable="false"+` cell was being deliberately blocked. + +In {productname} {release-version}, this issue has been resolved by removing the restriction on changing the row type from a `+contentEditable="false"+` cell. As a result, changes to the row type are now correctly applied. + +=== The `samp` format was being applied as a `block` level format, instead of an `inline` format. +// #TINY-11390 + +Previously, an issue was identified where the `samp` (Sample) format was incorrectly applied as a block-level format instead of an inline format. This caused the entire element to receive the `samp` format and be placed on a new line, rather than just the selected text receiving the format. + +In {productname} {release-version}, this issue has been resolved by registering the `samp` format as an inline format. This ensures that elements with the `samp` format are treated as inline elements, maintaining the intended content flow. + +=== Removed title attribute from dialog tree elements as they already have a tooltip. +// #TINY-11470 + +Previously, an issue was identified with tooltips for tree structures where multiple tooltip systems displayed the same text simultaneously: + +. The browser's native tooltip, triggered by the `title` attribute, displayed the text. +. {productname}'s custom tooltip functionality also displayed the text. + +As a consequence, this caused two tooltips with identical content to appear at the same time, leading to a confusing user experience, where the desired behavior was to show only the custom tooltip provided by {productname}. + +In {productname} {release-version}, this issue has been resolved. The `title` attribute is now automatically removed when the custom tooltip is applied, ensuring that only the custom tooltip is displayed. + +=== Fixed CSS Bundling for Skin UI Content CSS +// #TINY-11558 + +In self-hosted React setups, image resize handles were not displayed when using bundled {productname} editors. This issue impacted the usability of features such as image resizing. + +The root cause was a misconfiguration of resource keys for the CSS bundling JS files and CSS loading logic in {productname} core. As a result, bundled editors failed to load the necessary styles, causing the resize handles to remain hidden. + +This issue affected {productname} versions earlier than 7.1.0. + +{productname} {release-version} resolves this issue by updating the `stylesheetLoader` to correctly load the `ui/default/content.css` stylesheet, ensuring that image resize handles are displayed as expected. + +=== Incorrect translation of `Cut Column` and `Copy Column` in Hebrew +// #TINY-11583 + +An issue was identified where the Hebrew translations for `Cut Column` and `Copy Column` in the table plugin were incorrect. + +{productname} {release-version} addresses this issue by providing the correct Hebrew translations for these operations. + + +[[known-issues]] +== Known issues + +This section describes issues that users of {productname} {release-version} may encounter and possible workarounds for these issues. + +There is one known issue in {productname} {release-version}. + +=== Missing translations for "Solution" for all languages in the Accessibility Checker + +In {productname} {release-version}, the "Solution" translation is missing for all languages in the Accessibility Checker. This issue affects the "Solution" section of the Accessibility Checker, where the "Solution" text is not displayed in the user's selected language. + +**Status**: Currently under investigation. \ No newline at end of file diff --git a/modules/ROOT/pages/a11ychecker.adoc b/modules/ROOT/pages/a11ychecker.adoc index fe432375a6..cd9cc35d57 100644 --- a/modules/ROOT/pages/a11ychecker.adoc +++ b/modules/ROOT/pages/a11ychecker.adoc @@ -43,7 +43,6 @@ The following checks are available for the {pluginname} plugin. The rules checke Each rule has a severity level, which will be one of the following, listed in order of increasing severity: -* Information * Warning * Error @@ -264,7 +263,10 @@ WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H39.html[ *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+`. +[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 @@ -281,7 +283,10 @@ WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H73.html[ *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. +[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 @@ -296,7 +301,7 @@ WCAG 2.1 specification:: https://www.w3.org/WAI/WCAG21/Techniques/html/H73.html[ [[T4A]] === T4A - Table markup -*Rule description:* this rule checks that all `+tables+` contain both `+td+` and `+th+` elements. +*Rule description:* this rule checks that all `+tables+` contain both `+tr+` and `+td+` elements. ==== {pluginname} rule details - T4A @@ -360,6 +365,13 @@ include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] include::partial$misc/plugin-menu-item-id-boilerplate.adoc[] +[[events]] +== Events + +The {pluginname} plugin provides the following events. + +include::partial$events/a11ychecker-events.adoc[] + == APIs The {pluginname} plugin provides the following APIs. @@ -373,7 +385,7 @@ Opens and closes the accessibility checker dialog with the results of the audit [source,js] ---- -editor.plugins.a11ychecker.toggleaudit(); +tinymce.activeEditor.plugins.a11ychecker.toggleaudit(); ---- [[getreport]] @@ -389,21 +401,23 @@ const issues = tinymce.activeEditor.plugins.a11ychecker.getReport(); console.log(issues); -// example result +// Example result [ { + "contentID": "
    Text: \"H5\"
    ", + "description": "Headings must be applied in sequential order. For example: Heading 1 should be followed by Heading 2, not Heading 3.", + "element": h5, // reference to the DOM element where the issue was found "id": "D2", "severity": "error", - "url": "http://www.w3.org/TR/UNDERSTANDING-WCAG20/content-structure-separation-programmatic.html", - "description": "Headings must be applied in sequential order. For example: Heading 1 should be followed by Heading 2, not Heading 3.", - "element": {} // The element value contains the DOM element (such as

    ). + "url": "https://www.w3.org/WAI/WCAG21/Techniques/general/G141.html", }, { + "contentID": "
    Table: \"2x2\"
    ", + "description": "Tables must have captions", + "element": table, // reference to the DOM element where the issue was found "id": "T1", "severity": "error", - "url": "http://www.w3.org/TR/UNDERSTANDING-WCAG20/content-structure-separation-programmatic.html", - "description": "Tables must have captions", - "element": {} // The element value contains the DOM element (such as

  • ). + "url": "https://www.w3.org/WAI/WCAG21/Techniques/html/H39.html", } ] ---- @@ -411,7 +425,7 @@ console.log(issues); [[issue]] === The `+issue+` object -In a11ychecker, when the content within the editor is `audited`, each element is checked to ensure that no xref:a11ychecker.adoc#accessibility-rules[Accessibility rules] are violated. Any element which doesn’t adhere to a rule will generate an `issue` within the audit; the details of which are to be displayed in the a11ychecker dialog. +In a11ychecker, when the content within the editor is `audited`, each element is checked to ensure that no xref:a11ychecker.adoc#accessibility-rules[Accessibility rules] are violated. Any element which doesn't adhere to a rule will generate an `issue` within the audit; the details of which are to be displayed in the a11ychecker dialog. The `+'issue'+` object provides relevant data pertaining to any issue generated by an element which violates an xref:a11ychecker.adoc#accessibility-rules[Accessibility rule]: @@ -419,8 +433,10 @@ The `+'issue'+` object provides relevant data pertaining to any issue generated * `+description+` : `+String+` description of the issue; as will be displayed in the dialog. -* `+severity+` : `+String+` severity level of the issue; either `+info+`, `+warning+` or `+error+`. +* `+severity+` : `+String+` severity level of the issue; either `+warning+` or `+error+`. * `+url+` : `+String+` URL reference for the issue. By default, this will be a link to the W3 website, containing the W3 WCAG technique that needs to be addressed to clear the issue. * `+element+` : `+Object+` DOM element where the issue was found. + +* `+contentID+` : `+String+` A short snippet of the content (such as text, link, image, or table) where the issue was found. diff --git a/modules/ROOT/pages/advanced-templates.adoc b/modules/ROOT/pages/advanced-templates.adoc index 682f44ba46..453722fab0 100644 --- a/modules/ROOT/pages/advanced-templates.adoc +++ b/modules/ROOT/pages/advanced-templates.adoc @@ -79,6 +79,43 @@ To manage the template list ** Move all category items to another category. ** Delete template/category. +[[read-only-categories]] +=== Readonly categories + +include::partial$misc/admon-requires-7.4v.adoc[] + +{pluginname} categories can be set to read-only in {productname}, preventing users from modifying the category or its templates. When a category is set to read-only, users cannot: + +* add new templates to the category +* delete the category or its templates +* rename the category or its templates +* move templates into or out of the category + +A lock image:icons/lock.svg[lock.svg] icon visually indicates that a category is read-only, preventing users from modifying the category or its templates through the user interface. + +To create a locked (read-only) category, add the `+locked: true+` property to the category object in your templates data: + +.Example of a locked category +[source,js] +---- +{ + title: 'Locked Templates', + locked: true, // Locks the category as readonly + items: [ + { + title: 'How to find model number', + content: '

    Hi {{Customer.FirstName}},

    \n

    ...

    ' + }, + { + title: 'Support escalation', + content: '

    Hi {{Customer.FirstName}},

    \n

    ...

    ' + } + ] +} +---- + +liveDemo::{plugincode}-readonly-template[] + == Basic setup To setup the {pluginname} plugin user-interface in the editor: diff --git a/modules/ROOT/pages/ai-azure.adoc b/modules/ROOT/pages/ai-azure.adoc new file mode 100644 index 0000000000..4e61773d94 --- /dev/null +++ b/modules/ROOT/pages/ai-azure.adoc @@ -0,0 +1,206 @@ += Azure AI integration guide +:pluginname: AI Assistant +:plugincode: ai +:plugincategory: premium +:navtitle: Azure AI integration guide +:description_short: {pluginname} with Azure OpenAI Service +:description: A guide for integrating {pluginname} plugin using Azure OpenAI Service. +:keywords: example, demo, custom, plugin, ai, assistant, guide, azure, openai, service + +include::partial$misc/admon-ai-pricing.adoc[] + +== Introduction + +This guide provides instructions for integrating the {pluginname} plugin using the https://learn.microsoft.com/en-us/azure/ai-services/openai/[Azure OpenAI Service] in {productname}. + +Azure OpenAI Service provides REST API access to OpenAI's language models with Azure specific features such as private networking, regional availability, and responsible AI content filtering. + +To learn more about the difference between string and streaming responses, see the xref:ai.adoc#the-respondwith-object[`respondWith` object] on the plugin page. + +== Prerequisites + +Before beginning, make sure an OpenAI model has been set up in Azure. The model's endpoint URL and API key are required for integration. For more information, see the https://learn.microsoft.com/en-us/azure/ai-services/openai/chatgpt-quickstart?tabs=command-line%2Cpython-new&pivots=rest-api[Quick Start Guide^] provided by Azure. + +include::partial$misc/admon-ai-proxy.adoc[] + +== String response + +This example demonstrates how to integrate the {pluginname} plugin with the https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#chat-completions[Azure OpenAI Service Chat completions API] to generate a string response. + +[source,js] +---- +// This example stores the API key in the client side integration. This is not recommended for any purpose. +// Instead, an alternate method for retrieving the API key should be used. +const AZURE_OPENAI_API_KEY = ''; +const AZURE_OPENAI_ENDPOINT = ''; // e.g. https://.openai.azure.com/openai/deployments//chat/completions?api-version= + +const ai_request = (request, respondWith) => { + const azureOpenAiOptions = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'api-key': AZURE_OPENAI_API_KEY + }, + body: JSON.stringify({ + temperature: 0.7, + max_tokens: 800, + messages: [{ role: 'user', content: request.prompt }], + }) + }; + respondWith.string((signal) => window.fetch(AZURE_OPENAI_ENDPOINT, { signal, ...azureOpenAiOptions }) + .then(async (response) => { + if (response) { + const data = await response.json(); + if (data.error) { + throw new Error(`${data.error.type}: ${data.error.message}`); + } else if (response.ok) { + // Extract the response content from the data returned by the API + return data?.choices[0]?.message?.content?.trim(); + } + } else { + throw new Error('Failed to communicate with the Azure OpenAI API'); + } + }) + ); +}; + +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'ai', + toolbar: 'aidialog aishortcuts', + ai_request +}); +---- + +== Streaming response + +This example demonstrates how to integrate the {pluginname} plugin with the https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#chat-completions[Azure OpenAI Service Chat completions API] to generate streaming responses. + +[source,js] +---- +const fetchApi = import("https://unpkg.com/@microsoft/fetch-event-source@2.0.1/lib/esm/index.js").then(module => module.fetchEventSource); + +// This example stores the API key in the client side integration. This is not recommended for any purpose. +// Instead, an alternate method for retrieving the API key should be used. +const AZURE_OPENAI_API_KEY = ''; +const AZURE_OPENAI_ENDPOINT = ''; // e.g. https://.openai.azure.com/openai/deployments//chat/completions?api-version= + +const ai_request = (request, respondWith) => { + respondWith.stream((signal, streamMessage) => { + // Adds each previous query and response as individual messages + const conversation = request.thread.flatMap((event) => { + if (event.response) { + return [ + { role: 'user', content: event.request.query }, + { role: 'assistant', content: event.response.data } + ]; + } else { + return []; + } + }); + + // System messages provided by the plugin to format the output as HTML content. + const pluginSystemMessages = request.system.map((content) => ({ + role: 'system', + content + })); + + const systemMessages = [ + ...pluginSystemMessages, + // Additional system messages to control the output of the AI + { role: 'system', content: 'Remove lines with ``` from the response start and response end.' } + ] + + // Forms the new query sent to the API + const content = request.context.length === 0 || conversation.length > 0 + ? request.query + : `Question: ${request.query} Context: """${request.context}"""`; + + const messages = [ + ...conversation, + ...systemMessages, + { role: 'user', content } + ]; + + const requestBody = { + temperature: 0.7, + max_tokens: 800, + messages, + stream: true + }; + + const azureOpenAiOptions = { + signal, + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'api-key': AZURE_OPENAI_API_KEY + }, + body: JSON.stringify(requestBody) + }; + + const onopen = async (response) => { + if (response) { + const contentType = response.headers.get('content-type'); + if (response.ok && contentType?.includes('text/event-stream')) { + return; + } else if (contentType?.includes('application/json')) { + const data = await response.json(); + if (data.error) { + throw new Error(`${data.error.type}: ${data.error.message}`); + } + } + } else { + throw new Error('Failed to communicate with the Azure OpenAI API'); + } + }; + + // This function passes each new message into the plugin via the `streamMessage` callback. + const onmessage = (ev) => { + const data = ev.data; + if (data !== '[DONE]') { + const parsedData = JSON.parse(data); + const firstChoice = parsedData?.choices[0]; + const message = firstChoice?.delta?.content; + if (message) { + streamMessage(message); + } + } + }; + + const onerror = (error) => { + // Stop operation and do not retry by the fetch-event-source + throw error; + }; + + // Use microsoft's fetch-event-source library to work around the 2000 character limit + // of the browser `EventSource` API, which requires query strings + return fetchApi + .then(fetchEventSource => + fetchEventSource(AZURE_OPENAI_ENDPOINT, { + ...azureOpenAiOptions, + openWhenHidden: true, + onopen, + onmessage, + onerror + }) + ) + .then(async (response) => { + if (response && !response.ok) { + const data = await response.json(); + if (data.error) { + throw new Error(`${data.error.type}: ${data.error.message}`); + } + } + }) + .catch(onerror); + }); +}; + +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'ai', + toolbar: 'aidialog aishortcuts', + ai_request +}); +---- diff --git a/modules/ROOT/pages/ai-bedrock.adoc b/modules/ROOT/pages/ai-bedrock.adoc new file mode 100644 index 0000000000..8a1df93e3b --- /dev/null +++ b/modules/ROOT/pages/ai-bedrock.adoc @@ -0,0 +1,206 @@ += Amazon Bedrock integration guide +:pluginname: AI Assistant +:plugincode: ai +:plugincategory: premium +:navtitle: Amazon Bedrock integration guide +:description_short: {pluginname} with Amazon Bedrock +:description: A guide for integrating {pluginname} plugin using Amazon Bedrock. +:keywords: example, demo, custom, plugin, ai, assistant, guide, amazon, bedrock, aws + +include::partial$misc/admon-ai-pricing.adoc[] + +== Introduction + +This guide provides instructions for integrating the {pluginname} plugin using https://docs.aws.amazon.com/bedrock/latest/userguide/setting-up.html[Amazon Bedrock] in {productname}. Amazon Bedrock is a managed service for building generative AI applications on AWS. The advantage of using Amazon Bedrock is that it provides a wide range of foundation models that can be used interchangeably with little to no modification. + +The following examples load the AWS credentials directly on the client side. For security reasons, it is recommended to use an alternate method for retrieving these credentials. It is recommended to hide the API calls behind a server-side proxy to avoid exposing the AWS credentials to the client side. + +These examples use Node.js and https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/welcome.html[AWS SDK for JavaScript] through the `@aws-sdk/client-bedrock-runtime` package to interact with the Amazon Bedrock API. However, you can use any development environment that the https://aws.amazon.com/developer/tools[AWS SDKs] support. + +Here, the Anthropic Claude-3 Haiku model is used as an example. You can replace `modelId` with the model you want to use. See https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html[Supported models] for more information. Note that each foundation model comes with its own set of parameters. + +To learn more about the difference between string and streaming responses, see xref:ai.adoc#the-respondwith-object[The `respondWith` object] on the plugin page. + +== Prerequisites + +Before you begin, you need the following: + +. An AWS account with access to Amazon Bedrock. +. The AWS credentials for the account. +. A Node.js environment with the `@aws-sdk/client-bedrock-runtime` package installed. + +include::partial$misc/admon-ai-proxy.adoc[] + +== String response + +This example demonstrates how to integrate the {pluginname} plugin with the https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_InvokeModel.html[InvokeModel command] to generate string responses. + +[source,js] +---- +import { BedrockRuntimeClient, InvokeModelCommand } from "@aws-sdk/client-bedrock-runtime"; + +// Providing access credentials within the integration is not recommended for production use. +// It is recommended to set up a proxy server to authenticate requests and provide access. +const AWS_ACCESS_KEY_ID = ""; +const AWS_SECRET_ACCESS_KEY = ""; +const AWS_SESSION_TOKEN = ""; + +const config = { + region: "us-east-1", + credentials: { + accessKeyId: AWS_ACCESS_KEY_ID, + secretAccessKey: AWS_SECRET_ACCESS_KEY, + sessionToken: AWS_SESSION_TOKEN, + }, +}; +const client = new BedrockRuntimeClient(config); + +const ai_request = (request, respondWith) => { + const payload = { + anthropic_version: "bedrock-2023-05-31", + max_tokens: 1000, + messages: [{ + role: "user", + content: request.prompt + }], + }; + + const input = { + body: JSON.stringify(payload), + contentType: "application/json", + accept: "application/json", + modelId: "anthropic.claude-3-haiku-20240307-v1:0" + }; + + respondWith.string(async (_signal) => { + const command = new InvokeModelCommand(input); + const response = await client.send(command); + const decodedResponseBody = new TextDecoder().decode(response.body); + const responseBody = JSON.parse(decodedResponseBody); + const output = responseBody.content[0].text; + return await output; + }); +}; + +tinymce.init({ + selector: 'textarea', + plugins: 'ai code help', + toolbar: 'aidialog aishortcuts code help', + ai_request +}); +---- + +== Streaming response + +This example demonstrates how to integrate the {pluginname} plugin with the https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_InvokeModelWithResponseStream.html[InvokeModelWithResponseStream command] to generate streaming responses. +[source,js] +---- +import { BedrockRuntimeClient, InvokeModelWithResponseStreamCommand } from "@aws-sdk/client-bedrock-runtime"; + +// Providing access credentials within the integration is not recommended for production use. +// It is recommended to set up a proxy server to authenticate requests and provide access. +const AWS_ACCESS_KEY_ID = ""; +const AWS_SECRET_ACCESS_KEY = ""; +const AWS_SESSION_TOKEN = ""; + +const config = { + region: "us-east-1", + credentials: { + accessKeyId: AWS_ACCESS_KEY_ID, + secretAccessKey: AWS_SECRET_ACCESS_KEY, + sessionToken: AWS_SESSION_TOKEN, + }, +}; +const client = new BedrockRuntimeClient(config); + +const ai_request = (request, respondWith) => { + // Adds each previous query and response as individual messages + const conversation = request.thread.flatMap((event) => { + if (event.response) { + return [ + { role: 'user', content: event.request.query }, + { role: 'assistant', content: event.response.data } + ]; + } else { + return []; + } + }); + + // System messages provided by the plugin to format the output as HTML content. + const pluginSystemMessages = request.system.map((text) => ({ + text + })); + + const systemMessages = [ + ...pluginSystemMessages, + // Additional system messages to control the output of the AI + { text: 'Do not include html\`\`\` at the start or \`\`\` at the end.' }, + { text: 'No explanation or boilerplate, just give the HTML response.' } + ] + + const system = systemMessages.map((message) => message.text).join('\n'); + + // Forms the new query sent to the API + const text = request.context.length === 0 || conversation.length > 0 + ? request.query + : `Question: ${request.query} Context: """${request.context}"""`; + + const messages = [ + ...conversation, + { + role: "user", + content: text + } + ]; + + const payload = { + anthropic_version: "bedrock-2023-05-31", + max_tokens: 1000, + system, + messages, + }; + + const input = { + body: JSON.stringify(payload), + contentType: "application/json", + accept: "application/json", + modelId: "anthropic.claude-3-haiku-20240307-v1:0" + }; + + // Amazon Bedrock doesn't support cancelling a response mid-stream, so there is no use for the signal callback. + respondWith.stream(async (_signal, streamMessage) => { + const command = new InvokeModelWithResponseStreamCommand(input); + const response = await client.send(command); + for await (const item of response.body) { + const chunk = JSON.parse(new TextDecoder().decode(item.chunk.bytes)); + const chunk_type = chunk.type; + + switch (chunk_type) { + case "message_start": + break; + case "content_block_start": + break; + case "content_block_delta": + const message = chunk.delta.text; + streamMessage(message); + break; + case "content_block_stop": + break; + case "message_delta": + break; + case "message_stop": + break; + default: + return Promise.reject("Stream error"); + } + } + }); +}; + +tinymce.init({ + selector: 'textarea', + plugins: 'ai code help', + toolbar: 'aidialog aishortcuts code help', + ai_request +}); +---- \ No newline at end of file diff --git a/modules/ROOT/pages/ai-gemini.adoc b/modules/ROOT/pages/ai-gemini.adoc new file mode 100644 index 0000000000..434f5fe774 --- /dev/null +++ b/modules/ROOT/pages/ai-gemini.adoc @@ -0,0 +1,236 @@ += Google Gemini integration guide +:pluginname: AI Assistant +:plugincode: ai +:plugincategory: premium +:navtitle: Google Gemini integration guide +:description_short: {pluginname} with Google Gemini +:description: A guide for integrating {pluginname} plugin using Google Gemini. +:keywords: example, demo, custom, plugin, ai, assistant, guide, google, gemini, vertexai, ai-studio, console, gcp, platform, cloud + +include::partial$misc/admon-ai-pricing.adoc[] + +== Introduction + +This guide provides instructions for integrating the {pluginname} plugin using Google Gemini in {productname}. + +There are two version of the Google Gemini API: https://ai.google.dev/gemini-api/docs/get-started/rest[Google AI Studio] and https://cloud.google.com/vertex-ai[Google Cloud - Vertex AI]. The Google AI Studio API is ideal for quickly integrating the Google Gemini models into an application with the minimal setup required. The Google Cloud - Vertex AI API is more powerful and flexible than Google AI Studio, but requires more setup to integrate the Google Gemini models into an application. + +In this example, we will demonstrate how to integrate the {pluginname} plugin with the Vertex AI APIs, but the same principles can be applied to the Google AI Studio APIs by changing the API endpoint, request body, and authentication method. + +Vertex AI provides a `systemInstruction` field in the request body that allows controlling the output of the AI model. Google AI Studio does not currently provide this option, so the system messages would need to be provided as part of the user prompt for that use case. + +See https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/gemini[Google Cloud - Vertex AI Gemini API docs] for more information on the Vertex AI Gemini API. + +To learn more about the difference between string and streaming responses, see xref:ai.adoc#the-respondwith-object[The `respondWith` object] on the plugin page. + +== Authentication + +The access token is used in the Authorization header to authenticate the request to the Google Cloud API. The access token should be stored securely and not exposed to the client side integration. A recommended approach is to use a proxy server to generate the access token and make the API calls. For more information, see the xref:ai-proxy.adoc[AI Proxy Server reference guide]. + +The https://www.npmjs.com/package/google-auth-library[google-auth-library] can be used to programmatically generate an access token for the Google Cloud API. Alternatively, the https://cloud.google.com/nodejs/docs/reference/vertexai/latest[Vertex AI Node.js SDK] or other client library can be used, but may require modifications to the code. + +== Prerequisites + +Before you begin, you need to have the following: + +. A Google Cloud Platform (GCP) account. +. A Google Cloud Project with the Vertex AI API enabled. +. The Project ID and Region of the Google Cloud Project. +. An Access Token for the Vertex AI API. + +include::partial$misc/admon-ai-proxy.adoc[] + +== String response + +This example demonstrates how to integrate the {pluginname} plugin with the Vertex AI API to generate string responses. + +[source,js] +---- +// Providing access credentials within the integration is not recommended for production use. +// It is recommended to set up a proxy server to authenticate requests and provide access. +const ACCESS_TOKEN = ''; // used in the Authorization Header +const PROJECT_ID = ''; // retrieve from the Vertex AI Google Console +const REGION = ''; // e.g. us-central1 +const API_URL = `https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/publishers/google/models/gemini-1.0-pro:generateContent`; + +const ai_request = (request, respondWith) => { + const geminiOptions = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${ACCESS_TOKEN}` + }, + body: JSON.stringify({ + contents: { + role: "user", + parts: { text: request.prompt } + }, + generationConfig: { + temperature: 0.9, + maxOutputTokens: 800, + } + }) + }; + respondWith.string((signal) => window.fetch(API_URL, { signal, ...geminiOptions }) + .then(async (response) => { + if (response) { + const data = await response.json(); + if (data.error) { + throw new Error(`${data.error.type}: ${data.error.message}`); + } else if (response.ok) { + // Extract the response content from the data returned by the API + return data?.candidates[0]?.content?.parts[0]?.text?.trim().replace(/^```html\n/, "").replace(/\n```$/, ""); + } + } else { + throw new Error('Failed to communicate with the Gemini API'); + } + }) + ); +}; + +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'ai', + toolbar: 'aidialog aishortcuts', + ai_request +}); +---- + +== Streaming response + +This example demonstrates how to integrate the {pluginname} plugin with the Vertex AI API to generate streaming responses. +[source,js] +---- +const fetchApi = import("https://unpkg.com/@microsoft/fetch-event-source@2.0.1/lib/esm/index.js").then(module => module.fetchEventSource); + +// Providing access credentials within the integration is not recommended for production use. +// It is recommended to set up a proxy server to authenticate requests and provide access. +const ACCESS_TOKEN = ''; // used in the Authorization Header +const PROJECT_ID = ''; // retrieve from the Vertex AI Google Console +const REGION = ''; // e.g. us-central1 +const API_URL = `https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/publishers/google/models/gemini-1.0-pro:streamGenerateContent?alt=sse`; + +const ai_request = (request, respondWith) => { + respondWith.stream((signal, streamMessage) => { + // Adds each previous query and response as individual messages + const conversation = request.thread.flatMap((event) => { + if (event.response) { + return [ + { role: 'user', parts: [{ text: event.request.query }] }, + { role: 'model', parts: [{ text: event.response.data }] } + ]; + } else { + return []; + } + }); + + // System messages provided by the plugin to format the output as HTML content. + const pluginSystemMessages = request.system.map((text) => ({ + text + })); + + const systemInstruction = { + parts: [ + ...pluginSystemMessages, + // Additional system messages to control the output of the AI + { text: 'Do not include html``` at the start or ``` at the end of the response.' }, + { text: 'No boilerplate or explanation, just give the HTML response.' } + ] + }; + + // Forms the new query sent to the API + const text = request.context.length === 0 || conversation.length > 0 + ? request.query + : `Question: ${request.query} Context: """${request.context}"""`; + + const contents = [ + ...conversation, + { role: 'user', parts: [ + { text } + ]} + ]; + + const generationConfig = { + temperature: 0.9, + maxOutputTokens: 800, + }; + + const requestBody = { + contents, + generationConfig, + systemInstruction, + }; + + const geminiOptions = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${ACCESS_TOKEN}` + }, + body: JSON.stringify(requestBody) + }; + + const onopen = async (response) => { + if (response) { + const contentType = response.headers.get('content-type'); + if (response.ok && contentType?.includes('text/event-stream')) { + return; + } else if (contentType?.includes('application/json')) { + const data = await response.json(); + if (data.error) { + throw new Error(`${data.error.type}: ${data.error.message}`); + } + } + } else { + throw new Error('Failed to communicate with the Gemini API'); + } + }; + + // This function passes each new message into the plugin via the `streamMessage` callback. + const onmessage = (ev) => { + const data = ev.data; + if (data !== '[DONE]') { + const parsedData = JSON.parse(data); + const message = parsedData?.candidates[0]?.content?.parts[0]?.text?.replace(/^```html\n/, "").replace(/\n```$/, ""); + if (message) { + streamMessage(message); + } + } + }; + + const onerror = (error) => { + // Stop operation and do not retry by the fetch-event-source + throw error; + }; + + // Use microsoft's fetch-event-source library to work around the 2000 character limit + // of the browser `EventSource` API, which requires query strings + return fetchApi + .then(fetchEventSource => + fetchEventSource(API_URL, { + ...geminiOptions, + openWhenHidden: true, + onopen, + onmessage, + onerror + }) + ) + .then(async (response) => { + if (response && !response.ok) { + const data = await response.json(); + if (data.error) { + throw new Error(`${data.error.type}: ${data.error.message}`); + } + } + }) + .catch(onerror); + }); +}; + +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'ai', + toolbar: 'aidialog aishortcuts', + ai_request +}); +---- \ No newline at end of file diff --git a/modules/ROOT/pages/ai-openai.adoc b/modules/ROOT/pages/ai-openai.adoc new file mode 100644 index 0000000000..424f1cece5 --- /dev/null +++ b/modules/ROOT/pages/ai-openai.adoc @@ -0,0 +1,206 @@ += OpenAI ChatGPT integration guide +:pluginname: AI Assistant +:plugincode: ai +:plugincategory: premium +:navtitle: OpenAI ChatGPT integration guide +:description_short: {pluginname} with OpenAI ChatGPT +:description: A guide for integrating {pluginname} plugin using OpenAI ChatGPT. +:keywords: example, demo, custom, plugin, ai, assistant, guide, openai, gpt, chatgpt + +include::partial$misc/admon-ai-pricing.adoc[] + +== Introduction + +This guide provides instructions for integrating the {pluginname} plugin using https://platform.openai.com/docs/guides/text-generation[OpenAI ChatGPT] in {productname}. + +To learn more about the difference between string and streaming responses, see xref:ai.adoc#the-respondwith-object[The `respondWith` object] on the plugin page. + +== Prerequisites + +Before you begin, you need the following: + +. An OpenAI API Key. To get an API key, sign up for an account on the https://platform.openai.com/signup[OpenAI Platform]. + +include::partial$misc/admon-ai-proxy.adoc[] + +== String response + +This example demonstrates how to integrate the {pluginname} plugin with the OpenAI API to generate string responses. + +[source,js] +---- +// This example stores the API key in the client side integration. This is not recommended for any purpose. +// Instead, an alternate method for retrieving the API key should be used. +const api_key = ''; + +const ai_request = (request, respondWith) => { + const openAiOptions = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${api_key}` + }, + body: JSON.stringify({ + model: 'gpt-4o', + temperature: 0.7, + max_tokens: 800, + messages: [{ role: 'user', content: request.prompt }], + }) + }; + respondWith.string((signal) => window.fetch('https://api.openai.com/v1/chat/completions', { signal, ...openAiOptions }) + .then(async (response) => { + if (response) { + const data = await response.json(); + if (data.error) { + throw new Error(`${data.error.type}: ${data.error.message}`); + } else if (response.ok) { + // Extract the response content from the data returned by the API + return data?.choices[0]?.message?.content?.trim(); + } + } else { + throw new Error('Failed to communicate with the ChatGPT API'); + } + }) + ); +}; + +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'ai', + toolbar: 'aidialog aishortcuts', + ai_request +}); +---- + +== Streaming response + +This example demonstrates how to integrate the {pluginname} plugin with the OpenAI API to generate streaming responses. + +[source,js] +---- +const fetchApi = import("https://unpkg.com/@microsoft/fetch-event-source@2.0.1/lib/esm/index.js").then(module => module.fetchEventSource); + +// This example stores the API key in the client side integration. This is not recommended for any purpose. +// Instead, an alternate method for retrieving the API key should be used. +const api_key = ''; + +const ai_request = (request, respondWith) => { + respondWith.stream((signal, streamMessage) => { + // Adds each previous query and response as individual messages + const conversation = request.thread.flatMap((event) => { + if (event.response) { + return [ + { role: 'user', content: event.request.query }, + { role: 'assistant', content: event.response.data } + ]; + } else { + return []; + } + }); + + // System messages provided by the plugin to format the output as HTML content. + const pluginSystemMessages = request.system.map((content) => ({ + role: 'system', + content + })); + + const systemMessages = [ + ...pluginSystemMessages, + // Additional system messages to control the output of the AI + { role: 'system', content: 'Remove lines with ``` from the response start and response end.' } + ] + + // Forms the new query sent to the API + const content = request.context.length === 0 || conversation.length > 0 + ? request.query + : `Question: ${request.query} Context: """${request.context}"""`; + + const messages = [ + ...conversation, + ...systemMessages, + { role: 'user', content } + ]; + + const requestBody = { + model: 'gpt-4o', + temperature: 0.7, + max_tokens: 800, + messages, + stream: true + }; + + const openAiOptions = { + signal, + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${api_key}` + }, + body: JSON.stringify(requestBody) + }; + + const onopen = async (response) => { + if (response) { + const contentType = response.headers.get('content-type'); + if (response.ok && contentType?.includes('text/event-stream')) { + return; + } else if (contentType?.includes('application/json')) { + const data = await response.json(); + if (data.error) { + throw new Error(`${data.error.type}: ${data.error.message}`); + } + } + } else { + throw new Error('Failed to communicate with the ChatGPT API'); + } + }; + + // This function passes each new message into the plugin via the `streamMessage` callback. + const onmessage = (ev) => { + const data = ev.data; + if (data !== '[DONE]') { + const parsedData = JSON.parse(data); + const firstChoice = parsedData?.choices[0]; + const message = firstChoice?.delta?.content; + if (message) { + streamMessage(message); + } + } + }; + + const onerror = (error) => { + // Stop operation and do not retry by the fetch-event-source + throw error; + }; + + // Use microsoft's fetch-event-source library to work around the 2000 character limit + // of the browser `EventSource` API, which requires query strings + return fetchApi + .then(fetchEventSource => + fetchEventSource('https://api.openai.com/v1/chat/completions', { + ...openAiOptions, + openWhenHidden: true, + onopen, + onmessage, + onerror + }) + ) + .then(async (response) => { + if (response && !response.ok) { + const data = await response.json(); + if (data.error) { + throw new Error(`${data.error.type}: ${data.error.message}`); + } + } + }) + .catch(onerror); + }); +}; + +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'ai', + toolbar: 'aidialog aishortcuts', + ai_request +}); +---- \ No newline at end of file diff --git a/modules/ROOT/pages/ai.adoc b/modules/ROOT/pages/ai.adoc index 32353c5018..566fbbaa4d 100644 --- a/modules/ROOT/pages/ai.adoc +++ b/modules/ROOT/pages/ai.adoc @@ -2,7 +2,7 @@ :navtitle: AI Assistant :description: Sends queries to registered AI APIs and sets the results in the document or temporarily stores the results. :description_short: Query AI APIs and accept results. -:keywords: plugin, ai, artificial intelligence, query, search. +:keywords: plugin, ai, artificial intelligence, query, search, llm, gpt, assistant :pluginname: AI Assistant :plugincode: ai :plugincategory: premium @@ -21,58 +21,28 @@ Once a response is generated and displayed within the dialog, the user can choos Users can retrieve a history of their conversations with the AI using the xref:#getThreadLog[`getThreadLog` API], including any discarded responses. -[NOTE] -.{pluginname} demo -==== -Demos containing the {pluginname} plugin are currently only available on our main website. Check out https://www.tiny.cloud/tinymce/features/ai-integration/[the {pluginname} demo], or the https://www.tiny.cloud/[demo on our home page], to try it out today. -==== +== Interactive example + +NOTE: This example uses a proxy endpoint to communicate with the OpenAI API. This is done to avoid exposing the API key in the client-side code. For more information on using a proxy server with the {pluginname} plugin, see the xref:ai-proxy.adoc[AI Proxy Server reference guide]. + +liveDemo::ai[] == Basic setup -To add the {pluginname} plugin to the editor, add both `{plugincode}` to the `plugins` option in the editor configuration and the `ai_request` function to the editor configuration. +To add the {pluginname} plugin to the editor, follow these steps: -For example, interfacing with the OpenAI Completions API: +- Add `{plugincode}` to the `plugins` option in the editor configuration. +- Add the `ai_request` function to the editor configuration. + +For example: [source,js] ---- -// This example stores the API key in the client side integration. This is not recommended for any purpose. -// Instead, an alternate method for retrieving the API key should be used. -const api_key = ''; - tinymce.init({ - selector: 'textarea', // Change this value according to your HTML + selector: 'textarea', // change this value according to your HTML plugins: 'ai', toolbar: 'aidialog aishortcuts', - ai_request: (request, respondWith) => { - const openAiOptions = { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${api_key}` - }, - body: JSON.stringify({ - model: 'gpt-3.5-turbo', - temperature: 0.7, - max_tokens: 800, - messages: [{ role: 'user', content: request.prompt }], - }) - }; - respondWith.string((signal) => window.fetch('https://api.openai.com/v1/chat/completions', { signal, ...openAiOptions }) - .then(async (response) => { - if (response) { - const data = await response.json(); - if (data.error) { - throw new Error(`${data.error.type}: ${data.error.message}`); - } else if (response.ok) { - // Extract the response content from the data returned by the API - return data?.choices[0]?.message?.content?.trim(); - } - } else { - throw new Error('Failed to communicate with the ChatGPT API'); - } - }) - ); - } + ai_request: , }); ---- @@ -93,9 +63,9 @@ NOTE: The xref:ai-proxy.adoc[AI Proxy Server reference guide] is, as its name no The following configuration options affect the behavior of the {pluginname} plugin. -include::partial$configuration/ai_request.adoc[][leveloffset=+1] +include::partial$configuration/ai_request.adoc[leveloffset=+1] -include::partial$configuration/ai_shortcuts.adoc[][leveloffset=+1] +include::partial$configuration/ai_shortcuts.adoc[leveloffset=+1] include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] diff --git a/modules/ROOT/pages/apis/tinymce.dom.domutils.adoc b/modules/ROOT/pages/apis/tinymce.dom.domutils.adoc index eaf1691059..f524798708 100644 --- a/modules/ROOT/pages/apis/tinymce.dom.domutils.adoc +++ b/modules/ROOT/pages/apis/tinymce.dom.domutils.adoc @@ -48,6 +48,8 @@ available. If it's not, it will fall back to the custom TinyMCE implementation.| |xref:#encode[encode()]|Entity encodes a string. This method encodes the most common entities, such as `<`, `>`, `"` and `&`.|`xref:apis/tinymce.dom.domutils.adoc[DOMUtils]` |xref:#findCommonAncestor[findCommonAncestor()]|Find the common ancestor of two elements. This is a shorter method than using the DOM Range logic.|`xref:apis/tinymce.dom.domutils.adoc[DOMUtils]` |xref:#fire[fire()]|Fires the specified event name and optional object on the specified target. + + __Deprecated in TinyMCE 6.0 and has been marked for removal in TinyMCE 7.0. Use `dispatch` instead.__|`xref:apis/tinymce.dom.domutils.adoc[DOMUtils]` |xref:#get[get()]|Returns the specified element by ID or the input element if it isn't a string.|`xref:apis/tinymce.dom.domutils.adoc[DOMUtils]` |xref:#getAttrib[getAttrib()]|Returns the specified attribute by name.|`xref:apis/tinymce.dom.domutils.adoc[DOMUtils]` @@ -396,6 +398,8 @@ Find the common ancestor of two elements. This is a shorter method than using th fire(target: Node | Document | Window, name: String, evt: Object): Event ---- Fires the specified event name and optional object on the specified target. + + __Deprecated in TinyMCE 6.0 and has been marked for removal in TinyMCE 7.0. Use `dispatch` instead.__ ==== Parameters diff --git a/modules/ROOT/pages/apis/tinymce.dom.eventutils.adoc b/modules/ROOT/pages/apis/tinymce.dom.eventutils.adoc index 0a97e77422..71e2f5d1d3 100644 --- a/modules/ROOT/pages/apis/tinymce.dom.eventutils.adoc +++ b/modules/ROOT/pages/apis/tinymce.dom.eventutils.adoc @@ -19,6 +19,8 @@ This class wraps the browsers native event logic with more convenient methods. listeners to child nodes within that target.|`xref:apis/tinymce.dom.eventutils.adoc[EventUtils]` |xref:#dispatch[dispatch()]|Dispatches the specified event on the specified target.|`xref:apis/tinymce.dom.eventutils.adoc[EventUtils]` |xref:#fire[fire()]|Fires the specified event on the specified target. + + __Deprecated in TinyMCE 6.0 and has been marked for removal in TinyMCE 7.0. Use `dispatch` instead.__|`xref:apis/tinymce.dom.eventutils.adoc[EventUtils]` |xref:#unbind[unbind()]|Unbinds the specified event by name, name and callback or all events on the target.|`xref:apis/tinymce.dom.eventutils.adoc[EventUtils]` |=== @@ -93,6 +95,8 @@ Dispatches the specified event on the specified target. fire(target: Object, name: String, args: Object): EventUtils ---- Fires the specified event on the specified target. + + __Deprecated in TinyMCE 6.0 and has been marked for removal in TinyMCE 7.0. Use `dispatch` instead.__ ==== Parameters diff --git a/modules/ROOT/pages/apis/tinymce.editor.adoc b/modules/ROOT/pages/apis/tinymce.editor.adoc index f5a4852c8b..d67d64611b 100644 --- a/modules/ROOT/pages/apis/tinymce.editor.adoc +++ b/modules/ROOT/pages/apis/tinymce.editor.adoc @@ -83,11 +83,13 @@ manipulation functions.|`xref:apis/tinymce.editor.adoc[Editor]` that could leak memory. This method will be called automatically when the page is unloaded but you can also call it directly if you know what you are doing.|`xref:apis/tinymce.editor.adoc[Editor]` |xref:#dispatch[dispatch()]|Dispatches the specified event by name. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event.|`xref:apis/tinymce.util.observable.adoc[Observable]` +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event.|`xref:apis/tinymce.util.observable.adoc[Observable]` |xref:#execCommand[execCommand()]|Executes a registered command on the current instance. A list of available commands can be found in the tinymce command identifiers documentation.|`xref:apis/tinymce.editor.adoc[Editor]` |xref:#fire[fire()]|Fires the specified event by name. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event. +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event. + + __Deprecated in TinyMCE 6.0 and has been marked for removal in TinyMCE 7.0. Use `dispatch` instead.__|`xref:apis/tinymce.util.observable.adoc[Observable]` |xref:#focus[focus()]|Focuses/activates the editor. This will set this editor as the activeEditor in the tinymce collection it will also place DOM focus inside the editor.|`xref:apis/tinymce.editor.adoc[Editor]` @@ -102,6 +104,8 @@ holds the iframe or the editable element.|`xref:apis/tinymce.editor.adoc[Editor] |xref:#getDoc[getDoc()]|Returns the iframes document object.|`xref:apis/tinymce.editor.adoc[Editor]` |xref:#getElement[getElement()]|Returns the target element/textarea that got replaced with a TinyMCE editor instance.|`xref:apis/tinymce.editor.adoc[Editor]` |xref:#getParam[getParam()]|Returns a configuration parameter by name. + + __Deprecated in TinyMCE 6.0 and has been marked for removal in TinyMCE 7.0. Use the `editor.options.get` API instead.__|`xref:apis/tinymce.editor.adoc[Editor]` |xref:#getWin[getWin()]|Returns the iframes window object.|`xref:apis/tinymce.editor.adoc[Editor]` |xref:#hasEditableRoot[hasEditableRoot()]|Returns the current editable state of the editor's root element.|`xref:apis/tinymce.editor.adoc[Editor]` @@ -121,11 +125,11 @@ so all events etc that method has will get dispatched as well.|`xref:apis/tinymc |xref:#nodeChanged[nodeChanged()]|Dispatches out a onNodeChange event to all observers. This method should be called when you need to update the UI states or element path etc.|`xref:apis/tinymce.editor.adoc[Editor]` |xref:#off[off()]|Unbinds an event listener to a specific event by name. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event.|`xref:apis/tinymce.util.observable.adoc[Observable]` +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event.|`xref:apis/tinymce.util.observable.adoc[Observable]` |xref:#on[on()]|Binds an event listener to a specific event by name. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event.|`xref:apis/tinymce.util.observable.adoc[Observable]` +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event.|`xref:apis/tinymce.util.observable.adoc[Observable]` |xref:#once[once()]|Bind the event callback and once it fires the callback is removed. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event.|`xref:apis/tinymce.util.observable.adoc[Observable]` +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event.|`xref:apis/tinymce.util.observable.adoc[Observable]` |xref:#queryCommandState[queryCommandState()]|Returns a command specific state, for example if bold is enabled or not.|`xref:apis/tinymce.editor.adoc[Editor]` |xref:#queryCommandSupported[queryCommandSupported()]|Returns true/false if the command is supported or not.|`xref:apis/tinymce.editor.adoc[Editor]` |xref:#queryCommandValue[queryCommandValue()]|Returns a command specific value, for example the current font size.|`xref:apis/tinymce.editor.adoc[Editor]` @@ -138,6 +142,8 @@ This method will move the HTML contents from the editor into that textarea or di so all events etc that method has will get dispatched as well.|`xref:apis/tinymce.editor.adoc[Editor]` |xref:#setContent[setContent()]|Sets the specified content to the editor instance, this will cleanup the content before it gets set using the different cleanup rules options. + + __Note: The content return value was deprecated in TinyMCE 6.0 and has been marked for removal in TinyMCE 7.0.__|`xref:apis/tinymce.editor.adoc[Editor]` |xref:#setDirty[setDirty()]|Explicitly sets the dirty state. This will fire the dirty event if the editor dirty state is changed from false to true by invoking this method.|`xref:apis/tinymce.editor.adoc[Editor]` @@ -336,7 +342,7 @@ but you can also call it directly if you know what you are doing. dispatch(name: String, args: Object?, bubble: Boolean?): Object ---- Dispatches the specified event by name. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event. +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event. ==== Examples [source, javascript] @@ -385,7 +391,9 @@ the tinymce command identifiers documentation. fire(name: String, args: Object?, bubble: Boolean?): Object ---- Fires the specified event by name. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event. +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event. + + __Deprecated in TinyMCE 6.0 and has been marked for removal in TinyMCE 7.0. Use `dispatch` instead.__ ==== Examples @@ -533,6 +541,8 @@ Returns the target element/textarea that got replaced with a TinyMCE editor inst getParam(name: String, defaultVal: String, type: String): String ---- Returns a configuration parameter by name. + + __Deprecated in TinyMCE 6.0 and has been marked for removal in TinyMCE 7.0. Use the `editor.options.get` API instead.__ ==== Examples @@ -751,7 +761,7 @@ need to update the UI states or element path etc. off(name: String?, callback: Function?): Object ---- Unbinds an event listener to a specific event by name. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event. +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event. ==== Examples [source, javascript] @@ -784,7 +794,7 @@ instance.off(); on(name: String, callback: Function, prepend: Boolean): Object ---- Binds an event listener to a specific event by name. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event. +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event. ==== Examples [source, javascript] @@ -813,7 +823,7 @@ instance.on('event', (e) => { once(name: String, callback: Function): Object ---- Bind the event callback and once it fires the callback is removed. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event. +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event. ==== Parameters @@ -943,6 +953,8 @@ setContent(content: String, args: Object): String ---- Sets the specified content to the editor instance, this will cleanup the content before it gets set using the different cleanup rules options. + + __Note: The content return value was deprecated in TinyMCE 6.0 and has been marked for removal in TinyMCE 7.0.__ ==== Examples diff --git a/modules/ROOT/pages/apis/tinymce.editor.ui.registry.adoc b/modules/ROOT/pages/apis/tinymce.editor.ui.registry.adoc index 44025a5f98..967af87c39 100644 --- a/modules/ROOT/pages/apis/tinymce.editor.ui.registry.adoc +++ b/modules/ROOT/pages/apis/tinymce.editor.ui.registry.adoc @@ -1,7 +1,7 @@ = tinymce.editor.ui.Registry :navtitle: tinymce.editor.ui.Registry :description: TinyMCE UI registration API. -:keywords: addAutocompleter, addButton, addContextForm, addContextMenu, addContextToolbar, addGroupToolbarButton, addIcon, addMenuButton, addMenuItem, addNestedMenuItem, addSidebar, addSplitButton, addToggleButton, addToggleMenuItem, addView +:keywords: addAutocompleter, addButton, addContext, addContextForm, addContextMenu, addContextToolbar, addGroupToolbarButton, addIcon, addMenuButton, addMenuItem, addNestedMenuItem, addSidebar, addSplitButton, addToggleButton, addToggleMenuItem, addView :moxie-type: api TinyMCE UI registration API. @@ -17,36 +17,55 @@ TinyMCE UI registration API. |xref:#addAutocompleter[addAutocompleter()]|Registers a new auto completer component. When a configured string pattern is matched in the content while typing, the autocompleter will be triggered. Emoticons and Charmap use an autocompleter. + + For information on creating an autocompleter, see: link:https://www.tiny.cloud/docs/tinymce/7/autocompleter/[ UI Components - Autocompleter].|`xref:apis/tinymce.editor.ui.registry.adoc[Registry]` |xref:#addButton[addButton()]|Registers a new toolbar button that executes a command when clicked or activated via keyboard navigation controls. + + For information on creating a basic toolbar button, see: link:https://www.tiny.cloud/docs/tinymce/7/custom-basic-toolbar-button/[ UI Components - Types of toolbar buttons: Basic button].|`xref:apis/tinymce.editor.ui.registry.adoc[Registry]` +|xref:#addContext[addContext()]|Registers a new context configuration in the registry. +The registry stores all context configurations. +The buttons in editor configuration object can contain a context property. +These button specifications can use the registered contexts to determine +whether to enable or disable the buttons based on the current context.|`xref:apis/tinymce.editor.ui.registry.adoc[Registry]` |xref:#addContextForm[addContextForm()]|Registers a new contextual form item. Similar to a context menu item, a contextual form is an item with an input form element appearing when a content predicate is matched. An example of a contextual form is the link plugin when the configuration { link_context_toolbar: true } is used. When the cursor is on a link, a contextual input form appears allowing for quick changes to the url field. + + For information on creating context forms, see: link:https://www.tiny.cloud/docs/tinymce/7/contextform/[ UI Components - Context forms].|`xref:apis/tinymce.editor.ui.registry.adoc[Registry]` |xref:#addContextMenu[addContextMenu()]|Registers a new context menu section that only appears when a content predicate is matched, for example, the cursor is inside a table. + + For information on creating context menus, see: link:https://www.tiny.cloud/docs/tinymce/7/contextmenu/[ UI Components - Context Menu].|`xref:apis/tinymce.editor.ui.registry.adoc[Registry]` |xref:#addContextToolbar[addContextToolbar()]|Registers a new context toolbar that only appears when a content predicate is matched for example the cursor is on an image element. + + For information on creating context toolbars, see: -link:https://www.tiny.cloud/docs/tinymce/6/contexttoolbar/[ +link:https://www.tiny.cloud/docs/tinymce/7/contexttoolbar/[ UI Components - Context Toolbar].|`xref:apis/tinymce.editor.ui.registry.adoc[Registry]` |xref:#addGroupToolbarButton[addGroupToolbarButton()]|Registers a new group toolbar button for the toolbar. Renders a toolbar button that opens a floating toolbar when clicked. + + **Note:** Group toolbar buttons can only be used when using the floating toolbar mode. + + For information on creating a group toolbar button, see: link:https://www.tiny.cloud/docs/tinymce/7/custom-group-toolbar-button/[ UI Components - Types of toolbar buttons: Group toolbar button].|`xref:apis/tinymce.editor.ui.registry.adoc[Registry]` @@ -56,17 +75,23 @@ to the editor instance it was configured for.|`xref:apis/tinymce.editor.ui.regis |xref:#addMenuButton[addMenuButton()]|Registers a new menu button. Adds a toolbar button that opens a menu when clicked. The menu can be populated by items created by addMenuItem, addNestedMenuItem or addToggleMenuItem. + + For information on creating a toolbar menu button, see: link:https://www.tiny.cloud/docs/tinymce/7/custom-menu-toolbar-button/[ UI Components - Types of toolbar buttons: Menu button].|`xref:apis/tinymce.editor.ui.registry.adoc[Registry]` |xref:#addMenuItem[addMenuItem()]|Registers a new menu item that executes a command when clicked or activated via keyboard navigation controls. + + For information on creating a basic menu item, see: link:https://www.tiny.cloud/docs/tinymce/7/creating-custom-menu-items/[ UI Components - Custom menu items: Basic menu items].|`xref:apis/tinymce.editor.ui.registry.adoc[Registry]` |xref:#addNestedMenuItem[addNestedMenuItem()]|Registers a new menu item that reveals a submenu when clicked or activated by keyboard navigation controls.The submenu can be populated by items created by addMenuItem, addNestedMenuItem or addToggleMenuItem. + + For information on creating a nested menu item, see: link:https://www.tiny.cloud/docs/tinymce/7/custom-nested-menu-items/[ UI Components - Custom menu items: Nested menu items].|`xref:apis/tinymce.editor.ui.registry.adoc[Registry]` @@ -77,21 +102,29 @@ button with the same sidebar name is created. Additionally there is a ToggleSidebar command and a 'ToggleSidebar' event that can used to manage the sidebar open/closed state. The tinycomments plugin uses a sidebar for its Ui components. + + For information on creating a custom sidebar, see: link:https://www.tiny.cloud/docs/tinymce/7/customsidebar/[ UI Components - Custom sidebar].|`xref:apis/tinymce.editor.ui.registry.adoc[Registry]` |xref:#addSplitButton[addSplitButton()]|Registers a new split button for the toolbar. The list styles plugin uses a split button to simplify its functionality. + + For information on creating a split toolbar button, see: link:https://www.tiny.cloud/docs/tinymce/7/custom-split-toolbar-button/[ UI Components - Types of toolbar buttons: Split button].|`xref:apis/tinymce.editor.ui.registry.adoc[Registry]` |xref:#addToggleButton[addToggleButton()]|Registers a new toggle button for the toolbar. A toggle buttons state can be set in the configuration. + + For information on creating a toggle toolbar button, see: link:https://www.tiny.cloud/docs/tinymce/7/custom-toggle-toolbar-button/[ UI Components - Types of toolbar buttons: Toggle button].|`xref:apis/tinymce.editor.ui.registry.adoc[Registry]` |xref:#addToggleMenuItem[addToggleMenuItem()]|Registers a new menu item that will act like a toggle button, showing a tick in the menu item to represent state. + + For information on creating a toggle menu item, see: link:https://www.tiny.cloud/docs/tinymce/7/custom-toggle-menu-items/[ UI Components - Custom menu items: Toggle menu items].|`xref:apis/tinymce.editor.ui.registry.adoc[Registry]` @@ -103,6 +136,8 @@ When it is off, the specific view is hidden and the main view is shown. There is also a ToggleView command. The ToggleView command can toggle the view visibility. The ToggleView command can be queried for its current state. + + For information on creating a custom view, see: link:https://www.tiny.cloud/docs/tinymce/7/custom-view/[ UI Components - Custom view].|`xref:apis/tinymce.editor.ui.registry.adoc[Registry]` @@ -120,6 +155,8 @@ addAutocompleter(name: String, obj: InlineContent.AutocompleterSpec) Registers a new auto completer component. When a configured string pattern is matched in the content while typing, the autocompleter will be triggered. Emoticons and Charmap use an autocompleter. + + For information on creating an autocompleter, see: link:https://www.tiny.cloud/docs/tinymce/7/autocompleter/[ UI Components - Autocompleter]. @@ -139,6 +176,8 @@ addButton(name: String, obj: Toolbar.ToolbarButtonSpec) ---- Registers a new toolbar button that executes a command when clicked or activated via keyboard navigation controls. + + For information on creating a basic toolbar button, see: link:https://www.tiny.cloud/docs/tinymce/7/custom-basic-toolbar-button/[ UI Components - Types of toolbar buttons: Basic button]. @@ -150,6 +189,25 @@ UI Components - Types of toolbar buttons: Basic button]. ''' +[[addContext]] +=== addContext() +[source, javascript] +---- +addContext(name: String, pred: Function) +---- +Registers a new context configuration in the registry. +The registry stores all context configurations. +The buttons in editor configuration object can contain a context property. +These button specifications can use the registered contexts to determine +whether to enable or disable the buttons based on the current context. + +==== Parameters + +* `name (String)` - Unique name identifying the new context configuration. +* `pred (Function)` - A predicate function that determines if the context is active + +''' + [[addContextForm]] === addContextForm() [source, javascript] @@ -162,6 +220,8 @@ form element appearing when a content predicate is matched. An example of a contextual form is the link plugin when the configuration { link_context_toolbar: true } is used. When the cursor is on a link, a contextual input form appears allowing for quick changes to the url field. + + For information on creating context forms, see: link:https://www.tiny.cloud/docs/tinymce/7/contextform/[ UI Components - Context forms]. @@ -181,6 +241,8 @@ addContextMenu(name: String, obj: Menu.ContextMenuSpec) ---- Registers a new context menu section that only appears when a content predicate is matched, for example, the cursor is inside a table. + + For information on creating context menus, see: link:https://www.tiny.cloud/docs/tinymce/7/contextmenu/[ UI Components - Context Menu]. @@ -200,8 +262,10 @@ addContextToolbar(name: String, obj: Toolbar.ContextToolbarSpec) ---- Registers a new context toolbar that only appears when a content predicate is matched for example the cursor is on an image element. + + For information on creating context toolbars, see: -link:https://www.tiny.cloud/docs/tinymce/6/contexttoolbar/[ +link:https://www.tiny.cloud/docs/tinymce/7/contexttoolbar/[ UI Components - Context Toolbar]. ==== Parameters @@ -219,7 +283,11 @@ addGroupToolbarButton(name: String, obj: Toolbar.GroupToolbarButtonSpec) ---- Registers a new group toolbar button for the toolbar. Renders a toolbar button that opens a floating toolbar when clicked. + + **Note:** Group toolbar buttons can only be used when using the floating toolbar mode. + + For information on creating a group toolbar button, see: link:https://www.tiny.cloud/docs/tinymce/7/custom-group-toolbar-button/[ UI Components - Types of toolbar buttons: Group toolbar button]. @@ -264,6 +332,8 @@ addMenuButton(name: String, obj: Toolbar.ToolbarMenuButtonSpec) Registers a new menu button. Adds a toolbar button that opens a menu when clicked. The menu can be populated by items created by addMenuItem, addNestedMenuItem or addToggleMenuItem. + + For information on creating a toolbar menu button, see: link:https://www.tiny.cloud/docs/tinymce/7/custom-menu-toolbar-button/[ UI Components - Types of toolbar buttons: Menu button]. @@ -283,6 +353,8 @@ addMenuItem(name: String, obj: Menu.MenuItemSpec) ---- Registers a new menu item that executes a command when clicked or activated via keyboard navigation controls. + + For information on creating a basic menu item, see: link:https://www.tiny.cloud/docs/tinymce/7/creating-custom-menu-items/[ UI Components - Custom menu items: Basic menu items]. @@ -303,6 +375,8 @@ addNestedMenuItem(name: String, obj: Menu.NestedMenuItemSpec) Registers a new menu item that reveals a submenu when clicked or activated by keyboard navigation controls.The submenu can be populated by items created by addMenuItem, addNestedMenuItem or addToggleMenuItem. + + For information on creating a nested menu item, see: link:https://www.tiny.cloud/docs/tinymce/7/custom-nested-menu-items/[ UI Components - Custom menu items: Nested menu items]. @@ -327,6 +401,8 @@ button with the same sidebar name is created. Additionally there is a ToggleSidebar command and a 'ToggleSidebar' event that can used to manage the sidebar open/closed state. The tinycomments plugin uses a sidebar for its Ui components. + + For information on creating a custom sidebar, see: link:https://www.tiny.cloud/docs/tinymce/7/customsidebar/[ UI Components - Custom sidebar]. @@ -346,6 +422,8 @@ addSplitButton(name: String, obj: Toolbar.ToolbarSplitButtonSpec) ---- Registers a new split button for the toolbar. The list styles plugin uses a split button to simplify its functionality. + + For information on creating a split toolbar button, see: link:https://www.tiny.cloud/docs/tinymce/7/custom-split-toolbar-button/[ UI Components - Types of toolbar buttons: Split button]. @@ -365,6 +443,8 @@ addToggleButton(name: String, obj: Toolbar.ToolbarToggleButtonSpec) ---- Registers a new toggle button for the toolbar. A toggle buttons state can be set in the configuration. + + For information on creating a toggle toolbar button, see: link:https://www.tiny.cloud/docs/tinymce/7/custom-toggle-toolbar-button/[ UI Components - Types of toolbar buttons: Toggle button]. @@ -384,6 +464,8 @@ addToggleMenuItem(name: String, obj: Menu.ToggleMenuItemSpec) ---- Registers a new menu item that will act like a toggle button, showing a tick in the menu item to represent state. + + For information on creating a toggle menu item, see: link:https://www.tiny.cloud/docs/tinymce/7/custom-toggle-menu-items/[ UI Components - Custom menu items: Toggle menu items]. @@ -409,6 +491,8 @@ When it is off, the specific view is hidden and the main view is shown. There is also a ToggleView command. The ToggleView command can toggle the view visibility. The ToggleView command can be queried for its current state. + + For information on creating a custom view, see: link:https://www.tiny.cloud/docs/tinymce/7/custom-view/[ UI Components - Custom view]. diff --git a/modules/ROOT/pages/apis/tinymce.editor.ui.ui.adoc b/modules/ROOT/pages/apis/tinymce.editor.ui.ui.adoc index f1da76e1a6..5fbc55fcc6 100644 --- a/modules/ROOT/pages/apis/tinymce.editor.ui.ui.adoc +++ b/modules/ROOT/pages/apis/tinymce.editor.ui.ui.adoc @@ -25,6 +25,8 @@ This editor ui instance. |Name|Summary|Defined by |xref:#tinymce.editor.ui.hide[tinymce.editor.ui.hide()]|Hides the editor user interface for inline editors. This method affects all user interface elements, including: menu bar, toolbar, notifications, and dialogs. + + If the `toolbar_persist` option is set to `true` and this method is used, the user interface will remain hidden, regardless of focus.|`xref:apis/tinymce.editor.ui.ui.adoc[Ui]` |xref:#tinymce.editor.ui.isEnabled[tinymce.editor.ui.isEnabled()]|Determines if the editor user interface is `enabled` (`true`) or `disabled` (`false`).|`xref:apis/tinymce.editor.ui.ui.adoc[Ui]` @@ -33,6 +35,8 @@ This method affects all user interface elements, including: menu bar, toolbar, notifications, and dialogs. Can not be set to 'true' when in readonly mode.|`xref:apis/tinymce.editor.ui.ui.adoc[Ui]` |xref:#tinymce.editor.ui.show[tinymce.editor.ui.show()]|Reveals the editor user interface for inline editors. This method affects all user interface elements, including: menu bar, toolbar, notifications, and dialogs. + + If the `toolbar_persist` option is set to `true` and this method is used, the user interface will remain visible, regardless of focus.|`xref:apis/tinymce.editor.ui.ui.adoc[Ui]` |=== @@ -48,6 +52,8 @@ tinymce.editor.ui.hide() ---- Hides the editor user interface for inline editors. This method affects all user interface elements, including: menu bar, toolbar, notifications, and dialogs. + + If the `toolbar_persist` option is set to `true` and this method is used, the user interface will remain hidden, regardless of focus. @@ -91,6 +97,8 @@ tinymce.editor.ui.show() ---- Reveals the editor user interface for inline editors. This method affects all user interface elements, including: menu bar, toolbar, notifications, and dialogs. + + If the `toolbar_persist` option is set to `true` and this method is used, the user interface will remain visible, regardless of focus. diff --git a/modules/ROOT/pages/apis/tinymce.editoroptions.adoc b/modules/ROOT/pages/apis/tinymce.editoroptions.adoc index 6e8e871531..4057cd02e9 100644 --- a/modules/ROOT/pages/apis/tinymce.editoroptions.adoc +++ b/modules/ROOT/pages/apis/tinymce.editoroptions.adoc @@ -1,23 +1,47 @@ = tinymce.EditorOptions :navtitle: tinymce.EditorOptions :description: TinyMCE Editor Options API. The options API provides the ability to register, lookup and set editor options. -:keywords: get, isRegistered, isSet, register, set, unset +:keywords: debug, get, isRegistered, isSet, register, set, unset :moxie-type: api TinyMCE Editor Options API. The options API provides the ability to register, lookup and set editor options. All options need to be registered before they can be used in the editor. This is done by using the `register()` API which requires a name and an option specification. The specification should contain a `processor` and an optional `default` value. The processor is used to parse and validate the option value either passed in the initial configuration or via the `set()` API. + + + + The processor can either be a custom function that returns if the option value is valid, or one of the following built-in processors: + + + + - `string` + + - `number` + + - `boolean` + + - `array` + + - `function` + + - `object` + + - `string[]` + + - `object[]` + + - `regexp` [[examples]] @@ -45,6 +69,7 @@ editor.options.set('custom_option', 'value'); [cols="2,5,1",options="header"] |=== |Name|Summary|Defined by +|xref:#debug[debug()]|Logs the initial raw editor options to the console.|`xref:apis/tinymce.editoroptions.adoc[EditorOptions]` |xref:#get[get()]|Get the value of a registered option.|`xref:apis/tinymce.editoroptions.adoc[EditorOptions]` |xref:#isRegistered[isRegistered()]|Check if an option has been registered.|`xref:apis/tinymce.editoroptions.adoc[EditorOptions]` |xref:#isSet[isSet()]|Checks to see if a value has been set for the specified option.|`xref:apis/tinymce.editoroptions.adoc[EditorOptions]` @@ -56,6 +81,16 @@ editor.options.set('custom_option', 'value'); [[methods]] == Methods +[[debug]] +=== debug() +[source, javascript] +---- +debug() +---- +Logs the initial raw editor options to the console. + +''' + [[get]] === get() [source, javascript] diff --git a/modules/ROOT/pages/apis/tinymce.notificationmanager.adoc b/modules/ROOT/pages/apis/tinymce.notificationmanager.adoc index ecc9dbd46c..5452acd681 100644 --- a/modules/ROOT/pages/apis/tinymce.notificationmanager.adoc +++ b/modules/ROOT/pages/apis/tinymce.notificationmanager.adoc @@ -69,6 +69,10 @@ Opens a new notification. * `args (Object)` - A `name: value` collection containing settings such as: `timeout`, `type`, and message (`text`). -For information on the available settings, see: link:https://www.tiny.cloud/docs/tinymce/6/creating-custom-notifications/[Create custom notifications]. + + + + +For information on the available settings, see: link:https://www.tiny.cloud/docs/tinymce/7/creating-custom-notifications/[Create custom notifications]. ''' diff --git a/modules/ROOT/pages/apis/tinymce.plugin.adoc b/modules/ROOT/pages/apis/tinymce.plugin.adoc index 96bfa1480b..b07df128c9 100644 --- a/modules/ROOT/pages/apis/tinymce.plugin.adoc +++ b/modules/ROOT/pages/apis/tinymce.plugin.adoc @@ -8,8 +8,16 @@ TinyMCE plugin psuedo class. Allows for custom plugins to be added to TinyMCE wh This is a pseudo class that describes how to create a custom plugin for TinyMCE. + + + + A custom plugin registered using `PluginManager.add` should either not return any value or return plugin metadata as an object that contains the plugin's name and a URL. The URL is intended to link to help documentation. + + + + See AddOnManager for more information about the methods available on the PluginManager instance. [[examples]] diff --git a/modules/ROOT/pages/apis/tinymce.root.adoc b/modules/ROOT/pages/apis/tinymce.root.adoc index 7a72048596..65c46cc4c4 100644 --- a/modules/ROOT/pages/apis/tinymce.root.adoc +++ b/modules/ROOT/pages/apis/tinymce.root.adoc @@ -52,7 +52,11 @@ Checks if the input object `obj` has the property `prop`.|`xref:apis/tinymce.roo |xref:#inArray[inArray()]|Returns an index of the item or -1 if item is not present in the array.|`xref:apis/tinymce.root.adoc[tinymce]` |xref:#init[init()]|Initializes a set of editors. This method will create editors based on various settings. -For information on basic usage of `init`, see: link:https://www.tiny.cloud/docs/tinymce/6/basic-setup/[Basic setup].|`xref:apis/tinymce.root.adoc[tinymce]` + + + + +For information on basic usage of `init`, see: link:https://www.tiny.cloud/docs/tinymce/7/basic-setup/[Basic setup].|`xref:apis/tinymce.root.adoc[tinymce]` |xref:#is[is()]|Checks if a object is of a specific type for example an array.|`xref:apis/tinymce.root.adoc[tinymce]` |xref:#isArray[isArray()]|Returns true/false if the object is an array or not.|`xref:apis/tinymce.root.adoc[tinymce]` |xref:#makeMap[makeMap()]|Makes a name/object map out of an array with names.|`xref:apis/tinymce.root.adoc[tinymce]` @@ -60,8 +64,16 @@ For information on basic usage of `init`, see: link:https://www.tiny.cloud/docs/ one array list into another.|`xref:apis/tinymce.root.adoc[tinymce]` |xref:#overrideDefaults[overrideDefaults()]|Overrides the default options for editor instances. The `overrideDefaults` method replaces the `defaultOptions`, including any set by a previous call to the `overrideDefaults` method. + + + + When using the Tiny Cloud, some of these defaults are required for the cloud-based editor to function. + + + + Therefore, when using `overrideDefaults` with the cloud-based editor, any newly integrated options must be combined with the options in `tinymce.defaultOptions`.|`xref:apis/tinymce.root.adoc[tinymce]` |xref:#remove[remove()]|Removes a editor or editors form page.|`xref:apis/tinymce.root.adoc[tinymce]` |xref:#resolve[resolve()]|Resolves a string and returns the object from a specific structure.|`xref:apis/tinymce.root.adoc[tinymce]` @@ -315,7 +327,11 @@ init(options: Object): Promise ---- Initializes a set of editors. This method will create editors based on various settings. -For information on basic usage of `init`, see: link:https://www.tiny.cloud/docs/tinymce/6/basic-setup/[Basic setup]. + + + + +For information on basic usage of `init`, see: link:https://www.tiny.cloud/docs/tinymce/7/basic-setup/[Basic setup]. ==== Examples [source, javascript] @@ -428,8 +444,16 @@ overrideDefaults(defaultOptions: Object) ---- Overrides the default options for editor instances. The `overrideDefaults` method replaces the `defaultOptions`, including any set by a previous call to the `overrideDefaults` method. + + + + When using the Tiny Cloud, some of these defaults are required for the cloud-based editor to function. + + + + Therefore, when using `overrideDefaults` with the cloud-based editor, any newly integrated options must be combined with the options in `tinymce.defaultOptions`. ==== Examples diff --git a/modules/ROOT/pages/apis/tinymce.theme.adoc b/modules/ROOT/pages/apis/tinymce.theme.adoc index ec9eb8f362..795d98a638 100644 --- a/modules/ROOT/pages/apis/tinymce.theme.adoc +++ b/modules/ROOT/pages/apis/tinymce.theme.adoc @@ -8,8 +8,16 @@ TinyMCE theme pseudo class. Allows for a custom theme to be used with TinyMCE wh This is a pseudo class that describes how to create a custom theme for TinyMCE. + + + + See AddOnManager for more information about the methods available on the ThemeManager instance. + + + + **Warning**: Much of TinyMCE's functionality is provided by the default Silver theme. Creating a custom theme may require the re-implementation of this functionality. To change TinyMCE's appearance, Tiny recommends changing the Skin instead. [[examples]] diff --git a/modules/ROOT/pages/apis/tinymce.util.eventdispatcher.adoc b/modules/ROOT/pages/apis/tinymce.util.eventdispatcher.adoc index e90a0f3c96..db67455205 100644 --- a/modules/ROOT/pages/apis/tinymce.util.eventdispatcher.adoc +++ b/modules/ROOT/pages/apis/tinymce.util.eventdispatcher.adoc @@ -26,7 +26,9 @@ eventDispatcher.dispatch('click', { data: 123 }); |Name|Summary|Defined by |xref:#dispatch[dispatch()]|Dispatches the specified event by name.|`xref:apis/tinymce.util.eventdispatcher.adoc[EventDispatcher]` |xref:#fire[fire()]|Fires the specified event by name. -__Deprecated in TinyMCE 6.0 and has been marked for removal in TinyMCE 7.0. Use `dispatch` instead.__|`xref:apis/tinymce.util.eventdispatcher.adoc[EventDispatcher]` + + +__Marked for removal in TinyMCE 8.0. Use `dispatch` instead.__|`xref:apis/tinymce.util.eventdispatcher.adoc[EventDispatcher]` |xref:#has[has()]|Returns true/false if the dispatcher has a event of the specified name.|`xref:apis/tinymce.util.eventdispatcher.adoc[EventDispatcher]` |xref:#isNative[isNative()]|Returns true/false if the specified event name is a native browser event or not.|`xref:apis/tinymce.util.eventdispatcher.adoc[EventDispatcher]` |xref:#off[off()]|Unbinds an event listener to a specific event by name.|`xref:apis/tinymce.util.eventdispatcher.adoc[EventDispatcher]` @@ -70,7 +72,9 @@ instance.dispatch('event', {...}); fire(name: String, args: Object?): Object ---- Fires the specified event by name. -__Deprecated in TinyMCE 6.0 and has been marked for removal in TinyMCE 7.0. Use `dispatch` instead.__ + + +__Marked for removal in TinyMCE 8.0. Use `dispatch` instead.__ ==== Examples [source, javascript] diff --git a/modules/ROOT/pages/apis/tinymce.util.observable.adoc b/modules/ROOT/pages/apis/tinymce.util.observable.adoc index 8f0329ccf1..ccdad4b6b2 100644 --- a/modules/ROOT/pages/apis/tinymce.util.observable.adoc +++ b/modules/ROOT/pages/apis/tinymce.util.observable.adoc @@ -15,17 +15,19 @@ This mixin adds event binding logic to classes. Adapts the EventDispatcher class |=== |Name|Summary|Defined by |xref:#dispatch[dispatch()]|Dispatches the specified event by name. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event.|`xref:apis/tinymce.util.observable.adoc[Observable]` +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event.|`xref:apis/tinymce.util.observable.adoc[Observable]` |xref:#fire[fire()]|Fires the specified event by name. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event. +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event. + + __Deprecated in TinyMCE 6.0 and has been marked for removal in TinyMCE 7.0. Use `dispatch` instead.__|`xref:apis/tinymce.util.observable.adoc[Observable]` |xref:#hasEventListeners[hasEventListeners()]|Returns true/false if the object has a event of the specified name.|`xref:apis/tinymce.util.observable.adoc[Observable]` |xref:#off[off()]|Unbinds an event listener to a specific event by name. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event.|`xref:apis/tinymce.util.observable.adoc[Observable]` +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event.|`xref:apis/tinymce.util.observable.adoc[Observable]` |xref:#on[on()]|Binds an event listener to a specific event by name. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event.|`xref:apis/tinymce.util.observable.adoc[Observable]` +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event.|`xref:apis/tinymce.util.observable.adoc[Observable]` |xref:#once[once()]|Bind the event callback and once it fires the callback is removed. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event.|`xref:apis/tinymce.util.observable.adoc[Observable]` +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event.|`xref:apis/tinymce.util.observable.adoc[Observable]` |=== [[methods]] @@ -38,7 +40,7 @@ link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more det dispatch(name: String, args: Object?, bubble: Boolean?): Object ---- Dispatches the specified event by name. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event. +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event. ==== Examples [source, javascript] @@ -65,7 +67,9 @@ instance.dispatch('event', {...}); fire(name: String, args: Object?, bubble: Boolean?): Object ---- Fires the specified event by name. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event. +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event. + + __Deprecated in TinyMCE 6.0 and has been marked for removal in TinyMCE 7.0. Use `dispatch` instead.__ ==== Examples @@ -111,7 +115,7 @@ Returns true/false if the object has a event of the specified name. off(name: String?, callback: Function?): Object ---- Unbinds an event listener to a specific event by name. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event. +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event. ==== Examples [source, javascript] @@ -144,7 +148,7 @@ instance.off(); on(name: String, callback: Function, prepend: Boolean): Object ---- Binds an event listener to a specific event by name. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event. +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event. ==== Examples [source, javascript] @@ -173,7 +177,7 @@ instance.on('event', (e) => { once(name: String, callback: Function): Object ---- Bind the event callback and once it fires the callback is removed. Consult the -link:https://www.tiny.cloud/docs/tinymce/6/events/[event reference] for more details on each event. +link:https://www.tiny.cloud/docs/tinymce/7/events/[event reference] for more details on each event. ==== Parameters diff --git a/modules/ROOT/pages/apis/tinymce.windowmanager.adoc b/modules/ROOT/pages/apis/tinymce.windowmanager.adoc index cebcb7f4d0..2686c2605f 100644 --- a/modules/ROOT/pages/apis/tinymce.windowmanager.adoc +++ b/modules/ROOT/pages/apis/tinymce.windowmanager.adoc @@ -119,8 +119,8 @@ Opens a new window. ==== Parameters -* `config (Object)` - For information on the available options, see: link:https://www.tiny.cloud/docs/tinymce/6/dialog-configuration/#options[Dialog - Configuration options]. -* `params (Object)` - (Optional) For information on the available options, see: link:https://www.tiny.cloud/docs/tinymce/6/dialog-configuration/#configuration-parameters[Dialog - Configuration parameters]. +* `config (Object)` - For information on the available options, see: link:https://www.tiny.cloud/docs/tinymce/7/dialog-configuration/#options[Dialog - Configuration options]. +* `params (Object)` - (Optional) For information on the available options, see: link:https://www.tiny.cloud/docs/tinymce/7/dialog-configuration/#configuration-parameters[Dialog - Configuration parameters]. ==== Return value @@ -138,7 +138,7 @@ Opens a new window for the specified url. ==== Parameters -* `config (Object)` - For information on the available options, see: link:https://www.tiny.cloud/docs/tinymce/6/urldialog/#configuration[URL dialog - Configuration]. +* `config (Object)` - For information on the available options, see: link:https://www.tiny.cloud/docs/tinymce/7/urldialog/#configuration[URL dialog - Configuration]. ==== Return value diff --git a/modules/ROOT/pages/available-menu-items.adoc b/modules/ROOT/pages/available-menu-items.adoc index 72cb36eab9..87c6c92433 100644 --- a/modules/ROOT/pages/available-menu-items.adoc +++ b/modules/ROOT/pages/available-menu-items.adoc @@ -150,6 +150,11 @@ include::partial$misc/plugin-menu-item-id-boilerplate.adoc[] :plugincode: lists include::partial$misc/plugin-menu-item-id-boilerplate.adoc[] +:plugincategory: premium +:pluginname: Math +:plugincode: math +include::partial$misc/plugin-menu-item-id-boilerplate.adoc[] + :plugincategory: opensource :pluginname: Media :plugincode: media diff --git a/modules/ROOT/pages/available-toolbar-buttons.adoc b/modules/ROOT/pages/available-toolbar-buttons.adoc index ecfe622049..aeb089d9cd 100644 --- a/modules/ROOT/pages/available-toolbar-buttons.adoc +++ b/modules/ROOT/pages/available-toolbar-buttons.adoc @@ -172,6 +172,11 @@ include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] :plugincode: lists include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] +:plugincategory: premium +:pluginname: Math +:plugincode: math +include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] + :plugincategory: opensource :pluginname: Media :plugincode: media diff --git a/modules/ROOT/pages/bundling-plugins.adoc b/modules/ROOT/pages/bundling-plugins.adoc index 721a60c14a..c6853f99f3 100644 --- a/modules/ROOT/pages/bundling-plugins.adoc +++ b/modules/ROOT/pages/bundling-plugins.adoc @@ -7,17 +7,13 @@ include::partial$module-loading/bundling-ref-example.adoc[] :!editorcomponent: -The following table shows examples of the syntax used to bundle the following plugin. +[NOTE] +If using {productname} 7.0.1 or earlier, please refer to link:https://www.tiny.cloud/docs/tinymce/6/bundling-plugins/[Bundling TinyMCE plugins using module loading] from the {productname} v6 documentation guide. -Required files for an example plugin: +include::partial$plugin-files/plugin-file-index.js.adoc[] -[source, js] ----- -./plugins/example/content.js // or './plugins/example/content_css.js' -./plugins/example/plugin.js ----- -Example syntax for including the example "plugin" in a bundle using `content.js` or `content_css.js` files for bundling: +Example syntax for including the example "" plugin in a bundle using `content.js`for bundling: [cols='1,1,4'] |=== @@ -28,18 +24,14 @@ Example syntax for including the example "plugin" in a bundle using `content.js` a| [source, js] ---- -import pluginCss from 'tinymce/plugins/example/content.js'; -//import pluginCss from 'tinymce/plugins/example/content_css.js'; -import 'tinymce/plugins/example'; +import 'tinymce/plugins/'; ---- |`.zip` a| [source, js] ---- -import '../tinymce/plugins/example/content.js'; -//import '../tinymce/plugins/example/content_css.js'; -import '../tinymce/plugins/example/plugin'; +import '../tinymce/plugins/'; ---- .2+|Common JS @@ -47,18 +39,14 @@ import '../tinymce/plugins/example/plugin'; a| [source, js] ---- -const pluginCss = require('tinymce/plugins/example/content.js'); -//require('tinymce/plugins/example/content_css.js'); -require('tinymce/plugins/example'); +require('tinymce/plugins/'); ---- |`.zip` a| [source, js] ---- -const pluginCss = require('../tinymce/plugins/example/content.js'); -//require('../tinymce/plugins/example/content_css.js'); -require('../tinymce/plugins/example/plugin.js'); +require('../tinymce/plugins/'); ---- |=== diff --git a/modules/ROOT/pages/changelog.adoc b/modules/ROOT/pages/changelog.adoc index 04dc8e542c..f634eb7061 100644 --- a/modules/ROOT/pages/changelog.adoc +++ b/modules/ROOT/pages/changelog.adoc @@ -1,13 +1,292 @@ = Changelog -:description: The history of TinyMCE releases. +:description: The history of {productname} releases. :keywords: changelog 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:7.6.0-release-notes.adoc[7.6.0 - 2024-12-11] -== 7.0.1 - 2024-04-10 +=== Added +* It is now possible to create labeled groups in context toolbars. +// #TINY-11095 +// * New `contextsliderform` and `contextsizeinput` context form types. +// #TINY-11342 +* New `back` function in `ContextFormApi` to go back to the previous toolbar. +// #TINY-11344 +* New `QuickbarInsertImage` command that is executed by the `quickimage` button. +// #TINY-11399 +* New `onSetup` function to the context form API. +// #TINY-11494 +* New `placeholder` to the context form input field API. +// #TINY-11459 +* New `disabled` option to restore the previous `readonly` mode behavior, allowing the editor to be displayed in a disabled state. +// #TINY-11488 + +=== Improved +* Base64 data was not properly decoded due to unhandled URL-encoded characters. +// #TINY-9548 +* The `latin` list style type is now recognized as an alias for the `alpha` list style type. +// #TINY-11515 + +=== Fixed +* Image selection was removed when calling `+editor.nodeChanged()+` while having focus inside the editor UI. +// #TINY-11437 +* Tooltip would not show for group toolbar button. +// #TINY-11391 +* Changing the table row type when a `+contenteditable=false+` cell was selected would not work as expected. +// #TINY-11383 +* The `samp` format was being applied as a `block` level format, instead of an `inline` format. +// #TINY-11390 +* Removed title attribute from dialog tree elements as they already have a tooltip. +// #TINY-11470 +* Fixed CSS bundling for skin UI content CSS. +// #TINY-11558 +* Fixed incorrect resource keys for CSS bundling JS files. +// #TINY-11558 + +== xref:7.5-release-notes.adoc[7.5.0 - 2024-11-06] + +=== Added + +* Added support for using raw CSS in the list of possible colors, using the `color_map_raw` property. +// #GH-9788 +// #TINY-11217 + +=== Improved + +* Improved color picker aria support. +// #TINY-11291 + +=== Fixed + +* Autocompleter would not activate after applying an inline format like font size in some cases. +// #TINY-11273 +* The `toolbar-sticky-offset` would still be applied after entering fullscreen mode. +// #TINY-11137 +* Text and background color toolbar buttons would not be fully greyed out in readonly mode. +// #TINY-11313 +* Closing a nested modal dialog would lose focus from the editor. +// #TINY-11153 +* Inability to type `{` character on German keyboard layouts. +// #TINY-11395 + +== xref:7.4.1-release-notes.adoc[7.4.1 - 2024-10-10] + +=== Fixed + +* Invalid HTML elements within SVG elements were not removed. +// #TINY-11332 + +== xref:7.4-release-notes.adoc[7.4.0 - 2024-10-09] + +=== Added + +* New `context` property for all ui components. +// #TINY-11211 +* Tree component now allows the addition of a custom icon. +// #TINY-11131 +* New option `allow_mathml_annotation_encodings` to opt-in to keep math annotations with specific encodings. +// #TINY-11166 + +=== Improved + +* In read-only mode the editor now allows normal cursor movement and block element selection, including video playback. +// #TINY-11264 +* Pasting a table now places the cursor after the table instead of into the last cell. +// #TINY-11082 +* Dialog list dropdown menus now close when the browser window resizes. +// #TINY-11123 + +=== Fixed + +* Mouse hover on partially visible dialog collection elements no longer scrolls. +// #TINY-9915 +* Caret would unexpectedly shift to the non-editable table row above when pressing Enter. +// #TINY-11077 +* Deleting a selection in a list element would sometimes prevent the `input` event from being dispatched. +// #TINY-11100 +* Placing the cursor after a table with a br after it would misplace added newlines before the table instead of after. +// #TINY-11110 +* Sidebar could not be toggled until the skin was loaded. +// #TINY-11155 +* The image dialog lost focus after closing an image upload error alert. +// #TINY-11159 +* Copying tables to the clipboard did not correctly separate cells and rows for the "text/plain" MIME type. +// #TINY-10847 +* The editor resize handle was incorrectly rendered when all components were removed from the status bar. +// #TINY-11257 + +== xref:7.3-release-notes.adoc[7.3.0 - 2024-08-07] + +=== Added +* Colorpicker number input fields now show an error tooltip and error icon when invalid text has been entered. +// #TINY-10799 + +=== Improved +* When a full document was loaded as editor content the head elements were added to the body. +// #TINY-11053 + +=== Fixed +* Unnecessary nbsp entities were inserted when typing at the edges of inline elements. +// #TINY-10854 +* Fixed JavaScript error when inserting a table using the context menu by adjusting the event order in `renderInsertTableMenuItem`. +// #TINY-6887 +* Notifications didn't position and resize properly when resizing the editor or toggling views. +// #TINY-10894 +* The pattern commands would execute even if the command was not enabled. +// #TINY-10994 +* Split button popups were incorrectly positioned when switching to fullscreen mode if the editor was inside a scrollable container. +// #TINY-10973 +* Sequential html comments would in some cases generate unwanted elements. +// #TINY-10955 +* The listbox component had a fixed width and was not a responsive ui element. +// #TINY-10884 +* Prevent default mousedown on toolbar buttons was causing misplaced focus bugs. +// #TINY-10638 +* Attempting to use focus commands on an editor where the cursor had last been in certain `+contentEditable="true"+` elements would fail. +// #TINY-11085 +* Colorpicker's hex-based input field showed the wrong validation error message. +// #TINY-11115 + +== xref:7.2.1-release-notes.adoc[7.2.1 - 2024-07-03] === Fixed +* Text content could move unexpectedly when deleting a paragraph. +// #TINY-10590 +* Cursor would shift to the start of the editor body when focus was shifted to a noneditable cell of a table. +// #TINY-10127 +* Long translations of the bottom help text would cause minor graphical issues. +// #TINY-10961 +* Open Link button was disabled when selection partially covered a link or when multiple links were selected. +// #TINY-11009 + +== xref:7.2-release-notes.adoc[7.2.0 - 2024-06-19] + +=== Added +* Added `options.debug` API that logs the initial raw editor options to console. +// #TINY-10605 +* Added `referrerpolicy` as a valid attribute for an iframe element. +// #TINY-10374 +* New `onInit` and `stretched` properties to the `HtmlPanel` dialog component. +// #TINY-10900 +* Added support for querying the state of the `mceTogglePlainTextPaste` command. +// #TINY-10938 +* Added `for` option to dialog label components to improve accessibility. The value must be another component on the same dialog. +// #TINY-10971 + +=== Improved +* Dialog slider components now emit an onChange event when using arrow keys. +// #TINY-10428 +* Accessibility for element path buttons, added tooltip to describe the button and removed incorrect `aria-level` attribute. +// #TINY-10891 +* Improve merging of inserted inline elements by removing nodes with redundant inheritable styles. +// #TINY-10869 +* Improved Find & Replace dialog accessibility by changing placeholders to labels. +// #TINY-10871 + +=== Changed +* Replaced tiny branding logo with `Build with TinyMCE` text and logo. +// #TINY-11001 + +=== Fixed +* Deleting in a `div` with preceding `br` elements would sometimes throw errors. +// #TINY-10840 +* `autoresize_bottom_margin` was not reliably applied in some situations. +// #TINY-10793 +* Fixed cases where adding a newline around a br, table or img would not move the cursor to a new line. +// #TINY-10384 +* Focusing on `contenteditable="true"` element when using `editable_root: false` and inline mode causing selection to be shifted. +// #TINY-10820 +* Corrected the `role` attribute on listbox dialog components to `combobox` when there are no nested menu items. +// #TINY-10807 +* HTML entities that were double decoded in `noscript` elements caused an XSS vulnerability. +// #TINY-11019 +* It was possible to inject XSS HTML that was not matching the regexp when using the `noneditable_regexp` option. +// #TINY-11022 + + +== xref:7.1.2-release-notes.adoc[7.1.2 - 2024-06-05] + +### Fixed +- CSS color values set to `transparent` were incorrectly converted to `+#000000+`. +// #TINY-10916 + +== xref:7.1.1-release-notes.adoc[7.1.1 - 2024-05-22] + +=== Fixed + +* Insert/Edit image dialog lost focus after the image upload completed. +// #TINY-10885 +* Deleting into a list from a paragraph that has an `img` tag could cause extra inline styles to be added. +// #TINY-10892 +* Resolved an issue where emojis configured with the `emojiimages` database were not loading correctly due to a broken CDN. +// #TINY-10878 +* Iframes in dialogs were not rendering rounded borders correctly. +// #TINY-10901 +* Autocompleter possible values are no longer capped at a length of 10. +// #TINY-10942 + +== xref:7.1-release-notes.adoc[7.1.0 - 2024-05-08] + +=== Added + +* New `math-equation` icon. +// #TINY-10804 + +=== Improved + +* Included `itemprop`, `itemscope`, and `itemtype` as valid HTML5 attributes in the core schema. +// #TINY-9932 +* Improved accessibility for notifications: added tooltips, keyboard navigation, and a shortcut to focus on notifications. +// #TINY-6925 +* Removed `aria-pressed` from the `More` button in sliding toolbar mode and replaced it with `aria-expanded`. +// #TINY-10795 +* The editor UI now renders correctly in Windows High Contrast Mode. +// #TINY-10781 + +=== Fixed + +* Backspacing in certain HTML setups caused data to move around unexpectedly. +// #TINY-10590 +* Dialog title markup was changed to use an `h1` element instead of a `div`. +// #TINY-10800 +* The dialog title was not announced in macOS VoiceOver; dialogs now use `aria-label` instead of `aria-labelledby` on macOS. +// #TINY-10808 +* The theme loader did not respect the suffix when loading skin CSS files. +// #TINY-10602 +* Custom block elements with colon characters would throw errors. +// #TINY-10813 +* Tab navigation in views didn't work. +// #TINY-10780 +* Video and audio elements couldn't be played on Safari. +// #TINY-10774 +* The `ToggleToolbarDrawer` command did not toggle the toolbar in `sliding` mode when the `skipFocus: true` parameter was passed. +// #TINY-10726 +* The buttons in the custom view header were clipped when overflowing. +// #TINY-10741 +* In the custom view, the scrollbar of the container was not visible if its height was greater than the editor. +// #TINY-10741 +* Fixed an accessibility issue by removing the duplicate `role="menu"` attribute from color swatches. +// #TINY-10806 +* Fullscreen mode now prevents focus from leaving the editor. +// #TINY-10597 +* The "Open Link" context menu action did not work when the selection surrounded a link. +// #TINY-10391 +* Styles were not retained when toggling a list on and off. +// #TINY-10837 +* Caret and placeholder text were invisible in Windows High Contrast Mode. +// #TINY-9811 +* Firefox did not announce the iframe title when `iframe_aria_text` was set. +// #TINY-10718 +* Notification width was not constrained to the width of the editor. +// #TINY-10886 +* The "Open Link" context menu action was not enabled for links on images. +// #TINY-10391 + +== xref:7.0.1-release-notes.adoc[7.0.1 - 2024-04-10] + +=== Fixed + * Toggle list behavior generated wrong HTML when the `forced_root_block` option was set to `div`. // #TINY-10488 * Tapping inside a composed text on Firefox Android would not close the autocompleter. @@ -19,13 +298,13 @@ NOTE: This is the {productname} Community version changelog. For information abo * The status bar was invisible when the editor's height was set to the minimum. // #TINY-10705 - -== 7.0.0 - 2024-03-20 +== xref:7.0-release-notes.adoc[7.0.0 - 2024-03-20] [NOTE] {productname} 7.0 is licensed under GPL Version 2 or later. This version introduces a new `license_key` configuration setting that gives self-hosted users the ability to select a usage under the GPL or to authenticate their paid license with Tiny. === Added + * New `license_key` option that must be set to `gpl` or a valid license key. // #TINY-10681 * New custom tooltip functionality, tooltip will be shown when hovering with a mouse or with keyboard focus. @@ -51,6 +330,7 @@ NOTE: This is the {productname} Community version changelog. For information abo * Added importword, exportpdf and exportword menu items to default file menu. === Improved + * Included keyboard shortcut in custom tooltip for `ToolbarButton` and `ToolbarToggleButton`. // #TINY-10487 * Improved showing which element has focus for keyboard navigation. @@ -63,6 +343,7 @@ NOTE: This is the {productname} Community version changelog. For information abo // #TINY-10658 === Changed + * {productname} is now licensed GPL Version 2 or later. // #TINY-10578 * `convert_unsafe_embeds` editor option is now defaulted to `true`. @@ -95,6 +376,7 @@ NOTE: This is the {productname} Community version changelog. For information abo // #TINY-10694 === Removed + * Deprecated `force_hex_color` option, with the default now being all colors are forced to hex format as lower case. // #TINY-10436 * Deprecated `remove_trailing_brs` option from DomParser. @@ -111,6 +393,7 @@ NOTE: This is the {productname} Community version changelog. For information abo // #TINY-10654 === Fixed + * When deleting the last row in a table, the cursor would jump to the first cell (top left), instead of moving to the next adjacent cell in some cases. // #TINY-6309 * Heading formatting would be partially applied to the content within the `summary` element when the caret was positioned between words. diff --git a/modules/ROOT/pages/cloud-deployment-guide.adoc b/modules/ROOT/pages/cloud-deployment-guide.adoc index 5dd9c1a977..daf7da9798 100644 --- a/modules/ROOT/pages/cloud-deployment-guide.adoc +++ b/modules/ROOT/pages/cloud-deployment-guide.adoc @@ -4,40 +4,40 @@ :type: folder // 2 Columns, both asciidoc -[cols=2*a] +[cols="1,1"] |=== -| +a| [.lead] xref:editor-and-features.adoc[Cloud deployment of editor & plugins] Learn how to set up the {productname} editor via the Cloud or migrate from a self-hosted environment. -| +a| [.lead] xref:features-only.adoc[Cloud deployment of plugins Only] Connect to Tiny Cloud within a hybrid deployment. -| +a| [.lead] -xref:editor-plugin-version.adoc[Specify editor & plugin versions] +xref:editor-plugin-version.adoc[Specify editor & plugins] -Specifying editor and plugin versions for Tiny Cloud deployments. +Specifying editor and plugins for Tiny Cloud deployments. -| +a| [.lead] xref:plugin-editor-version-compatibility.adoc[Version compatibility reference] Matrix of compatibility between TinyMCE editor versions and premium plugins. -| +a| [.lead] xref:cloud-troubleshooting.adoc[Cloud Troubleshooting] Troubleshooting errors shown by the Tiny Cloud. // Empty cell to even out rows -// | +a| |=== \ No newline at end of file diff --git a/modules/ROOT/pages/comments-access-options.adoc b/modules/ROOT/pages/comments-access-options.adoc new file mode 100644 index 0000000000..495952f526 --- /dev/null +++ b/modules/ROOT/pages/comments-access-options.adoc @@ -0,0 +1,14 @@ += Configuring the Comments plugin access option +:navtitle: Comments Access Options +:description: TinyMCE Comments plugin access options. +:keywords: comments, commenting, tinycomments, access options +:pluginname: Comments +:plugincode: comments +:pluginminimumplan: enterprise + +[[access-options]] +== Access Options + +The following configuration option affects the behavior of the {pluginname} plugin. + +include::partial$configuration/comments-tinycomments_access.adoc[leveloffset=+1] diff --git a/modules/ROOT/pages/comments-callback-mode.adoc b/modules/ROOT/pages/comments-callback-mode.adoc index 0b6e342277..f6aca219a1 100644 --- a/modules/ROOT/pages/comments-callback-mode.adoc +++ b/modules/ROOT/pages/comments-callback-mode.adoc @@ -1,4 +1,4 @@ -= Configuring the Comments plugin in callback mode += Configuring the {pluginname} plugin in callback mode :navtitle: Callback mode :description: Information on configuring the Comments plugin in callback mode :keywords: comments, commenting, tinycomments, callback @@ -6,32 +6,36 @@ :plugincode: comments :commentsMode: callback -*Callback mode* is the default mode for the Comments plugin. In the callback mode, callback functions are required to save user comments on a server. The Comments functions (create, reply, edit, delete comment, delete all conversations, resolve, and lookup) are configured differently depending upon the server-side storage configuration. +*Callback mode* is the default mode for the {pluginname} plugin. In the callback mode, callback functions are required to save user comments on a server. The {pluginname} functions (create, reply, edit, delete comment, delete all conversations, resolve, lookup, and fetch conversations) are configured differently depending upon the server-side storage configuration. -== Interactive example - -The following example uses a simulated server (provided by https://netflix.github.io/pollyjs/[Polly.js]) which has been hidden from the example javascript to keep the example code concise. The interactions between TinyMCE and Polly.js are visible in the browser console. - -liveDemo::comments-callback[] - -=== How the comments plugin works in callback mode +== How the {pluginname} plugin works in callback mode All options accept functions incorporating `+done+` and `+fail+` callbacks as parameters. The function return type is not important, but all functions must call exactly one of these two callbacks: `+fail+` or `+done+`. * The `+fail+` callback takes either a string or a JavaScript Error type. * The `+done+` callback takes an argument specific to each function. -Most (create, reply, and edit) functions require an `+id+` identifying the *current author*. +Most functions (create, reply, and edit) require an `+id+` identifying the *current author*. -Current author:: The Comments plugin does not know the name of the current user. Determining the current user and storing the comment related to that user, has to be configured by the developer. +[NOTE] +**Current author**: The {pluginname} plugin does not know the name of the current user. Determining the current user and storing the comment related to that user is required to be configured by the integrator. -After a user comments (triggering `+tinycomments_create+` for the first comment, or `+tinycomments_reply+` for subsequent comments), the Comments plugin requests the updated conversation using `+tinycomments_lookup+`, which should now contain the additional comment with the proper author. +During the initial editor load, the {pluginname} uses `+tinycomments_fetch+` callback to retrieve the existing conversations in the document. If not configured, the {pluginname} will fallback to `+tinycomments_lookup+`. + +When a user adds a comment or a reply, the {pluginname} plugin uses the `+tinycomments_lookup+` callback to retrieve the selected conversation. + +[[comments-callback-live-demo]] +== Interactive example + +The following example uses a simulated server (provided by link:https://netflix.github.io/pollyjs/[Polly.js]), which has been hidden from the example JavaScript to keep the example code concise. The interactions between {productname} and Polly.js are visible in the browser console. + +liveDemo::comments-callback[] == Options === Required options -When using callback mode, the Comments plugin requires callback functions for the following options: +When using callback mode, the {pluginname} plugin requires callback functions for the following options: * xref:tinycomments_create[`+tinycomments_create+`] * xref:tinycomments_reply[`+tinycomments_reply+`] @@ -41,16 +45,12 @@ When using callback mode, the Comments plugin requires callback functions for th * xref:tinycomments_delete_all[`+tinycomments_delete_all+`] * xref:tinycomments_lookup[`+tinycomments_lookup+`] -The xref:tinycomments_resolve[`+tinycomments_resolve+`] option is _optional_. - include::partial$configuration/tinycomments_create.adoc[leveloffset=+1] include::partial$configuration/tinycomments_reply.adoc[leveloffset=+1] include::partial$configuration/tinycomments_edit_comment.adoc[leveloffset=+1] -include::partial$configuration/tinycomments_resolve.adoc[leveloffset=+1] - include::partial$configuration/tinycomments_delete_comment.adoc[leveloffset=+1] include::partial$configuration/tinycomments_delete.adoc[leveloffset=+1] @@ -59,6 +59,15 @@ include::partial$configuration/tinycomments_delete_all.adoc[leveloffset=+1] include::partial$configuration/tinycomments_lookup.adoc[leveloffset=+1] +== Optional options + +* xref:tinycomments_resolve[`+tinycomments_resolve+`] +* xref:tinycomments_fetch[`+tinycomments_fetch+`] + +include::partial$configuration/tinycomments_resolve.adoc[leveloffset=+1] + +include::partial$configuration/tinycomments_fetch.adoc[leveloffset=+1] + include::partial$plugins/comments-open-sidebar.adoc[] include::partial$plugins/comments-highlighting-css.adoc[] diff --git a/modules/ROOT/pages/comments-commands-events-apis.adoc b/modules/ROOT/pages/comments-commands-events-apis.adoc index 89b8e3b3f7..1a03744b2f 100644 --- a/modules/ROOT/pages/comments-commands-events-apis.adoc +++ b/modules/ROOT/pages/comments-commands-events-apis.adoc @@ -1,4 +1,4 @@ -= Commands, Events and APIs for the comments plugin += Commands, Events and APIs for the {pluginname} plugin :navtitle: Commands, Events and APIs :description: Information on the commands, events and APIs provided with the comments plugin. :keywords: comments, commenting, tinycomments @@ -7,7 +7,7 @@ == Commands -The Comments plugin provides the following {productname} commands. +The {pluginname} plugin provides the following {productname} commands. include::partial$commands/comments-cmds.adoc[] @@ -37,36 +37,7 @@ tinymce.init({ }); ---- -== APIs - -The {pluginname} plugin provides the xref:comments-commands-events-apis#getEventLog[`+getEventLog()+`] API, as well as an annotator named xref:comments-commands-events-apis#tinycomments-annotator[`+'tinycomments'+`] created using the xref:annotations.adoc[`+editor.annotator+` API]. - -[[getEventLog]] -=== getEventLog() - -include::partial$misc/admon-requires-6.1v.adoc[] - -Returns a log with information and timestamps of all changes to comments, including when: - -* A new comment is added (and who added it). -* A comment is edited (and who edited it). -* A reply to a comment is added (and who added the reply). -* A comment is resolved (and who resolved the comment). -* A comment is deleted (and who deleted the comment). - -The event log can be retrieved either in full or with the `after` option, which restricts the returned list to Comment events after a time-stamp date in the link:https://en.wikipedia.org/wiki/ISO_8601[ISO-8601] format, both shown in the following: - -==== Example: using `+getEventLog()+` - -[source,js] ----- -const comments = tinymce.activeEditor.plugins.tinycomments; - -console.log(comments.getEventLog()); -console.log(comments.getEventLog( - { after: '2022-02-22T12:34:56Z' } // ISO-8601 standard: YYYY-MM-DDThh:mm:ssZ -)); ----- +include::partial$plugin-apis/comments-apis.adoc[] [[tinycomments-annotator]] === The `+'tinycomments'+` annotator @@ -81,7 +52,7 @@ The `+'tinycomments'+` annotator, like all editor APIs, can only be accessed aft This example makes use of the `+annotationChanged+` method in the `+editor.annotator+` API to create a xref:creating-custom-notifications.adoc[custom notification]. -This notification displays for five seconds every time any content with a `+'tinycomments'+` annotation is selected. +The below notification example displays for five seconds every time any content with a `+'tinycomments'+` annotation is selected. [source,js] ---- diff --git a/modules/ROOT/pages/comments-embedded-mode.adoc b/modules/ROOT/pages/comments-embedded-mode.adoc index af3fb39179..f0f8c1fa6f 100644 --- a/modules/ROOT/pages/comments-embedded-mode.adoc +++ b/modules/ROOT/pages/comments-embedded-mode.adoc @@ -1,27 +1,29 @@ -= Configuring the Comments plugin in embedded mode += Configuring the {pluginname} plugin in embedded mode :navtitle: Embedded mode :description: Information on configuring the Comments plugin in embedded mode :keywords: comments, commenting, tinycomments, embedded, embedded mode :pluginname: Comments :plugincode: comments -== Add the Comments plugin in embedded mode +== Add the {pluginname} plugin in embedded mode -To add the Comments plugin in embedded mode to the {productname}, configure the following options: +To add the {pluginname} plugin in embedded mode to the {productname}, configure the following options: [source,js] ---- tinymce.init({ selector: 'textarea', // change this value according to your html plugins: 'tinycomments', + toolbar: 'addcomment showcomments', tinycomments_author: 'author', tinycomments_author_name: 'Name of the commenter', tinycomments_mode: 'embedded' }); ---- -This is the minimum recommended setup for the Comments plugin in embedded mode. If the `+tinycomments_author+` and `+tinycomments_author_name+` options are not configured, all users will be assigned the name "_ANON_". +This is the minimum recommended setup for the {pluginname} plugin in embedded mode. If the `+tinycomments_author+` and `+tinycomments_author_name+` options are not configured, all users will be assigned the name "_ANON_". +[[comments-embedded-live-demo]] == Interactive example liveDemo::comments-embedded[] @@ -44,4 +46,4 @@ include::partial$configuration/tinycomments_can_edit_comment.adoc[leveloffset=+1 include::partial$plugins/comments-open-sidebar.adoc[] -include::partial$plugins/comments-highlighting-css.adoc[] +include::partial$plugins/comments-highlighting-css.adoc[] \ No newline at end of file diff --git a/modules/ROOT/pages/comments-toolbars-menus.adoc b/modules/ROOT/pages/comments-toolbars-menus.adoc index ce82e328a8..4d3e9d803b 100644 --- a/modules/ROOT/pages/comments-toolbars-menus.adoc +++ b/modules/ROOT/pages/comments-toolbars-menus.adoc @@ -1,4 +1,4 @@ -= Toolbar buttons and menu items for the Comments plugin += Toolbar buttons and menu items for the {pluginname} plugin :navtitle: Toolbar buttons and menu items :description: Details of the toolbar buttons and menu items provided for the Comments plugin. :keywords: comments, commenting, tinycomments diff --git a/modules/ROOT/pages/comments-using-comments.adoc b/modules/ROOT/pages/comments-using-comments.adoc index 41e322084e..4fe65b2582 100644 --- a/modules/ROOT/pages/comments-using-comments.adoc +++ b/modules/ROOT/pages/comments-using-comments.adoc @@ -1,34 +1,68 @@ -= Using TinyMCE Comments += Using {productname} {pluginname} :navtitle: Using Comments -:description: How to add, edit, resolve, and remove comments in TinyMCE +:description: How to add, edit, resolve, and remove comments in {productname} :keywords: comments, commenting, tinycomments :pluginname: Comments :plugincode: comments -I'm trying to: +== Overview -* xref:add-a-comment[Add a comment]. -* xref:edit-a-comment[Edit a comment]. -* xref:delete-a-comment[Delete a comment]. -* xref:delete-a-comment-thread-conversation[Delete a comment thread (conversation)]. -* xref:resolve-a-comment-thread-conversation[Resolve a comment thread (conversation)]. -* xref:show-or-view-a-comment[Show or view a comment]. -* xref:delete-all-comment-threads[Delete all comment threads]. +This guide provides visual instructions for using the comments plugin, including how to: + +* xref:add-a-comment[add new comments] to selected content +* xref:replying-to-comments[replying to comments] +* xref:edit-a-comment[edit existing comments] +* xref:delete-a-comment[delete individual comments] +* xref:delete-a-comment-thread-conversation[delete entire conversations] +* xref:resolve-a-comment-thread-conversation[resolving conversations] +* xref:show-or-view-a-comment[viewing comments] using the sidebar +* xref:delete-all-comment-threads[deleting all conversations] in a document + +[TIP] +The editor must contain content before a comment can be added. [[add-a-comment]] == Add a comment . Select the content from the desired location in the editor body. -. From the navigation menu, choose *Insert*-> *Add Comment* or click on the *Add comment* image:icons/comment-add.svg[Add comment] toolbar button to add the comment. -. The Comment box appears in the sidebar of the editor instance. -. Type a comment in the comment box, the "_Add comment…_" placeholder text will disappear. -. Press *Clear* to discard or *Comment* to store the input comment. +.. From the menubar, toggle *Insert* -> *Add comment*, or +.. click on the *Add comment* image:icons/comment-add.svg[Add comment] toolbar button, or +.. press `Ctrl+Alt+M` (Windows/Linux) or `Cmd+Option+M` `+⌥ + ⌘ + M+` (Mac) to add a comment. +. The {pluginname} sidebar will appear on the right side of the editor instance. +. The `+ + + +---- + +include::partial$auth/document-converters/nodejs/configuration-steps.adoc[] \ No newline at end of file diff --git a/modules/ROOT/pages/export-to-pdf-with-jwt-authentication-php.adoc b/modules/ROOT/pages/export-to-pdf-with-jwt-authentication-php.adoc new file mode 100644 index 0000000000..9d33d8b096 --- /dev/null +++ b/modules/ROOT/pages/export-to-pdf-with-jwt-authentication-php.adoc @@ -0,0 +1,65 @@ += {pluginname} with JWT authentication (PHP) Guide +:navtitle: JWT Authentication setup for Export to PDF +:description: Guide on how to setup JWT Authentication for exporting PDF files with {productname} +:keywords: jwt, authentication, exportpdf, pdf, php +:pluginname: Export to PDF +:plugincode: exportpdf + +include::partial$auth/document-converters/php/intro-and-prerequisites.adoc[] + +include::partial$auth/document-converters/php/initial-project-setup.adoc[] + +== Setup + +=== Generate a Public/Private Key Pair + +include::partial$auth/document-converters/jwt-setup-document-converters.adoc[leveloffset=+2] + +include::partial$auth/document-converters/php/server-setup-php.adoc[] + +=== Web Page Setup (index.html) + +Inside the `public` folder where you created the `index.html` file add the HTML setup code. + +[source,html] +---- + + + + TinyMCE with PDF Export + + + + +

    TinyMCE Export to PDF Demo

    + + + +---- + +include::partial$auth/document-converters/php/configuration-steps.adoc[] diff --git a/modules/ROOT/pages/export-to-word-standalone-service.adoc b/modules/ROOT/pages/export-to-word-standalone-service.adoc new file mode 100644 index 0000000000..24d50e771c --- /dev/null +++ b/modules/ROOT/pages/export-to-word-standalone-service.adoc @@ -0,0 +1,5 @@ += Export to Word Standalone Service +:navtitle: Export to Word Standalone Service +:description: The Export to Word service feature, provides the ability to generate a .docx Word files directly without the need for an editor. +:description_short: Generate a Word file directly from standalone application. +:keywords: service, exportword, export to Word \ No newline at end of file diff --git a/modules/ROOT/pages/export-to-word-with-jwt-authentication-nodejs.adoc b/modules/ROOT/pages/export-to-word-with-jwt-authentication-nodejs.adoc new file mode 100644 index 0000000000..d30583177b --- /dev/null +++ b/modules/ROOT/pages/export-to-word-with-jwt-authentication-nodejs.adoc @@ -0,0 +1,65 @@ += {pluginname} with JWT authentication (Node.js) Guide +:plugincode: exportword +:pluginname: Export to Word +:navtitle: JWT Authentication setup for {pluginname} +:description: Guide on how to setup JWT Authentication for exporting docx (Microsoft Word) files with {pluginname} +:keywords: jwt, authentication, exportword, node.js + + +include::partial$auth/document-converters/nodejs/intro-and-prerequisites.adoc[] + +include::partial$auth/document-converters/nodejs/initial-project-setup.adoc[] + +== Setup + +=== Generate a Public/Private Key Pair + +include::partial$auth/document-converters/jwt-setup-document-converters.adoc[leveloffset=+2] + +include::partial$auth/document-converters/nodejs/server-setup-jwt.adoc[] + +=== Web Page (public/index.html) + +Inside the `public` folder where you created the `index.html` file add the HTML setup code. + +[source,html] +---- + + + + TinyMCE with Export to Word + + + + +

    TinyMCE Export to Word Demo

    + + + +---- + +include::partial$auth/document-converters/nodejs/configuration-steps.adoc[] \ No newline at end of file diff --git a/modules/ROOT/pages/export-to-word-with-jwt-authentication-php.adoc b/modules/ROOT/pages/export-to-word-with-jwt-authentication-php.adoc new file mode 100644 index 0000000000..3febecce94 --- /dev/null +++ b/modules/ROOT/pages/export-to-word-with-jwt-authentication-php.adoc @@ -0,0 +1,65 @@ += {pluginname} with JWT authentication (PHP) Guide +:navtitle: JWT Authentication setup for Export to Word +:description: Guide on how to setup JWT Authentication for exporting Word files with {productname} +:keywords: jwt, authentication, exportword, word, php +:pluginname: Export to Word +:plugincode: exportword + +include::partial$auth/document-converters/php/intro-and-prerequisites.adoc[] + +include::partial$auth/document-converters/php/initial-project-setup.adoc[] + +== Setup + +=== Generate a Public/Private Key Pair + +include::partial$auth/document-converters/jwt-setup-document-converters.adoc[leveloffset=+2] + +include::partial$auth/document-converters/php/server-setup-php.adoc[] + +=== Web Page Setup (index.html) + +Inside the `public` folder where you created the `index.html` file add the HTML setup code. + +[source,html] +---- + + + + TinyMCE with Word Export + + + + +

    TinyMCE Export to Word Demo

    + + + +---- + +include::partial$auth/document-converters/php/configuration-steps.adoc[] diff --git a/modules/ROOT/pages/exportpdf.adoc b/modules/ROOT/pages/exportpdf.adoc index c01dad352a..1fe441c19c 100644 --- a/modules/ROOT/pages/exportpdf.adoc +++ b/modules/ROOT/pages/exportpdf.adoc @@ -1,10 +1,10 @@ -= Export to PDF plugin -:navtitle: Export to PDF -:description: The Export to PDF feature provides the ability to generate a PDF file directly from the editor. -:description_short: Generate a PDF file directly from the editor. -:keywords: plugin, exportpdf, export to pdf -:pluginname: Export to PDF += {pluginname} plugin :plugincode: exportpdf +:pluginname: Export to PDF +:navtitle: {pluginname} +:description: The {pluginname} feature provides the ability to generate a PDF file directly from the editor. +:description_short: Generate a PDF file directly from the editor. +:keywords: plugin, {plugincode}, {pluginname} :plugincategory: premium @@ -12,17 +12,13 @@ include::partial$misc/admon-export-pdf-paid-addon-pricing.adoc[] include::partial$misc/admon-requires-7.0v.adoc[] -The {pluginname} functionality gathers the HTML produced using the `editor.getcontent()` method and the default editor content styles, along with the styles specified in the configuration options for the plugin. This data is transmitted to the {productname} Cloud Services HTML to PDF converter service. The service processes this information to create a PDF file, which is then sent back to the user's browser for saving to their local disk. +The {pluginname} feature collects the HTML generated with the `tinymce.editor.getContent()` method and combines it with the default editor content styles along with the styles provided in the plugin configuration. The combined content and styles are then processed by the included server-side converter service, which can be either self-hosted or cloud-based. Following this processing, a PDF file is generated, which is subsequently returned to the user's browser, enabling them to save it onto their disk or drive. == Interactive example -[NOTE] -.{pluginname} demo -==== -Demos containing the {pluginname} plugin are currently only available on our main website. Check out https://www.tiny.cloud/tinymce/features/export-pdf[the {pluginname} demo], or the https://www.tiny.cloud/[demo on our home page], to try it out today. -==== +liveDemo::exportpdf[] -== Basic setup +== Basic setup using the {companyname} Cloud service To add the {pluginname} plugin to the editor, add `{plugincode}` to the `plugins` option in the editor configuration. @@ -34,15 +30,47 @@ tinymce.init({ selector: 'textarea', plugins: 'exportpdf', toolbar: 'exportpdf', - exportpdf_service_url: '' }); ---- +[IMPORTANT] +When using the {pluginname} plugin with the {companyname} Cloud service, JWT authentication is required to use the service. For more information on how to set up JWT authentication with {pluginname}, see examples: + +* xref:export-to-pdf-with-jwt-authentication-nodejs.adoc[{pluginname} with JWT authentication (Node.js)] +* xref:export-to-pdf-with-jwt-authentication-php.adoc[{pluginname} with JWT authentication (PHP)] + +== Basic setup using the self-hosted service + +To use the self-hosted version of the {pluginname} plugin, you need to set the `exportpdf_service_url` option to the URL of the service. + +For example: + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'exportpdf', + toolbar: 'exportpdf', + exportpdf_service_url: 'http://localhost:8080/' // Update with the URL of the service you are using such as 'http://myserver.com/' +}); +---- + +[IMPORTANT] +==== +The `exportpdf_service_url` option automatically appends `/v1/convert` to the URL provided, so only the base URL is required. For example, if the service is hosted at `http://localhost:8080/v1/convert`, the `exportpdf_service_url` option should be set to `http://localhost:8080/`. When using in production, ensure that `exportpdf_service_url` is updated to the production URL such as `https://myserver.com/`. +==== + == Options The following configuration options affect the behavior of the {pluginname} plugin. -include::partial$configuration/{plugincode}.adoc[leveloffset=+1] +include::partial$configuration/exportpdf_service_url.adoc[leveloffset=+1] + +include::partial$configuration/exportpdf_token_provider.adoc[leveloffset=+1] + +include::partial$configuration/exportpdf_converter_options.adoc[leveloffset=+1] + +include::partial$configuration/exportpdf_converter_style.adoc[leveloffset=+1] include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] @@ -56,4 +84,4 @@ include::partial$commands/{plugincode}-cmds.adoc[] == API Reference -> Explore the comprehensive API documentation for the {pluginname} Premium plugin at https://exportpdf.converter.tiny.cloud/docs[Export to PDF.^] \ No newline at end of file +> Explore the comprehensive API documentation for the {pluginname} Premium plugin at https://exportpdf.api.tiny.cloud/docs[{pluginname} API Reference Documentation.^] diff --git a/modules/ROOT/pages/exportword.adoc b/modules/ROOT/pages/exportword.adoc index d8de057d31..f633967941 100644 --- a/modules/ROOT/pages/exportword.adoc +++ b/modules/ROOT/pages/exportword.adoc @@ -1,25 +1,21 @@ -= Export to Word -:navtitle: exportword -:description: The export to Word feature lets you generate a .docx file directly from the editor. -:description_short: Generate a .docx file directly from the editor. -:keywords: plugin, exportword. -:pluginname: Export to Word += {pluginname} plugin :plugincode: exportword +:pluginname: Export to Word +:navtitle: {pluginname} +:description: The {pluginname} feature lets you generate a .docx (Microsoft Word document) file directly from the editor. +:description_short: Generate a .docx file directly from the editor. +:keywords: plugin, {plugincode}, {pluginname} :plugincategory: premium include::partial$misc/admon-export-word-paid-addon-pricing.adoc[] include::partial$misc/admon-requires-7.0v.adoc[] -The export to Microsoft Word feature collects the HTML generated with the `tinymce.editor.getContent()` method and combines it with the default editor content styles along with the styles provided in the configuration. The combined content and styles are then transmitted to the {productname} Cloud Services HTML to DOCX converter service. Following this, the service generates a Word file, which is subsequently returned to the user’s browser, enabling them to save it in the Word format onto their disk. +The export to Microsoft Word feature collects the HTML generated with the `tinymce.editor.getContent()` method and combines it with the default editor content styles along with the styles provided in the plugin configuration. The combined content and styles are then processed by the included server-side converter service, which can be either self-hosted or cloud-based. Following this processing, a Word file is generated, which is subsequently returned to the user's browser, enabling them to save it in the Word format onto their disk or drive. == Interactive example -[NOTE] -.{pluginname} demo -==== -Demos containing the {pluginname} plugin are currently only available on our main website. Check out https://www.tiny.cloud/tinymce/features/export-word[the {pluginname} demo], or the https://www.tiny.cloud/[demo on our home page], to try it out today. -==== +liveDemo::exportword[] [NOTE] .{pluginname} known issues @@ -28,7 +24,7 @@ Demos containing the {pluginname} plugin are currently only available on our mai * xref:introduction-to-mediaembed.adoc[Enhanced Media Embed] will not be included in the exported document, resulting in a console.error _"The Export to Word plugin requires the `exportword_service_url` to be configured"_. ==== -== Basic setup +== Basic setup using the {companyname} Cloud service To add the {pluginname} plugin to the editor, add `{plugincode}` to the `plugins` option in the editor configuration. @@ -40,22 +36,53 @@ tinymce.init({ selector: 'textarea', plugins: 'exportword', toolbar: 'exportword', - exportword_service_url: '' }); ---- +[IMPORTANT] +When using the {pluginname} plugin with the {companyname} Cloud service, JWT authentication is required to use the service. For more information on how to set up JWT authentication with {pluginname}, see examples: + +* xref:export-to-word-with-jwt-authentication-nodejs.adoc[{pluginname} with JWT authentication (Node.js)] +* xref:export-to-word-with-jwt-authentication-php.adoc[{pluginname} with JWT authentication (PHP)] + +== Basic setup using the self-hosted service + +To use the self-hosted version of the {pluginname} plugin, you need to set the `exportword_service_url` option to the URL of the service. + +For example: +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'exportword', + toolbar: 'exportword', + exportword_service_url: 'http://localhost:8080/' // Update with the URL of the service you are using such as 'http://myserver.com/' +}); +---- + +[IMPORTANT] +==== +The `exportword_service_url` option automatically appends `/v2/convert/html-docx` to the URL provided, so only the base URL is required. For example, if the service is hosted at `http://localhost:8080/v2/convert/html-docx`, the `exportword_service_url` option should be set to `http://localhost:8080/`. When using in production, ensure that `exportword_service_url` is updated to the production URL such as `https://myserver.com/`. +==== + == Options The following configuration options affect the behavior of the {pluginname} plugin. -include::partial$configuration/{plugincode}.adoc[leveloffset=+1] +include::partial$configuration/exportword_service_url.adoc[leveloffset=+1] + +include::partial$configuration/exportword_token_provider.adoc[leveloffset=+1] + +include::partial$configuration/exportword_converter_options.adoc[leveloffset=+1] + +include::partial$configuration/exportword_converter_style.adoc[leveloffset=+1] == Commands The {pluginname} plugin provides the following {productname} commands. -include::partial$commands/{plugincode}-cmds.adoc[][leveloffset=+1] +include::partial$commands/exportword-cmds.adoc[][leveloffset=+1] == API Reference -> Explore the comprehensive API documentation for the {pluginname} Premium plugin at https://exportdocx.converter.tiny.cloud/docs#section/Export-to-Word[Export to Word.^] \ No newline at end of file +> Explore the comprehensive API documentation for the {pluginname} Premium plugin at link:https://exportdocx.api.tiny.cloud/v2/convert/docs#section/Export-to-Word[{pluginname} API Reference Documentation.^] diff --git a/modules/ROOT/pages/filter-content.adoc b/modules/ROOT/pages/filter-content.adoc index 80c716c227..00704f99ac 100644 --- a/modules/ROOT/pages/filter-content.adoc +++ b/modules/ROOT/pages/filter-content.adoc @@ -16,7 +16,7 @@ Check out the xref:user-formatting-options.adoc#style_formats[custom formats exa === Style merging -Similar elements and styles are merged by default to reduce the output HTML size. For example, instead of assigning one `+span+` element for font size and another `+span+` element for font face, {productname} merges the two styles into a sing `+span+` element. +Similar elements and styles are merged by default to reduce the output HTML size. For example, instead of assigning one `+span+` element for font size and another `+span+` element for font face, {productname} merges the two styles into a single `+span+` element. === Built-in formats diff --git a/modules/ROOT/pages/full-featured-premium-demo.adoc b/modules/ROOT/pages/full-featured-premium-demo.adoc index 97f77ccbd6..2bf15a25c4 100644 --- a/modules/ROOT/pages/full-featured-premium-demo.adoc +++ b/modules/ROOT/pages/full-featured-premium-demo.adoc @@ -17,25 +17,12 @@ The following plugins are excluded from this example: |=== |Excluded plugins |Notes - -|xref:ai.adoc[AI Assistant] -|Logistical concerns regarding exposing API keys preclude adding this. - |xref:autoresize.adoc[Autoresize] |Resizes the editor to fit the content. |xref:code.adoc[Code] |xref:advcode.adoc[*Enhanced Code Editor*] included instead. -|xref:exportpdf.adoc[Export to PDF] -|Logistical concerns regarding exposing internal service URLs preclude adding this. - -|xref:exportword.adoc[Export to Word] -|Logistical concerns regarding exposing internal service URLs preclude adding this. - -|xref:importword.adoc[Import from Word] -|Logistical concerns regarding exposing internal service URLs preclude adding this. - |xref:moxiemanager.adoc[MoxieManager] |xref:tinydrive-introduction.adoc[*{cloudfilemanager}*] included instead. diff --git a/modules/ROOT/pages/how-to-guides.adoc b/modules/ROOT/pages/how-to-guides.adoc index b499ae7c70..33498730e1 100644 --- a/modules/ROOT/pages/how-to-guides.adoc +++ b/modules/ROOT/pages/how-to-guides.adoc @@ -4,118 +4,111 @@ :type: folder // 2 Columns, both asciidoc -[cols=2*a] +[cols="1,1"] |=== -| +a| [.lead] xref:accessibility.adoc[Accessibility] Learn how TinyMCE works with screen readers and how screen readers work with TinyMCE. -| +a| [.lead] xref:security.adoc[Security] Security information for TinyMCE. -| +a| [.lead] xref:creating-a-skin.adoc[Create a skin] Introducing skin creation. -| +a| [.lead] xref:creating-an-icon-pack.adoc[Create an icon pack] Introducing icon pack creation. -| +a| [.lead] xref:creating-a-plugin.adoc[Create a plugin] Introducing plugin creation, with an example. -| +a| [.lead] xref:annotations.adoc[Annotations] TinyMCE Annotations provides the ability to describe particular features or add general information to a... -| -[.lead] -xref:yeoman-generator.adoc[Yeoman generator] - -How to use the Yeoman generator to bootstrap a new TinyMCE plugin - -| +a| [.lead] xref:creating-custom-notifications.adoc[Create custom notifications] Learn how to make custom notifications. -| +a| [.lead] xref:php-upload-handler.adoc[PHP image upload handler] A server-side upload handler PHP script. -| +a| [.lead] xref:available-menu-items.adoc[Available Menu Items] Complete list of menu items available for the menu bar and context menus. -| +a| [.lead] xref:available-toolbar-buttons.adoc[Available Toolbar Buttons] Complete list of toolbar buttons available for the toolbar and quick toolbars. -| +a| [.lead] xref:editor-command-identifiers.adoc[Available Commands] Complete list of editor commands. -| +a| [.lead] xref:editor-icon-identifiers.adoc[Available Icons] Complete list of icon identifiers. -| +a| [.lead] xref:editor-context-menu-identifiers.adoc[Available Context Menu Items] Complete list of available context menu sections. -| +a| [.lead] xref:events.adoc[Available Events] List of common editor events -| +a| [.lead] xref:keyboard-shortcuts.adoc[Keyboard shortcuts] Complete list of keyboard shortcuts. -| +a| [.lead] xref:introduction-to-bundling-tinymce.adoc[Bundling TinyMCE] Bundling TinyMCE with Webpack, rollup.js, or Browserify. -| +a| [.lead] xref:generate-rsa-key-pairs.adoc[Generate public key pairs] Instructions on how to generate private/public key pairs for the Tiny Cloud // Empty cell to even out rows -// | - +|a |=== \ No newline at end of file diff --git a/modules/ROOT/pages/html-to-docx-converter-api.adoc b/modules/ROOT/pages/html-to-docx-converter-api.adoc new file mode 100644 index 0000000000..89c20a3c70 --- /dev/null +++ b/modules/ROOT/pages/html-to-docx-converter-api.adoc @@ -0,0 +1,44 @@ += HTML to Docx Converter API +:navtitle: Export to Word Standalone Service +:description: The Export to Microsoft Word feature collects the HTML generated with the tinymce.editor.getContent() method and combines it with the default editor content styles along with the styles provided in the configuration. +:description_short: Generate a .docx file directly from any application. +:keywords: service, exportword, export to docx, export to word, html to docx converter api +:pluginname: Export to Word +:servicename: HTML to Docx Converter API + +[NOTE] +This is a premium feature. link:https://www.tiny.cloud/contact/[Contact us] to purchase a license or to learn more about our tailored offers. Note that any documents generated without authentication will be watermarked. + +== Overview + +The {servicename} allows developers to convert HTML content into DOCX files seamlessly. It is designed to integrate effortlessly into your applications, providing high-quality document conversions with ease. + +== Key Features + +- **HTML to DOCX Conversion**: Transform HTML content into DOCX files with precision, maintaining the structure and styling. +- **Customizable Outputs**: Tailor the DOCX output to match your requirements, including custom headers, footers, and styles. +- **High Performance**: Engineered for efficiency, ensuring fast and reliable document conversions. +- **Ease of Integration**: Simple RESTful API interface that can be integrated into any application or workflow. + +[[options]] +== Flexible Configuration Options + +You can customize the DOCX output by specifying various options in your request: + +- **Headers and Footers**: Add custom headers and footers to your DOCX documents. +- **Styles**: Define custom styles for different HTML elements to ensure your documents look exactly as desired. +- **Page Format**: Select from a wide range of page formats, including Letter, Legal, Tabloid, and A4, ensuring your documents look perfect every time. + +== Ideal for Various Use Cases + +Examples on how you can use the API to convert an HTML document with custom styles and a header and footer. + +* **Legal Document Automation**: Automate the generation of legal documents by converting pre-defined HTML templates into standardized DOCX files, complete with custom headers, footers, and styling. +* **Dynamic Report Generation**: Generate dynamic reports from HTML data, allowing for consistent formatting and styling across all generated documents. +* **Educational Material Distribution**: Convert HTML-based educational content into DOCX files for easy distribution and offline access by students. +* **Newsletter Archiving**: Archive HTML newsletters as DOCX files, preserving the layout and design for future reference. + + +== HTML to Docx Converter API Reference + +> Explore the comprehensive API documentation at link:https://exportdocx.api.tiny.cloud/docs#section/Export-to-Word[HTML to Docx Converter API Reference documentation.^] \ No newline at end of file diff --git a/modules/ROOT/pages/html-to-pdf-converter-api.adoc b/modules/ROOT/pages/html-to-pdf-converter-api.adoc new file mode 100644 index 0000000000..3beeff4ac2 --- /dev/null +++ b/modules/ROOT/pages/html-to-pdf-converter-api.adoc @@ -0,0 +1,43 @@ += HTML to PDF Converter API +:navtitle: Export to PDF Standalone Service +:description: The HTML to PDF Converter API service feature, provides the ability to generate a PDF files directly without the need for an editor. +:description_short: Generate a .pdf file directly from any application. +:keywords: service, exportpdf, export to pdf, HTML to PDF Converter API +:pluginname: Export to PDF +:servicename: HTML to PDF Converter API + +[NOTE] +This is a premium feature. link:https://www.tiny.cloud/contact/[Contact us] to purchase a license or to learn more about our tailored offers. Note that any documents generated without authentication will be watermarked. + +== Overview + +The {servicename} is a powerful tool that seamlessly integrates advanced document conversion capabilities into developers workflows. This API allows for the efficient conversion of HTML content into PDF documents, catering to a wide range of use cases. + +=== Key Features + +* **Versatile Document Conversion**: Convert HTML content into high-quality PDF documents, providing flexibility for various document needs. +* **Preprocessing Capabilities**: Pre-process content before conversion, such as resolving merge tags, ensuring fully customized and ready-to-use PDF documents. +* **Customizable Output**: Tailor the appearance and structure of the converted PDFs with customizable output xref:html-to-pdf-converter-api.adoc#options[options], including page sizes, margins, and formatting. +* **Scalability**: Handle large volumes of PDF documents with consistent performance and reliability, supporting business growth and varying demands. +* **Ease of Integration**: Integrate the API into existing workflows easily with comprehensive documentation and straightforward API endpoints. +* **Security and Compliance**: Ensure secure document conversion processes that adhere to data protection standards and industry regulations, crucial for handling sensitive information. + +[[options]] +== Flexible Configuration Options + +Tailor your PDF documents to suit your needs: + +* **Custom CSS Styling:** Apply link:https://exportpdf.api.tiny.cloud/docs#section/General/CSS[custom CSS^] styles to your PDFs for brand consistency and enhanced presentation. +* **Header and Footer Options:** Add link:https://exportpdf.api.tiny.cloud/docs#section/PDF-options/Header-and-footer[headers, footers^], and other branding elements to your PDF documents for a professional touch. +* **Page Formatting:** Control page settings such as orientation, link:https://exportpdf.api.tiny.cloud/docs#section/PDF-options/Margins[margins^], and link:https://exportpdf.api.tiny.cloud/docs#section/PDF-options/Page-format[page size] to optimize readability. + +== Ideal for Various Use Cases + +* **Aggregating Content from Multiple Sources**: Combine content from various editors into a single cohesive PDF document, simplifying content management for organizations using multiple tools. +* **Centralized Document Management**: Store generated PDF documents centrally for better organization and accessibility, facilitating team collaboration and efficient document retrieval. +* **Preprocessing and Customization**: Pre-process content to resolve merge tags and customize PDF document formatting, ensuring that the final output meets specific requirements and is ready for immediate use. +* **Large-Scale Document Processing**: Utilize the API’s scalability to handle large volumes of PDF documents, maintaining consistent performance and reliability, essential for growing businesses. + +== PDF Converter API Reference + +> Explore the comprehensive API documentation at link:https://exportpdf.api.tiny.cloud/docs[PDF Converter API Reference documentation.^] \ No newline at end of file diff --git a/modules/ROOT/pages/import-from-word-standalone-service.adoc b/modules/ROOT/pages/import-from-word-standalone-service.adoc new file mode 100644 index 0000000000..13f01a683a --- /dev/null +++ b/modules/ROOT/pages/import-from-word-standalone-service.adoc @@ -0,0 +1,5 @@ += Import from Word Standalone Service +:navtitle: Import from Word Standalone Service +:description: The Import from Word service feature lets you import .docx (Word document) or .dotx (Word template) files into standalone application. +:description_short: Import a Word file directly into a standalone application while preserving formatting and rich media. +:keywords: service, importword, Import from Word \ No newline at end of file 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 new file mode 100644 index 0000000000..07d7fd8521 --- /dev/null +++ b/modules/ROOT/pages/import-from-word-with-jwt-authentication-nodejs.adoc @@ -0,0 +1,67 @@ += {pluginname} with JWT authentication (Node.js) Guide +:plugincode: importword +:pluginname: Import from Word +:navtitle: JWT Authentication setup for {pluginname} +:description: Guide on how to setup JWT Authentication for importing docx (Microsoft Word) files with {pluginname} +:keywords: jwt, authentication, importword, node.js + + +include::partial$auth/document-converters/nodejs/intro-and-prerequisites.adoc[] + +include::partial$auth/document-converters/nodejs/initial-project-setup.adoc[] + +== Setup + +=== Generate a Public/Private Key Pair + +include::partial$auth/document-converters/jwt-setup-document-converters.adoc[leveloffset=+2] + +include::partial$auth/document-converters/nodejs/server-setup-jwt.adoc[] + +=== Web Page (public/index.html) + +Inside the `public` folder where you created the `index.html` file add the HTML setup code. + +[source,html] +---- + + + + TinyMCE with Import from Word + + + + +

    TinyMCE Import from Word Demo

    + + + +---- + +include::partial$auth/document-converters/nodejs/configuration-steps.adoc[] \ No newline at end of file diff --git a/modules/ROOT/pages/import-from-word-with-jwt-authentication-php.adoc b/modules/ROOT/pages/import-from-word-with-jwt-authentication-php.adoc new file mode 100644 index 0000000000..375a5d536f --- /dev/null +++ b/modules/ROOT/pages/import-from-word-with-jwt-authentication-php.adoc @@ -0,0 +1,65 @@ += {pluginname} with JWT authentication (PHP) Guide +:navtitle: JWT Authentication setup for Import from Word +:description: Guide on how to setup JWT Authentication for importing Word files with {productname} +:keywords: jwt, authentication, importword, word, php +:pluginname: Import from Word +:plugincode: importword + +include::partial$auth/document-converters/php/intro-and-prerequisites.adoc[] + +include::partial$auth/document-converters/php/initial-project-setup.adoc[] + +== Setup + +=== Generate a Public/Private Key Pair + +include::partial$auth/document-converters/jwt-setup-document-converters.adoc[leveloffset=+2] + +include::partial$auth/document-converters/php/server-setup-php.adoc[] + +=== Web Page Setup (index.html) + +Inside the `public` folder where you created the `index.html` file add the HTML setup code. + +[source,html] +---- + + + + TinyMCE with Word Import + + + + +

    TinyMCE Import Word Demo

    + + + +---- + +include::partial$auth/document-converters/php/configuration-steps.adoc[] diff --git a/modules/ROOT/pages/importword.adoc b/modules/ROOT/pages/importword.adoc index 3c1f74bc95..72bdca3751 100644 --- a/modules/ROOT/pages/importword.adoc +++ b/modules/ROOT/pages/importword.adoc @@ -1,11 +1,11 @@ -= Import from Word plugin -:navtitle: Import from Word -:description: Provides a way to import .docx (Word documents) or .dotx (Word templates) files into the editor. -:description_short: Import .docx or .dotx files into the editor. -:keywords: plugin, importword, import from word -:pluginname: Import from Word += {pluginname} plugin :plugincode: importword +:pluginname: Import from Word +:navtitle: {pluginname} +:description: Provides a way to import .docx (Microsoft Word documents) or .dotx (Microsoft Word templates) files into the editor. +:description_short: Import .docx or .dotx files into the editor. +:keywords: plugin, {plugincode}, {pluginname} :plugincategory: premium include::partial$misc/admon-import-word-paid-addon-pricing.adoc[] @@ -17,13 +17,9 @@ The {pluginname} plugin lets you import `.docx` (Word document) or `.dotx` (Word == Interactive example -[NOTE] -.{pluginname} demo -==== -Demos containing the {pluginname} plugin are currently only available on our main website. Check out https://www.tiny.cloud/tinymce/features/import-from-word[the {pluginname} demo], or the https://www.tiny.cloud/[demo on our home page], to try it out today. -==== +liveDemo::importword[] -== Basic setup +== Basic setup using the {companyname} Cloud service To add the {pluginname} plugin to the editor, add `{plugincode}` to the `plugins` option in the editor configuration. @@ -33,17 +29,47 @@ For example: ---- tinymce.init({ selector: 'textarea', - plugins: 'code importword', - toolbar: 'importword code', - importword_service_url: '' + plugins: 'importword', + toolbar: 'importword', +}); +---- + +[IMPORTANT] +When using the {pluginname} plugin with the {companyname} Cloud service, JWT authentication is required to use the service. For more information on how to set up JWT authentication with {pluginname}, see examples: + +* xref:import-from-word-with-jwt-authentication-nodejs.adoc[{pluginname} with JWT authentication (Node.js)] +* xref:import-from-word-with-jwt-authentication-php.adoc[{pluginname} with JWT authentication (PHP)] + +== Basic setup using the self-hosted service + +To use the self-hosted version of the {pluginname} plugin, you need to set the `importword_service_url` option to the URL of the service. + +For example: + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'importword', + toolbar: 'importword', + importword_service_url: 'http://localhost:8080/' // Update with the URL of the service you are using such as 'http://myserver.com/' }); ---- +[IMPORTANT] +==== +The `importword_service_url` option automatically appends `/v2/convert/docx-html` to the URL provided, so only the base URL is required. For example, if the service is hosted at `http://localhost:8080/v2/convert/docx-html`, the `importword_service_url` option should be set to `http://localhost:8080/`. When using in production, ensure that the `importword_service_url` is updated to the production URL such as `https://myserver.com/`. +==== + == Options The following configuration options affect the behavior of the {pluginname} plugin. -include::partial$configuration/{plugincode}.adoc[leveloffset=+1] +include::partial$configuration/importword_service_url.adoc[leveloffset=+1] + +include::partial$configuration/importword_token_provider.adoc[leveloffset=+1] + +include::partial$configuration/importword_converter_options.adoc[leveloffset=+1] include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] @@ -53,8 +79,8 @@ include::partial$misc/plugin-menu-item-id-boilerplate.adoc[] The {pluginname} plugin provides the following {productname} commands. -include::partial$commands/{plugincode}-cmds.adoc[] +include::partial$commands/importword-cmds.adoc[] == API Reference -> Explore the comprehensive API documentation for the {pluginname} Premium plugin at https://importdocx.converter.tiny.cloud/docs#section/Import-from-Word[Import from Word.^] \ No newline at end of file +> Explore the comprehensive API documentation for the {pluginname} Premium plugin at link:https://importdocx.api.tiny.cloud/v2/convert/docs#section/Import-from-Word[{pluginname} API Reference Documentation.^] diff --git a/modules/ROOT/pages/individual-export-to-pdf-on-premises.adoc b/modules/ROOT/pages/individual-export-to-pdf-on-premises.adoc new file mode 100644 index 0000000000..40f8f4f3d1 --- /dev/null +++ b/modules/ROOT/pages/individual-export-to-pdf-on-premises.adoc @@ -0,0 +1,21 @@ += Deploy the {productname} {pluginname} service server-side component using Docker (individually licensed) +:navtitle: Export to PDF +:description: Setting up Export to PDF using Docker. +:keywords: server-side, docker, export-to-pdf, on-premises +:pluginname: Export to PDF + +include::partial$individually-licensed-components/export-to-pdf/export-to-pdf-overview.adoc[] + +include::partial$individually-licensed-components/export-to-pdf/export-to-pdf-requirements.adoc[] + +include::partial$individually-licensed-components/export-to-pdf/export-to-pdf-installation.adoc[] + +include::partial$individually-licensed-components/export-to-pdf/export-to-pdf-fonts.adoc[] + +include::partial$individually-licensed-components/export-to-pdf/export-to-pdf-autorization.adoc[] + +include::partial$individually-licensed-components/export-to-pdf/export-to-pdf-api-usage.adoc[] + +include::partial$individually-licensed-components/export-to-pdf/export-to-pdf-ssl-communication.adoc[] + +include::partial$individually-licensed-components/export-to-pdf/export-to-pdf-logs.adoc[] \ No newline at end of file diff --git a/modules/ROOT/pages/individual-import-from-word-and-export-to-word-on-premises.adoc b/modules/ROOT/pages/individual-import-from-word-and-export-to-word-on-premises.adoc new file mode 100644 index 0000000000..3cca7d5e1b --- /dev/null +++ b/modules/ROOT/pages/individual-import-from-word-and-export-to-word-on-premises.adoc @@ -0,0 +1,19 @@ += Deploy the {productname} {pluginname} service server-side component using Docker (individually licensed) +:navtitle: Import from Word and Export to Word +:description: Setting up Import from Word and Export to Word using Docker. +:keywords: server-side, docker, import-from-word, export-to-word, on-premises +:pluginname: Import from Word and Export to Word + +include::partial$individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-overview-on-premises.adoc[] + +include::partial$individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-requirements-on-premises.adoc[] + +include::partial$individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-installation-on-premises.adoc[] + +include::partial$individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-autorization-on-premises.adoc[] + +include::partial$individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-api-usage-on-premises.adoc[] + +include::partial$individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-ssl-communication-on-premises.adoc[] + +include::partial$individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-logs-on-premises.adoc[] \ No newline at end of file diff --git a/modules/ROOT/pages/introduction-to-tiny-comments.adoc b/modules/ROOT/pages/introduction-to-tiny-comments.adoc index 761ef56980..ec989581cd 100644 --- a/modules/ROOT/pages/introduction-to-tiny-comments.adoc +++ b/modules/ROOT/pages/introduction-to-tiny-comments.adoc @@ -1,6 +1,6 @@ -= Introduction to Tiny Comments += Introduction to {companyname} {pluginname} :navtitle: Introduction -:description: Tiny Comments provides the ability to add comments to the content and collaborate with other users for content editing. +:description: Tiny Comments enables users to add comments to content, fostering collaboration during content editing. :keywords: comments, commenting, tinycomments :pluginname: Comments :plugincode: comments @@ -8,52 +8,55 @@ == Contents -* For help using comments in TinyMCE, see: xref:comments-using-comments.adoc[Using comments]. -* For an overview of the TinyMCE Comments plugin, see: xref:overview[Overview]. -* For information on adding and configuring the comments plugin for TinyMCE, see: xref:getting-started-with-the-comments-plugin-selecting-a-mode[Getting started with the Comments plugin - Selecting a mode]. +* For guidance on using comments in {productname}, refer to: xref:comments-using-comments.adoc[Using comments]. +* For an overview of the {productname} {pluginname} plugin, refer to: xref:overview[Overview]. +* For instructions on configuring the {pluginname} plugin, refer to: xref:getting-started-with-the-comments-plugin-selecting-a-mode[Getting started with the {pluginname} plugin - Selecting a mode]. [[overview]] == Overview include::partial$misc/admon-premium-plugin.adoc[] -The Comments plugin provides the ability to start or join a conversation by adding comments to the content within the {productname} editor. +The {pluginname} plugin allows users to initiate and engage in conversations by adding comments directly within the {productname} editor. It also supports viewing all comments in a document for efficient collaboration. -=== Collaborate on your projects within your content +=== Interactive examples -The Comments plugin provides: +For interactive live demos for the {pluginname} plugin, showcasing both callback and embedded modes, see: -* A *user interface* to collaborate on content by creating and replying to comments. -* A way to control the delete and resolve operations on a comment or comment thread. +* xref:comments-callback-mode.adoc#comments-callback-live-demo[Callback mode] Demo +* xref:comments-embedded-mode.adoc#comments-embedded-live-demo[Embedded mode] Demo -=== Primary Comments functions +=== Collaborate seamlessly within your content -The Comments plugin allows the user to perform the following functions: +With the {pluginname} plugin, users can: -* Create a comment -* Edit a comment -* Reply to a comment -* Lookup a comment -* Resolve a comment thread -* Delete a comment or comment thread +* Collaborate on content through an intuitive interface for creating and replying to comments. +* Control the ability to delete or resolve individual comments or entire comment threads. -include::partial$misc/annotation-supported-content.adoc[leveloffset=+2] - -=== Interactive example +=== Key features of the {pluginname} plugin -The following example shows how to configure the Comments plugin in *embedded* mode. For information on configuring the Comments plugin, see: xref:getting-started-with-the-comments-plugin-selecting-a-mode[Comments plugin Modes]. +The {pluginname} plugin enables users to: -liveDemo::comments-embedded[] +* Create comments +* Edit comments +* Reply to comments +* Search for comments +* Resolve comment threads +* Delete comments or entire threads -// include::partial$misc/purchase-premium-plugins.adoc[] +include::partial$misc/annotation-supported-content.adoc[leveloffset=+2] [[getting-started-with-the-comments-plugin-selecting-a-mode]] -== Getting started with the Comments plugin - Selecting a mode +== Getting started with the {pluginname} plugin - Selecting a mode + +The {pluginname} plugin offers two modes: + +=== Callback Mode -The Comments plugin is available in two _modes_: *Callback mode* and *Embedded mode*. +This default mode stores comments externally, such as in a database, and requires callback functions to manage comment data. For setup details, refer to: xref:comments-callback-mode.adoc[Configuring the {pluginname} plugin in Callback mode]. -Callback Mode:: This is the default mode for the Comments plugin. This mode is used to store the comments outside the content on a server, such as a database. This mode requires a number of callback functions to handle comment data. For instructions on configuring the Comments plugin in callback mode, see: xref:comments-callback-mode.adoc[Configuring the Comments plugin in callback mode] +=== Embedded Mode -Embedded Mode:: This mode stores the comments within the content. No callbacks need to be configured for this mode. For instructions on configuring the Comments plugin in embedded mode, see: xref:comments-embedded-mode.adoc[Configuring the Comments plugin Comments in embedded mode] +In this mode, comments are stored directly within the content, without needing callback configuration. For setup details, refer to: xref:comments-embedded-mode.adoc[Configuring the Comments plugin in Embedded mode]. -include::partial$misc/admon-inline-editing-mode-does-not-support-comments.adoc[] +include::partial$misc/admon-inline-editing-mode-does-not-support-comments.adoc[] \ No newline at end of file diff --git a/modules/ROOT/pages/introduction-to-tiny-spellchecker.adoc b/modules/ROOT/pages/introduction-to-tiny-spellchecker.adoc index 78c36aafe7..5d9cfa5fd6 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' + spellchecker_language: 'en_US' }); ---- @@ -47,7 +47,7 @@ tinymce.init({ selector: 'textarea', plugins: 'tinymcespellchecker', spellchecker_rpc_url: 'localhost/ephox-spelling', - spellchecker_language: 'en' + spellchecker_language: 'en_US' }); ---- diff --git a/modules/ROOT/pages/keyboard-shortcuts.adoc b/modules/ROOT/pages/keyboard-shortcuts.adoc index 1e561b863b..5976e054bb 100644 --- a/modules/ROOT/pages/keyboard-shortcuts.adoc +++ b/modules/ROOT/pages/keyboard-shortcuts.adoc @@ -30,6 +30,7 @@ This is a list of available keyboard shortcuts within the editor body. |Focus to menu bar |Alt+F9 |⌥+F9 |core |Focus to toolbar |Alt+F10 |⌥+F10 |core |Focus to element path |Alt+F11 |⌥+F11 |core +|Focus to notification |Alt+F12 |⌥+F12 |core |Focus to contextual toolbar |Ctrl+F9 |Ctrl+F9 |core |Print |Ctrl+P |⌘+P |core |Open the {productname} Help dialog |Alt+0 |⌥+0 |xref:help.adoc[help] @@ -59,6 +60,7 @@ This is a list of available keyboard shortcuts within the editor user interface. |Close submenu |Left Arrow / Esc |Left Arrow / Esc |Close dialog |Esc |Esc |Close menu |Esc |Esc +|Close notification |Esc |Esc |Move focus back to editor body |Esc |Esc |=== diff --git a/modules/ROOT/pages/math.adoc b/modules/ROOT/pages/math.adoc new file mode 100644 index 0000000000..94046b7d90 --- /dev/null +++ b/modules/ROOT/pages/math.adoc @@ -0,0 +1,79 @@ += Math plugin +:navtitle: Math Plugin +:description: Math plugin allows users to insert math equations into the {productname} editor. +:description_short: Insert `++` elements into {productname}. +:keywords: plugin, math, formulas +:pluginname: Math +:plugincode: math +:plugincategory: premium + +include::partial$misc/admon-paid-addon-pricing.adoc[] + +include::partial$misc/admon-requires-7.1v.adoc[] + +The {pluginname} plugin provides a way for users to insert complex formulas. + +== Interactive example + +liveDemo::{plugincode}[] + +== Basic setup + +To set up the {pluginname} plugin user interface in the editor: + +* add `+math+` to the plugins option in the editor configuration; + +For example: + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'math', + toolbar: 'math', +}); +---- + +== How to Use + +To work with math elements, follow these steps: + +. **Enable Math Plugin** ++ +.. Open the {productname} editor with the {pluginname} plugin enabled. ++ +. **Insert or Edit {pluginname} Elements** +.. Click the {pluginname} plugin icon in the toolbar. +.. This opens the {pluginname} dialog. +.. Select preferred **language** +.. Enter {pluginname} **formula** in the textarea. +.. Choose preferred **text wrap** ++ +. **Preview and Save** +.. Check {pluginname} formula output in **preview.** +.. Review the final {pluginname} equation in the **preview** section. +.. Click the **save** button in the {pluginname} dialog. +.. The {pluginname} equation is inserted into the editor, wrapped accordingly based on the chosen **text wrap.** ++ + + +**Formula Tag Wrapping** + +. The {pluginname} dialog wraps the inserted formula with a specific tag. +. The choice of tag depends on the selected **text wrap** option in the dialog: +.. For block (_Text above and below_) text wrap, the tag used is ``. +.. For inline (_Inline with text_) text wrap, the tag used is ``. + + +[NOTE] +Visit link:https://katex.org/docs/supported.html[https://katex.org/docs/supported^] for a comprehensive list of supported symbols and functions when inserting mathematical equations after selecting "Language (LaTeX)". + +include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] + +include::partial$misc/plugin-menu-item-id-boilerplate.adoc[] + +== Commands + +The {pluginname} plugin provides the following {productname} commands. + +include::partial$commands/{plugincode}-cmds.adoc[] \ No newline at end of file diff --git a/modules/ROOT/pages/mergetags.adoc b/modules/ROOT/pages/mergetags.adoc index a8ce2f9f15..d5b1a2fbf3 100644 --- a/modules/ROOT/pages/mergetags.adoc +++ b/modules/ROOT/pages/mergetags.adoc @@ -66,13 +66,13 @@ For example, a merge tag can be set to any available typeface, type-size, foregr + A selected merge tag can be changed to any other merge tag by using the {pluginname} toolbar menu button. -. Text that matches an existing merge tag will be recognised as a merge tag when it is pasted or otherwise inserted into a {productname} document. +. Text that matches an existing merge tag will be recognized as a merge tag when it is pasted or otherwise inserted into a {productname} document. + -Content containing the specified prefix and suffix, and matching a specified merge tag, will be inserted as a merge tag when pasted into the editor. For example, if `Sender.Firstname` is a merge tag value, and the merge tag prefix and suffix have their default values, adding the string, `{{Sender.FirstName}}`, to a {productname} document will result in the string automatically being recognised as a merge tag. +Content containing the specified prefix and suffix, and matching a specified merge tag, will be inserted as a merge tag when pasted into the editor. For example, if `Sender.Firstname` is a merge tag value, and the merge tag prefix and suffix have their default values, adding the string, `{{Sender.FirstName}}`, to a {productname} document will result in the string automatically being recognized as a merge tag. . {pluginname} can be nested within the `+mergetags_list+` option. + -The `+mergetags_list+` option allows for the specification of a nested menu item within the {pluginname} toolbar menu button. This option allows any number of nested menus and items for merge tag categorisation. +The `+mergetags_list+` option allows for the specification of a nested menu item within the {pluginname} toolbar menu button. This option allows any number of nested menus and items for merge tag categorization. == Styling Merge Tags @@ -126,4 +126,4 @@ include::partial$configuration/mergetags_list.adoc[leveloffset=+1] include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] -include::partial$misc/plugin-menu-item-id-boilerplate.adoc[] +include::partial$misc/plugin-menu-item-id-boilerplate.adoc[] \ No newline at end of file diff --git a/modules/ROOT/pages/migration-from-6x.adoc b/modules/ROOT/pages/migration-from-6x.adoc index e5ce23071e..f28052f085 100644 --- a/modules/ROOT/pages/migration-from-6x.adoc +++ b/modules/ROOT/pages/migration-from-6x.adoc @@ -1,14 +1,14 @@ -= Migrating from TinyMCE 6 to TinyMCE 7 += Migrating from {productname} 6 to {productname} 7 :navtitle: Migrating from TinyMCE 6 :description: Guidance for migrating from TinyMCE 6 to TinyMCE 7 :keywords: migration, considerations, premigration, pre-migration +:release-version: 7.0 -The process for setting up a basic {productname} 7 instance is the same as {productname} 6. +The process for setting up a basic {productname} {release-version} instance is the same as {productname} 6. -Most configuration changes in {productname} 7.0 only affect complex use cases, such as custom plugins and customized user interface components. +Most configuration changes in {productname} {release-version} only affect complex use cases, such as custom plugins and customized user interface components. - -It set outs the {productname} 7.0 changes that customers using {productname} 6 should be aware of as part of upgrading. +This documentation details the changes in {productname} {release-version} that integrators using {productname} 6 should consider when upgrading. NOTE: For support related to migration, please contact https://support.tiny.cloud/hc/en-us/requests/new[Tiny Support]. + Open Source users: please report issues in the https://github.com/tinymce/tinymce/[TinyMCE GitHub Repository]. @@ -25,7 +25,7 @@ Open Source users: please report issues in the https://github.com/tinymce/tinymc [[tinymce-70-core-changes]] == {productname} {productmajorversion} core changes. -For additional details on {productname} 7.0 changes, see xref:7.0-release-notes.adoc[{productname} 7.0 release notes]. +For additional details on {productname} {release-version} changes, see xref:7.0-release-notes.adoc[{productname} {release-version} release notes]. [[commands-and-apis]] @@ -63,10 +63,10 @@ The `remove_trailing_brs` setting was removed from the xref:apis/tinymce.html.do Applying basic formats such as headings, lists, bold and italic from typing them out in Markdown syntax is considered a must-have for WYSIWYG Editor's. In previous versions, {productname} would only apply these formats once the user presses the `Enter` key. -{productname} 7 updates the default behavior of the `text-patterns` option to apply these formats when the user presses the `Space` key. +{productname} {release-version} updates the default behavior of the `text-patterns` option to apply these formats when the user presses the `Space` key. [NOTE] -The previous default `text_patterns` behavior, applying the format on an `Enter` key press, can be configured by replacing the `trigger` property with the value `'space'`. Learn more about how you can configure `text_patterns` in the xref:7.0-release-notes.adoc#a-new-trigger-property-for-block-text-pattern-configurations-allowing-pattern-activation-with-either-space-or-enter-keys[7.0 Release notes] +The previous default `text_patterns` behavior, applying the format on an `Enter` key press, can be configured by replacing the `trigger` property with the value `'space'`. Learn more about how you can configure `text_patterns` in the xref:7.0-release-notes.adoc#a-new-trigger-property-for-block-text-pattern-configurations-allowing-pattern-activation-with-either-space-or-enter-keys[{release-version} Release notes] .Updated default text patterns [source, ts] @@ -111,7 +111,7 @@ For more information, visit the updated xref:autocompleter.adoc[Autocompleter] d [[highlight-on-focus]] ==== `highlight_on_focus` -Previously, the default value for the editor configuration option `highlight_on_focus` was set to `false` by default. In {productname} 7.0 this option is now by default set to `true`. +Previously, the default value for the editor configuration option `highlight_on_focus` was set to `false` by default. In {productname} {release-version} this option is now by default set to `true`. As a result, the focus outline for the editor will by default be displayed when the focus is on the editor. @@ -125,19 +125,33 @@ This change does not impact editors using inline mode. [[force-hex-color]] ==== `force_hex_color` -Previously in {productname} 6, all colors in the content HTML were set to use `rgb` values by default. As the common practice is using `hex` values this change has been reverted. +Previously in {productname} 6, all colors in the content HTML were set to use `rgb` values by default. As the common practice is using `hex` values, this change has been reverted. .Example [source, html] ---- - + +// RGB value

    Hello red color

    - - +// RGBA value +

    Hello red color

    +// HSL value +

    Hello red color

    +// RGB value with alpha parameter +

    Hello red color

    +// RGB value with calculation +

    Hello red color

    + +

    Hello red color

    +

    Hello red color

    +

    Hello red color

    +// non-absolute values and absolute values with calculation will not be converted to HEX color +

    Hello red color

    +

    Hello red color

    ---- -In {productname} 7.0, all colors (excluding `rgba` values) are converted to use `hex` values and the `forced_hex_color` option has been removed. +In {productname} 7.0, only RGB values in absolute value like `rgb(255, 255, 255)` are converted to HEX values. Other RGB formats such as those with non-absolute values, and color options such as RGBA and HSL remain unchanged. The `forced_hex_color` option has been removed. [[plugins]] == Plugins @@ -198,7 +212,7 @@ For more information on using `+media_url_resolver+`, see xref:media.adoc#media_ [[removed-plugins]] === Removed Plugins -In {productname} 7.0 the below plugin has been removed. +In {productname} {release-version} the below plugin has been removed. [[removed-plugins-template-plugin]] ==== Removed open-source `Template` plugin @@ -228,13 +242,13 @@ Removed **Template** options: Previously, {productname} added numerous `height` styles when resizing table rows such as on the `table` element, `tr` elements, and `td` elements. This resulted in unnecessarily verbose HTML output. -{productname} 7.0 addresses this by making a couple of changes: +{productname} {release-version} addresses this by making a couple of changes: * The height input field has been removed from the "Cell Properties" dialog. Now, the "Row Properties" dialog is the only way to update row heights. * When a table is resized using the resize handles or the "Row properties" dialog, existing `height` styles will be stripped from `td/th` elements where applicable and only applied to the `table` element and `tr` elements. [NOTE] -{productname} 7.0 does not provide any fallback to revert to the old behavior. +{productname} {release-version} does not provide any fallback to revert to the old behavior. === Removed diff --git a/modules/ROOT/pages/pageembed.adoc b/modules/ROOT/pages/pageembed.adoc index a3f9c25a5f..cc88b7a8c9 100644 --- a/modules/ROOT/pages/pageembed.adoc +++ b/modules/ROOT/pages/pageembed.adoc @@ -58,8 +58,8 @@ NOTE: The *Responsive* option has pre-defined width and height values. The *Widt . In the *Advanced* tab, provide a name and title for the iframe in the *Name* and *Title* fields. . The *Long description URL* field can be used to describe an iframe by including text in a separate resource when a short text alternative does not adequately convey the function or information provided in the iframe. * Click on the image:icons/browse.svg[Source](*Long description URL*) icon to upload a description file. -. Click on the *Show iframe border* radio button to display iframe borders. -. Click on the *Scrollbar* radio button to add scrollbars to the iframe. +. Click on the *Show iframe border* checkbox to display iframe borders. +. Click on the *Scrollbar* checkbox to add scrollbar to the iframe. . Click *Save* to save and exit or *Cancel* to dismiss and exit. *Result*: An iframe of the configured size is inserted in the desired location within the content. diff --git a/modules/ROOT/pages/permanentpen.adoc b/modules/ROOT/pages/permanentpen.adoc index 6cbe0f5166..a9e6bf4056 100644 --- a/modules/ROOT/pages/permanentpen.adoc +++ b/modules/ROOT/pages/permanentpen.adoc @@ -87,7 +87,7 @@ NOTE: The Permanent Pen has to be enabled to access the *Permanent Pen Propertie . Open the *Permanent Pen Properties* dialog box using any of the above methods. image:permanent-pen-props.png[Permanent pen properties] . Select the desired settings from the *Font* and *Size* drop-down menus. -. To select the desired *Styles*, click on the radio button next to *Bold*, *Italic*, *Strikethrough*, or *Underline*. +. To select the desired *Styles*, click on the checkbox next to *Bold*, *Italic*, *Strikethrough*, or *Underline*. . Choose the desired *Text color*. . Select the desired *Background color* . Press *Ok* to save or *Cancel* to dismiss. diff --git a/modules/ROOT/pages/powerpaste-options.adoc b/modules/ROOT/pages/powerpaste-options.adoc index 9d5b68b347..62b788dc5f 100644 --- a/modules/ROOT/pages/powerpaste-options.adoc +++ b/modules/ROOT/pages/powerpaste-options.adoc @@ -19,6 +19,8 @@ include::partial$configuration/powerpaste_googledocs_import.adoc[leveloffset=+1] include::partial$configuration/powerpaste_html_import.adoc[leveloffset=+1] +include::partial$configuration/powerpaste_autolink_urls.adoc[leveloffset=+1] + include::partial$configuration/powerpaste_allow_local_images.adoc[leveloffset=+1] include::partial$configuration/paste_block_drop.adoc[leveloffset=+1] diff --git a/modules/ROOT/pages/react-cloud.adoc b/modules/ROOT/pages/react-cloud.adoc index 5cfc646688..90667b351d 100644 --- a/modules/ROOT/pages/react-cloud.adoc +++ b/modules/ROOT/pages/react-cloud.adoc @@ -1,7 +1,7 @@ = Using TinyMCE from the Tiny Cloud CDN with the React framework :navtitle: React :description: A guide on integrating TinyMCE from the Tiny Cloud into the React framework. -:keywords: integration, integrate, react, reactjs, create-react-app, tinymce-react +:keywords: integration, integrate, react, reactjs, vite, tinymce-react :productSource: cloud include::partial$integrations/react-quick-start.adoc[] diff --git a/modules/ROOT/pages/react-pm-bundle.adoc b/modules/ROOT/pages/react-pm-bundle.adoc index 3bb53c0340..f01456116b 100644 --- a/modules/ROOT/pages/react-pm-bundle.adoc +++ b/modules/ROOT/pages/react-pm-bundle.adoc @@ -1,7 +1,7 @@ = Bundling the TinyMCE package with the React framework :navtitle: Using a package manager with bundling :description: A guide on integrating the TinyMCE package into the React framework by bundling it. -:keywords: integration, integrate, react, reactjs, create-react-app, tinymce-react, bundle +:keywords: integration, integrate, react, reactjs, vite, tinymce-react, bundle :productSource: package-manager :productUse: bundle diff --git a/modules/ROOT/pages/react-pm-host.adoc b/modules/ROOT/pages/react-pm-host.adoc index 7fb69c31ab..d193822346 100644 --- a/modules/ROOT/pages/react-pm-host.adoc +++ b/modules/ROOT/pages/react-pm-host.adoc @@ -2,7 +2,7 @@ :page-aliases: react-pm.adoc :navtitle: Using a package manager with hosting :description: A guide on integrating the TinyMCE package into the React framework by self-hosting it. -:keywords: integration, integrate, react, reactjs, create-react-app, tinymce-react, host +:keywords: integration, integrate, react, reactjs, vite, tinymce-react, host :productSource: package-manager :productUse: host diff --git a/modules/ROOT/pages/react-zip-bundle.adoc b/modules/ROOT/pages/react-zip-bundle.adoc index 072e753695..6281d40ae1 100644 --- a/modules/ROOT/pages/react-zip-bundle.adoc +++ b/modules/ROOT/pages/react-zip-bundle.adoc @@ -1,7 +1,7 @@ = Bundling the TinyMCE .zip package with the React framework :navtitle: Using a .zip package with bundling :description: A guide on integrating a .zip version of TinyMCE into the React framework by bundling it. -:keywords: integration, integrate, react, reactjs, create-react-app, tinymce-react, bundle +:keywords: integration, integrate, react, reactjs, vite, tinymce-react, bundle :productSource: zip :productUse: bundle diff --git a/modules/ROOT/pages/react-zip-host.adoc b/modules/ROOT/pages/react-zip-host.adoc index a91609f9ae..4fdf72456c 100644 --- a/modules/ROOT/pages/react-zip-host.adoc +++ b/modules/ROOT/pages/react-zip-host.adoc @@ -2,7 +2,7 @@ :page-aliases: react-zip.adoc :navtitle: Using a .zip package with hosting :description: A guide on integrating a .zip version of TinyMCE into the React framework by self-hosting it. -:keywords: integration, integrate, react, reactjs, create-react-app, tinymce-react, host +:keywords: integration, integrate, react, reactjs, vite, tinymce-react, host :productSource: zip :productUse: host diff --git a/modules/ROOT/pages/release-notes.adoc b/modules/ROOT/pages/release-notes.adoc index ca6a9bb2e1..9b6f8be992 100644 --- a/modules/ROOT/pages/release-notes.adoc +++ b/modules/ROOT/pages/release-notes.adoc @@ -9,6 +9,72 @@ This section lists the releases for {productname} 7 and the changes made in each [cols="1,1"] |=== +a| +[.lead] +xref:7.6.0-release-notes.adoc#overview[{productname} 7.6.0] + +Release notes for {productname} 7.6.0 + +a| +[.lead] +xref:7.5.1-release-notes.adoc#overview[{productname} 7.5.1] + +Release notes for {productname} 7.5.1 + +a| +[.lead] +xref:7.5-release-notes.adoc#overview[{productname} 7.5] + +Release notes for {productname} 7.5 + +a| +[.lead] +xref:7.4.1-release-notes.adoc#overview[{productname} 7.4.1] + +Release notes for {productname} 7.4.1 + +a| +[.lead] +xref:7.4-release-notes.adoc#overview[{productname} 7.4] + +Release notes for {productname} 7.4 + +a| +[.lead] +xref:7.3-release-notes.adoc#overview[{productname} 7.3] + +Release notes for {productname} 7.3 + +a| +[.lead] +xref:7.2.1-release-notes.adoc#overview[{productname} 7.2.1] + +Release notes for {productname} 7.2.1 + +a| +[.lead] +xref:7.2-release-notes.adoc#overview[{productname} 7.2] + +Release notes for {productname} 7.2 + +a| +[.lead] +xref:7.1.2-release-notes.adoc#overview[{productname} 7.1.2] + +Release notes for {productname} 7.1.2 + +a| +[.lead] +xref:7.1.1-release-notes.adoc#overview[{productname} 7.1.1] + +Release notes for {productname} 7.1.1 + +a| +[.lead] +xref:7.1-release-notes.adoc#overview[{productname} 7.1] + +Release notes for {productname} 7.1 + a| [.lead] xref:7.0.1-release-notes.adoc#overview[{productname} 7.0.1] @@ -21,14 +87,7 @@ xref:7.0-release-notes.adoc#overview[{productname} 7.0] Release notes for {productname} 7.0 -// Dummy table cell. -// 1. When the number of cells in the table is odd: -// * remove the inline comment markup pre-pending this -// element. -// -// 2. When the number of cells in the table is even: -// * prepend the inline comment markup to this -// element. -// a| +// Uncomment this dummy cell when the number of cells above is odd to ensure the table renders correctly. +a| |=== diff --git a/modules/ROOT/pages/revisionhistory.adoc b/modules/ROOT/pages/revisionhistory.adoc index cc19c429f2..06fc18b2b1 100644 --- a/modules/ROOT/pages/revisionhistory.adoc +++ b/modules/ROOT/pages/revisionhistory.adoc @@ -2,7 +2,7 @@ :navtitle: Revision History :description: A view that allows {productname} users to see historical snapshots of a document and an ability to restore from a snapshot :description_short: View containing historical snapshots of a document. -:keywords: plugin, Revision History, history, version, snapshots, restore, changes +:keywords: plugin, Revision History, history, version, snapshots, restore, changes, revision, diff :pluginname: Revision History :plugincode: revisionhistory :plugincategory: premium @@ -11,7 +11,7 @@ include::partial$misc/admon-revisionhistory-paid-addon-pricing.adoc[] include::partial$misc/admon-requires-7.0v.adoc[] -The {pluginname} plugin offers users the ability to view document changes over time and restore previous versions effortlessly. +The {pluginname} plugin offers users the ability to view document changes over time and restore previous revisions effortlessly. == Interactive example @@ -26,24 +26,24 @@ The {pluginname} view is accessible via either the `revisionhistory` toolbar but The key components are: 1. In the {pluginname} view header, there are two buttons. -* `Restore this version`: Set the selected version's content to the editor and close the view. -* `Close`: Close the view. +* `Restore this version`: Sets the selected revision's content to the editor and closes the view. Note: the button is disabled for the `initial` and `draft` revisions. +* `Close`: Closes the **Revision History** view. -2. The readonly diff view presents the changes between the selected version and its immediate predecessor, clearly highlighting for easy recognition. The changes are also color-coded for clarity: +2. The readonly diff view presents the changes between the selected revision and its immediate predecessor, clearly highlighting for easy recognition. The changes are also color-coded for clarity: * Red: Removed content. * Green: New content. * Yellow: Content being modified. Modifications to HTML content implies attributes or formatting (e.g. bold, italic, etc.). -3. The revisions sidebar displays all available document versions. When a new version is selected, the diff view is updated accordingly. +3. The revisions sidebar displays all available document revisions. When a revision is selected, the diff view is updated accordingly. [NOTE] The default highlighting colors can be customized using the xref:revisionhistory_css_url[`+revisionhistory_css_url+`] option. [NOTE] -The {pluginname} plugin interprets commented HTML as valid content, yet it disregards this content during the version comparison process. Consequently, a version containing solely commented content appears as empty in the user interface displaying the differential content. +The {pluginname} plugin processes commented HTML as valid content but disregards it during the revision comparison process. Revisions containing only commented content appear as empty in the view. == Basic setup -To setup the {pluginname} plugin user-interface in the editor: +To setup the {pluginname} plugin in the editor: * add `{plugincode}` to the `plugins` option in the editor configuration; * add `{plugincode}` to the `toolbar` option in the editor configuration; @@ -57,44 +57,62 @@ tinymce.init({ selector: 'textarea', // change this value according to your HTML plugins: 'revisionhistory', toolbar: 'revisionhistory', - // Required - revisionhistory_fetch: () => new Promise((resolve) => { - const revisions = []; // Replace this with an API request to get saved versions - resolve(revisions); - }) + revisionhistory_fetch: () => Promise.resolve([]), // Replace this with an API request to get saved revisions }); ---- -== Understanding initial and current versions +== Understanding revision types -When dealing with a new document, that has no saved versions, {pluginname} plugin will always typically maintain two versions: the `initial` and `current` versions. +The {pluginname} plugin offers three revision types: -* Initial Version: This version is generated during the {productname} `Loaded` event, with the editor's initial content. -* Current Version: This is generated upon accessing the {pluginname}, reflecting the editor's current content. When included, it becomes the `latest version` and is placed at the top of the revisions list. +. **Initial**: This revision is generated during the {productname} `Loaded` event, capturing the editor's initial content. +. **Draft**: Generated upon opening the {pluginname}, this revision reflects the editor's current content. When included, it becomes the `latest revision` in the revisions list. +. **Saved**: These revisions are fetched from the client's storage when opening the {pluginname} view, using the `revisionhistory_fetch` and `revisionhistory_fetch_revision` options. -[TIP] -When the editor is initialized with content and both versions contain the same content, the {pluginname} retains only the `current version`. +When working with a document that has no saved revisions, the {pluginname} plugin typically maintains two revisions: `initial` and `draft`. If no changes have been made to the content since initialization, the `initial` revision is not displayed, as it is identical to the `draft` revision. -For documents with saved versions, the `initial version` is disregarded by the {pluginname} assuming it's already part of the version history. The current version is discarded if its content matches the closest saved version. +For documents with saved revisions, the `initial` revision is disregarded, assuming it already exists among the saved revisions. To include the initial content, add it as a revision using the `revisionhistory_fetch` option. -The table below summarizes how versions are handled in the {pluginname}: +== Data structure -[cols="1,1,1,3", options="header"] +=== Revision + +The revision is an `+Object+` that contains the following fields: + +[cols="1,1,1,3",options="header"] +|=== +| Field | Type | Required? | Description +| `+revisionId+` | `+string+` | required | The unique string ID of the revision. +| `+createdAt+` | `+string+` | required | A UTC datetime string in ISO-8061 format. +| `+content+` | `+string+` | optional | HTML string of the revision content. Empty string is considered as valid content. +| `+author+` | xref:#author[Author] `+Object+` | optional | The author of the revision. +|=== + +=== Author + +The author is an `+Object+` that represents the author or creator of a revision. It contains the following fields: + +[cols="1,1,1,3",options="header"] |=== -|Has Initial Version |Current Version |Has Saved Versions |Expectation -|No |N/A |No |No versions are shown -|No |N/A |Yes |Only the saved versions are shown -|Yes |N/A |No |Only the current version is shown -|Yes |Different |No |Both the initial and current versions are shown -|Yes |N/A |Yes |The saved versions and the current version are shown +| Field | Type | Required? | Description +| `+id+` | `+string+` | required | The unique string ID of the author. +| `+name+` | `+string+` | optional | The name of the revision author. If not provided, the default value is `Anonymous`. +| `+avatar+` | `+string+` | optional | The URL of the author's avatar image. If not provided or invalid, the {pluginname} will use a generated avatar using the author's initials. |=== + == Options The following configuration options affect the behavior of the {pluginname} plugin. include::partial$configuration/revisionhistory_fetch.adoc[leveloffset=+1] +include::partial$configuration/revisionhistory_fetch_revision.adoc[leveloffset=+1] + +include::partial$configuration/revisionhistory_author.adoc[leveloffset=+1] + +include::partial$configuration/revisionhistory_display_author.adoc[leveloffset=+1] + include::partial$configuration/revisionhistory_css_url.adoc[leveloffset=+1] include::partial$configuration/revisionhistory_diff_classes.adoc[leveloffset=+1] @@ -113,4 +131,10 @@ include::partial$commands/{plugincode}-cmds.adoc[] The {pluginname} plugin provides the following events. -include::partial$events/{plugincode}-events.adoc[] \ No newline at end of file +include::partial$events/{plugincode}-events.adoc[] + +== APIs + +The {pluginname} plugin provide the following APIs. + +include::partial$plugin-apis/{plugincode}-apis.adoc[] \ No newline at end of file diff --git a/modules/ROOT/pages/shadow-dom.adoc b/modules/ROOT/pages/shadow-dom.adoc index 4aa811784d..b4bd46641f 100644 --- a/modules/ROOT/pages/shadow-dom.adoc +++ b/modules/ROOT/pages/shadow-dom.adoc @@ -31,11 +31,12 @@ For example: // Do not use ‘selector’. target: node, plugins: [ - "advlist autolink lists link image charmap print preview anchor", - "searchreplace visualblocks code fullscreen", - "insertdatetime media table help" - ].join(' '), - toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image" + "advlist", "anchor", "autolink", "charmap", "code", "fullscreen", + "help", "image", "insertdatetime", "link", "lists", "media", + "preview", "searchreplace", "table", "visualblocks", + ], + toolbar: "undo redo | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image", + }); ---- diff --git a/modules/ROOT/pages/tinydrive-dropbox-integration.adoc b/modules/ROOT/pages/tinydrive-dropbox-integration.adoc index d20dcc2b3a..26d76ffb91 100644 --- a/modules/ROOT/pages/tinydrive-dropbox-integration.adoc +++ b/modules/ROOT/pages/tinydrive-dropbox-integration.adoc @@ -51,7 +51,7 @@ For information on other {cloudfilemanager} config options refer to the xref:tin . From the {productname} user interface, click on the image:insertimage.png[Insert/edit image] button to access the {cloudfilemanager} user interface. . Click on the image:upload.png[Upload/Create] button to select Dropbox from the list of storages. -. Select the file to upload/import from Dropbox by clicking on the radio button next to it and click the *Choose* button to upload or *Cancel* to abort the operation. +. Select the file to upload/import from Dropbox by clicking on the checkbox next to it and click the *Choose* button to upload or *Cancel* to abort the operation. . Alternatively, files from your local browser can be uploaded to the Dropbox by clicking on the *Upload files* option and selecting the files to upload. *Result:* You should be able to view the selected files in your {cloudfilemanager} storage. diff --git a/modules/ROOT/pages/tinydrive-googledrive-integration.adoc b/modules/ROOT/pages/tinydrive-googledrive-integration.adoc index 5a2f518778..296616bafa 100644 --- a/modules/ROOT/pages/tinydrive-googledrive-integration.adoc +++ b/modules/ROOT/pages/tinydrive-googledrive-integration.adoc @@ -74,7 +74,7 @@ For information on other {cloudfilemanager} config options refer to the xref:tin . From the {productname} user interface, click on the image:insertimage.png[Insert/edit image] button to access the {cloudfilemanager} user interface. . Click on the image:upload.png[Upload/Create] button to select Google Drive from the list of storages. -. Select the file to upload/import from Google Drive by clicking on the radio button next to it. Alternatively, to directly insert the file into the editor, double-click on it. +. Select the file to upload/import from Google Drive by clicking on the checkbox button next to it. Alternatively, to directly insert the file into the editor, double-click on it. . Choose *Save* to upload/import the selected file/files to {cloudfilemanager}. *Result:* You should be able to view the selected files in your {cloudfilemanager} storage. diff --git a/modules/ROOT/pages/tinymce-and-screenreaders.adoc b/modules/ROOT/pages/tinymce-and-screenreaders.adoc index 9c3e34a236..7d16a59194 100644 --- a/modules/ROOT/pages/tinymce-and-screenreaders.adoc +++ b/modules/ROOT/pages/tinymce-and-screenreaders.adoc @@ -16,6 +16,7 @@ The following *Alt+key* and *Option+key* shortcuts can only be used when the con |Focus/jump to menu bar |Alt+F9 |⌥+F9 |Focus/jump to toolbar |Alt+F10 |⌥+F10 |Focus/jump to element path |Alt+F11 |⌥+F11 +|Focus/jump to notification |Alt+F12 |⌥+F12 |Close menu/submenu/dialog |Esc |Esc |Return to the editor content area |Esc |Esc |Navigate left/right through menu/toolbar |Tab and the Arrow Keys |Tab and the Arrow Keys @@ -46,6 +47,10 @@ To open submenus or grid selections on toolbar buttons, use the *Enter*, *Return Dialogs such as *Insert/Edit Image* are opened from either a menu item or a toolbar button. Some dialogs contain multiple tabs or pages of options. To change tabs or pages, use the arrow keys; the highlighted tab will become active immediately. Use the *Tab* key to navigate between the dialog options on the selected dialog tab. The *Save* dialog button stores the changes, and the *Cancel* dialog button or the *Esc* key discards changes. +=== Navigating notifications + +To focus on the editor notifications, press *Alt+F12* (or *⌥+F12*); which moves the keyboard focus to the first notification. To move the focus _between_ notifications and other focusable elements (e.g. links or buttons) within a notification, use the *Tab* key. Use *Shift+Tab* key to navigate backward. When you reach the end of the elements within a notification using *Tab* key, it will either cycle to the next notification in the list or cycle back to the first one if you're already on the last. To close the currently focused notification, press the *Esc* key. + == Accessibility options {productname} has accessibility options that can be set when initializing the editor, see: xref:accessibility.adoc[Accessibility options]. diff --git a/modules/ROOT/pages/uploadcare.adoc b/modules/ROOT/pages/uploadcare.adoc new file mode 100644 index 0000000000..323fd687fe --- /dev/null +++ b/modules/ROOT/pages/uploadcare.adoc @@ -0,0 +1,216 @@ += {pluginname} plugin +:navtitle: Image Optimizer Powered by Uploadcare +:description: The Image Optimizer Powered by Uploadcare plugin allows you to optimize images in your content. +:description_short: +:plugincode: uploadcare +:pluginname: Image Optimizer Powered by Uploadcare +:keywords: plugin, {plugincode}, image, align, transform, alt text, caption, adjust, filter +:plugincategory: premium + +include::partial$misc/admon-premium-plugin.adoc[] + +include::partial$misc/admon-requires-7.6v.adoc[] + +== Overview + +The **Image Optimizer** plugin offers a range of powerful features for image hosting, serving, and editing. These include responsive image delivery, automatic image format selection, automatic compression, and non-destructive image transformations and adjustments, all powered by link:https://uploadcare.com[Uploadcare]. + +== Key benefits + +* Improve page loading speed and save on bandwidth by serving images in the optimal size, format, and compression based on the visitor's browser and device. +* Ditch the image editor and adjust images right inside {productname} with non-destructive transformations and adjustments. Change your mind any time! +* Stay safe and compliant with secure uploads, built in malware protection, and unsafe content detection +* Enterprise-ready scalable cloud storage provided by Uploadcare, delivered through its lightning-fast global CDN, and compliant with SOC2 and GDPR standards. + +== Interactive example + +liveDemo::{plugincode}[] + +== Basic setup + +To add the {pluginname} plugin to the editor, add `{plugincode}` to the `plugins` option in the editor configuration. + +For example: + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'uploadcare', + toolbar: 'uploadcare', + uploadcare_public_key: '', + // uploadcare_signed_upload_auth_provider: (_publicKey) => Promise.resolve({ + // signature: 'sig', + // expire: 123 + // }), // Recommended option for secure uploads +}); +---- + +[NOTE] +==== +The {pluginname} plugin overrides the xref:quickbars.adoc[Quickbar] quickimage toolbar item. To ensure a better user experience and to avoid having two image buttons configure `quickbars_insert_toolbar` to omit the `quickimage` toolbar item. +==== + +== Image Operations + +Below is an overview of the features of the {pluginname} plugin includes for image optimization: + +[cols="1,1,^1,3",options="header"] +|=== +| Feature | Operation | Icon | Description + +| Align +| +| image:icons/align-left.svg[align-left.svg] +| Provides alignment options for the image or element. + +| +| Align Left +| image:icons/align-left.svg[align-left.svg] +| Aligns the image to the left. + +| +| Align Centre +| image:icons/align-center.svg[align-center.svg] +| Centers the image. + +| +| Align Right +| image:icons/align-right.svg[align-right.svg] +| Aligns the image to the right. + +| Transform +| +| image:icons/transform-image.svg[transform-image.svg] +| Allows users to apply transformations to the image: + +| +| Rotate Left +| image:icons/rotate-left.svg[rotate-left.svg] +| Rotates the image counterclockwise (left). + +| +| Rotate Right +| image:icons/rotate-right.svg[rotate-right.svg] +| Rotates the image clockwise (right). + +| +| Flip Vertically +| image:icons/flip-vertically.svg[flip-vertically.svg] +| Flips the image vertically. + +| +| Flip Horizontally +| image:icons/flip-horizontally.svg[flip-horizontally.svg] +| Flips the image horizontally. + +| +| Resize +| image:icons/resize.svg[resize.svg] +| Changes the size of the image. + +| Alt Text +| +| image:icons/alt-text.svg[alt-text.svg] +| Adds alternative text to describe the image for accessibility purposes. + +| +| Decorative Image +| image:icons/image-decorative.svg[image-decorative.svg] +a| +Marks the image as decorative, indicating it doesn't require alternative text for accessibility. + +This icon will only appear when the `a11y_advanced_options` configuration option is enabled. + +| Caption +| +| image:icons/caption.svg[caption.svg] +| Adds a caption below the image for additional context. + +| Adjust +| +| image:icons/adjustments.svg[adjustments.svg] +| Provides tools for adjusting image properties: + +| +| Brightness +| image:icons/brightness.svg[brightness.svg] +| Adjusts the image brightness. + +| +| Contrast +| image:icons/contrast.svg[contrast.svg] +| Adjusts the image contrast. + +| +| Exposure +| image:icons/exposure.svg[exposure.svg] +| Adjusts the image exposure. + +| +| Gamma +| image:icons/gamma.svg[gamma.svg] +| Adjusts the image gamma. + +| +| Vibrance +| image:icons/vibrance.svg[vibrance.svg] +| Adjusts the image vibrance. + +| +| Saturation +| image:icons/saturation.svg[saturation.svg] +| Adjusts the image saturation. + +| +| Warmth +| image:icons/warmth.svg[warmth.svg] +| Adjusts the image warmth. + +| +| Grayscale +| image:icons/grayscale.svg[grayscale.svg] +| Converts the image to grayscale. + +| +| Invert Colors +| image:icons/invert.svg[invert.svg] +| Inverts the image colors. + +| +| Sharpen +| image:icons/sharpen.svg[sharpen.svg] +| Sharpens the image. + +| +| Blur +| image:icons/blur.svg[blur.svg] +| Blurs the image. + +| Revert +| +| image:icons/revert.svg[revert.svg] +| Restores the image to its original state by undoing all edits. +|=== + +== Options + +The following configuration options affect the behavior of the {pluginname} plugin. + +include::partial$configuration/uploadcare_public_key.adoc[leveloffset=+1] + +include::partial$configuration/uploadcare_signed_upload_auth_provider.adoc[leveloffset=+1] + +include::partial$configuration/uploadcare_cdn_base_url.adoc[leveloffset=+1] + +include::partial$configuration/uploadcare_srcset_steps.adoc[leveloffset=+1] + +include::partial$configuration/uploadcare_store_type.adoc[leveloffset=+1] + +:includedSection: uploadcarePlugin +include::partial$configuration/a11y_advanced_options.adoc[leveloffset=+1] +:!includedSection: + +include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] + +include::partial$misc/plugin-menu-item-id-boilerplate.adoc[] diff --git a/modules/ROOT/pages/usage-based-billing.adoc b/modules/ROOT/pages/usage-based-billing.adoc new file mode 100644 index 0000000000..f26a7fe227 --- /dev/null +++ b/modules/ROOT/pages/usage-based-billing.adoc @@ -0,0 +1,70 @@ + += About Tiny Cloud's Usage-Based Billing (UBB) +:description_short: About Tiny Cloud's Usage-Based Billing (UBB) | {productname} +:description: Learn more about what Tiny Cloud's Usage-Based Billing (UBB) is, and how it affects your application. +:keywords: {productname}, cloud, script, textarea, ubb, faq, usage-based billing, frequently asked questions, usage, billing + + +[NOTE] +The below information is only relevant to Tiny Cloud users. Users who self-host the open source version of {productname} are not subject to Usage-Based Billing terms, but are required to comply with the open source license terms. + +== Definitions + +Understanding the following terms related to Usage-Based Billing can assist you in making an informed decision when selecting the appropriate link:https://www.tiny.cloud/pricing[pricing plan] to best suit your needs: + +== Tiny Cloud + +Tiny Cloud is our user-friendly cloud-based editor service that hosts {productname} in the cloud. It provides access to the link:https://www.tiny.cloud/tinymce/features/[premium features] of our rich text editor. With link:https://www.tiny.cloud/solutions/on-premise-or-cloud-based-text-editor/[Tiny Cloud], you can enjoy the benefits of automatic updates, ensuring your {productname} editor is always equipped with the latest features, enhancements, and security patches. + +Alternatively, if you prefer to utilize only the free open-source version of {productname} and your project aligns with our open-source software license, you can self-host {productname} in the cloud using any CDN service of your choice, bypassing the need for Tiny Cloud. +If you want to self-host {productname} and still access our Premium features like link:https://www.tiny.cloud/tinymce/features/powerpaste/[PowerPaste], link:https://www.tiny.cloud/tinymce/features/accessibility-checker/[Accessibility Checker], link:https://www.tiny.cloud/tinymce/features/templates/[Templates], link:https://www.tiny.cloud/tinymce/features/ai-integration/[AI Assistant], and many more, link:https://www.tiny.cloud/contact/[contact our sales team] for a quote. + +=== Editor Load + +An xref:understanding-editor-loads.adoc[editor load] is the event that occurs each time {productname} is initialized in your application. The editor dispatches the 'init' event to indicate a successful load. For example, if 100 users load {productname} 10 times each, the result would be 1,000 editor loads. + +Learn more about xref:understanding-editor-loads.adoc#how-are-editor-loads-counted[how we count editor loads]. + +=== How Usage-Based Billing works + +Usage-Based Billing means the cost you incur depends on how much you use the {productname} editor. + +Each of our pricing plans includes a specific number of editor loads. If you require additional editor loads, you have the option to upgrade to a more suitable plan or pay for every block of 1,000 editor loads over your allocated plan limit. + +=== When does my billing month start? + +Your billing month starts the day after your trial ends. + +For example, if the last day of your trial is May 15^th^, we start counting your monthly editor loads on May 16^th^, and then reset that count to 0 every 16^th^ day of each subsequent month. + +[IMPORTANT] +Unused editor loads do not carry over to the next month. + +=== What happens if I exceed my monthly limit? + +If you exceed your monthly limit, you will automatically be charged $40 USD for every block of 1,000 editor loads over your allocated plan limit. + +=== What if I’m using the free {productname} Core plan? + +If you use our free {productname} Core plan without providing a valid payment method and exceed your allocated editor loads, your editor will transition to read-only mode until the next month. If you provide a valid payment method, you will automatically be charged $40 USD for every block of 1,000 editor loads over our allocated plan limit. + +=== How can I ensure I don’t go over my monthly limit? + +All Admin users can check their usage data for the past six months in the {productname} Usage section of the Customer Portal. Usage data for the current billing cycle can be found in the Customer Portal > Settings > Billing Portal. We recommend monitoring your editor loads and choosing a plan that will both meet your needs and minimize your costs. Additionally, we will send an email notification to the address associated with your plan when you reach 70% of your monthly editor loads. + +If your editor loads are consistently exceeding your plan limit, we suggest upgrading your plan to minimize costs. You can review the cost of link:https://www.tiny.cloud/pricing/[upgrading to a higher plan] at any time and can upgrade in the Billing Portal to immediately receive a higher editor load limit and new capabilities. + +[NOTE] +We recommend that the email address associated with your plan is linked to either a group alias, IT, or administrator address that will remain valid over time (e.g. accounts@example.com). By doing so, you'll avoid any disruption of {productname} in your project or application in the event of organizational or staff changes. + +=== How are editor loads counted during the free 14-day trial period? + +During the trial, you can enjoy unlimited editor loads. + +=== I have an annual plan. Are my editor loads calculated monthly or over the entire year? + +If you have an annual plan, your editor loads are calculated on a monthly basis within the structure of your annual plan. Similar to our monthly plans, you have a set monthly editor load limit and are automatically charged $40 USD per every block of 1,000 editor loads over your allocated plan limit. Learn more about Tiny Cloud’s Usage-Based Billing model. + +=== If I’m on the Essential plan and reach 5,000 editor loads, will I automatically be upgraded to the Professional plan? + +You will not automatically be upgraded. You will remain on your current plan and will automatically be charged $40 USD for each additional block of 1,000 editor loads over your plan limit. To avoid these charges, we encourage you to periodically review your editor load count to ensure you’re on the most appropriate pricing plan. You can always upgrade your plan in our Customer Portal > Settings > Billing Portal > Change Plans. \ No newline at end of file diff --git a/modules/ROOT/pages/wordpress.adoc b/modules/ROOT/pages/wordpress.adoc index daaae0703c..dea3255600 100644 --- a/modules/ROOT/pages/wordpress.adoc +++ b/modules/ROOT/pages/wordpress.adoc @@ -20,5 +20,4 @@ https://wordpress.org/plugins/tinymce-advanced/[Advanced Editor Tools] is a Word For details, visit: -* https://wordpress.org/plugins/tinymce-advanced/[WordPress.org Plugins - Advanced Editor Tools]. -* link:{blogurl}/how-to-use-tinymce-premium-plugins-in-wordpress-5[{companyname} Blog - How to use TinyMCE premium plugins in WordPress 5]. +* https://wordpress.org/plugins/tinymce-advanced/[WordPress.org Plugins - Advanced Editor Tools]. \ No newline at end of file diff --git a/modules/ROOT/pages/yeoman-generator.adoc b/modules/ROOT/pages/yeoman-generator.adoc deleted file mode 100644 index dee7577fe6..0000000000 --- a/modules/ROOT/pages/yeoman-generator.adoc +++ /dev/null @@ -1,74 +0,0 @@ -= TinyMCE plugin Yeoman generator -:navtitle: Yeoman generator -:description_short: How to use the Yeoman generator to bootstrap a new TinyMCE plugin -:description: How to use the Yeoman generator to bootstrap a new TinyMCE plugin using ES2015/Babel or TypeScript. -:keywords: webpack, yeoman, generator, plugin, tinymce - -{companyname} maintains a xref:yeoman-generator.adoc[Yeoman generator] to assist with creating plugins for {productname}. The Yeoman Generator will create the files and boilerplate code required for a custom plugin, and sets up some helpful commands. - -== Install the generator - -The plugin generator is built with the project scaffolding tool http://yeoman.io/[Yeoman]. To get started install both `+yo+` (the yeoman command) and the generator with the following command: - -[source,sh] ----- -npm install --global yo generator-tinymce ----- - -Wait for the install to finish. - -== Run the generator - -Start the generator with the following command: - -[source,sh] ----- -yo tinymce ----- - -You will then be guided through these questions: - -. *Plugin name:* The name of the plugin. -. *Plugin description (optional):* An optional description of the plugin. -. *Initialize git repo?* Here you can skip the creation of a new repository for the plugin. -. *What’s your name?* For license. -. *Your email (optional):* For license. -. *Your website (optional):* For license. -. *Which license do you want to use?* Choose the license for the plugin. - -Yeoman installs the needed dependencies, and the project is bootstrapped and ready. `+cd+` into the plugin directory and run the following command to start the auto-reloading development server: - -[source,sh] ----- -npm start ----- - -== Create distribution ready build - -Run the following command once you have completed development of the plugin: - -[source,sh] ----- -yarn build ----- - -A `+dist+` directory will be created, containing a sub-directory with the same name as the plugin. The sub-directory will contain the following files: - -* `+plugin.js+` - unminified plugin bundle -* `+plugin.min.js+` - minified and uglified plugin bundle -* `+CHANGELOG.txt+` - the text file containing your changes -* `+LICENSE.txt+` - the text file containing your license -* `+version.txt+` - the text file containing the version of your plugin - -For example, `+yarn build+` will generate the following output for a plugin named `+my_plugin+`: - -[source,sh] ----- -dist/ -└── my_plugin/ - ├── CHANGELOG.txt - ├── LICENSE.txt - ├── plugin.js - ├── plugin.min.js - └── version.txt ----- diff --git a/modules/ROOT/partials/auth/document-converters/jwt-setup-document-converters.adoc b/modules/ROOT/partials/auth/document-converters/jwt-setup-document-converters.adoc new file mode 100644 index 0000000000..907b4cd997 --- /dev/null +++ b/modules/ROOT/partials/auth/document-converters/jwt-setup-document-converters.adoc @@ -0,0 +1,55 @@ +[[setting-up-jwt-authentication]] +== Setting up JWT authentication + +To set up JSON Web Token (JWT) authentication for {productname} {pluginname}: + +. Add a public key to your {accountpage}, link:https://www.tiny.cloud/auth/login/[login]. +. Set up a JSON Web Token (JWT) Provider endpoint via link:{accountjwturl}[{accountpage} - JWT Keys] +. Configure your {productname} to use the JWT endpoint. + +include::partial$auth/private-public-key-pairs-for-tiny-cloud-services.adoc[] + +[[set-up-a-json-web-token-jwt-endpoint]] +== Set up a JSON Web Token (JWT) endpoint + +include::partial$auth/how-jwts-are-used.adoc[] + +=== JWT endpoint requirements + +A JSON Web Token (JWT) endpoint for {pluginname} requires: + +* The endpoint or server accepts a JSON HTTP POST request. +* User authentication - A method of verifying the user, and that they should have access to the {pluginname}. +* The JWTs are generated (signed) using the _private_ key that pairs with the _public_ key provided to link:{accountjwturl}[{accountpage} - JWT Keys]. +* The endpoint or server produces a JSON response with the token. {pluginname} will submit the token with requests to the {pluginname} Server. + +=== Required JWT claims for {pluginname} + +JSON Web Tokens produced by the JWT endpoint must include the following claims: + +`+aud+` _(required)_:: +*Type:* `+String+` ++ +The `aud` is case-sensitive string that must match a valid API key that has the {pluginname} plugin enabled. + +`+iat+` _(required)_:: +*Type:* `+Number+` ++ +The `iat` represents the issue timestamp, specified as the number of seconds. For example, to set the issue time to the current timestamp, calculate the issue time as the current timestamp divided by 1000. + +.Example +[source,json] +---- +iat: Math.floor(Date.now() / 1000), // Issue timestamp +---- + +`+exp+` _(required)_:: +*Type:* `+Number+` ++ +The `exp` represents the expiration timestamp, specified as the number of seconds. For example, to set a validity period of 10 minutes, calculate the expiration time as the current timestamp plus 600 seconds. + +.Example +[source,json] +---- +exp: Math.floor(Date.now() / 1000) + (60 * 10) // Expiration time (10 minutes) +---- \ No newline at end of file diff --git a/modules/ROOT/partials/auth/document-converters/nodejs/configuration-steps.adoc b/modules/ROOT/partials/auth/document-converters/nodejs/configuration-steps.adoc new file mode 100644 index 0000000000..27873853c9 --- /dev/null +++ b/modules/ROOT/partials/auth/document-converters/nodejs/configuration-steps.adoc @@ -0,0 +1,26 @@ +== Configuration Steps + +=== Add Your API Key + +* Replace `YOUR-API-KEY` in both files with your actual {productname} API key +* The API key should be the same in both the HTML script source and the JWT payload + +=== Add Your Private Key + +* Replace the private key placeholder in `jwt.js` with your actual private key +* Make sure it's in `PKCS8` format +* Keep this key secure and never share it publicly + +=== Running Your Project + +. Start the server: ++ +[source,bash] +---- +node jwt.js +---- + +. Open your browser to: `http://localhost:3000` +. You should see: +* The {productname} editor +* An "{pluginname}" button in the toolbar \ No newline at end of file diff --git a/modules/ROOT/partials/auth/document-converters/nodejs/initial-project-setup.adoc b/modules/ROOT/partials/auth/document-converters/nodejs/initial-project-setup.adoc new file mode 100644 index 0000000000..bd630ea569 --- /dev/null +++ b/modules/ROOT/partials/auth/document-converters/nodejs/initial-project-setup.adoc @@ -0,0 +1,39 @@ +== Quick Start Guide + +=== Project Setup + +[source,bash] +---- +# Create and enter project directory +mkdir tinymce-my-app +cd tinymce-my-app + +# Initialize project +npm init -y + +# Install required packages +npm install express cors jsonwebtoken +---- + +Verify that the `package.json` file now includes the required dependencies. + +=== Create Project Structure + +[source,bash] +---- +# Create the public folder for your web files +mkdir public +touch public/index.html +touch jwt.js +---- + +Your project should look like this: + +[source] +---- +/tinymce-my-app + /public + index.html (TinyMCE webpage) + jwt.js (Server code) + package.json (Project configuration) +---- \ No newline at end of file diff --git a/modules/ROOT/partials/auth/document-converters/nodejs/intro-and-prerequisites.adoc b/modules/ROOT/partials/auth/document-converters/nodejs/intro-and-prerequisites.adoc new file mode 100644 index 0000000000..45eadc6e32 --- /dev/null +++ b/modules/ROOT/partials/auth/document-converters/nodejs/intro-and-prerequisites.adoc @@ -0,0 +1,31 @@ +== Introduction + +{pluginname} requires setting up JSON Web Token (JWT) authentication to maintain control over file security. A JWT endpoint generates and provides authorization tokens that verify submitted content is sent by authorized users, preventing unauthorized access. As a standard web services authorization solution, JWT is documented extensively at link:https://jwt.io/[https://jwt.io/]. + +This guide provides a comprehensive walkthrough for integrating {pluginname} with {productname}, including {pluginname} functionality, by using a Node.js server for JWT token generation. It covers project setup, server configuration, and {productname} customization. + +=== What You'll Build + +Before diving into the technical details, here's what you'll achieve with this guide: + +* A working {productname} editor running the {pluginname} plugin +* A secure authentication system using JWT tokens +* A simple Node.js server to handle the authentication + +[TIP] +==== +This guide is designed for developers new to JWT authentication and {productname} integration. +==== + +=== Prerequisites + +Before starting, ensure you have: + +* Node.js installed on your computer (to check, run `node -v` in your terminal) +* A {productname} API key (get one from link:https://www.tiny.cloud/signup[TinyMCE's website]) +* Basic familiarity with the command line + +[IMPORTANT] +==== +Make sure you have your API key ready before starting. You'll need it for both the server and client configuration. +==== \ No newline at end of file diff --git a/modules/ROOT/partials/auth/document-converters/nodejs/server-setup-jwt.adoc b/modules/ROOT/partials/auth/document-converters/nodejs/server-setup-jwt.adoc new file mode 100644 index 0000000000..016553e5f9 --- /dev/null +++ b/modules/ROOT/partials/auth/document-converters/nodejs/server-setup-jwt.adoc @@ -0,0 +1,46 @@ +=== Server Setup (jwt.js) + +In the root directory, copy and paste the server setup code into the `jwt.js` file. + +[source,javascript] +---- +const express = require('express'); // Sets up the web server. +const jwt = require('jsonwebtoken'); // Generates and signs JWTs. +const cors = require('cors'); // Allows cross-origin requests. +const path = require('path'); // Handles file paths. + +const app = express(); +app.use(cors()); + +// Your private key (Replace this with your actual key) +const privateKey = ` +-----BEGIN PRIVATE KEY----- +{Your private PKCS8 key goes here} +-----END PRIVATE KEY----- +`; + +app.use(express.static(path.join(__dirname, 'public'))); + +// JWT token generation endpoint +app.post('/jwt', (req, res) => { + const payload = { + aud: 'YOUR-API-KEY', // Replace with your actual API key + iat: Math.floor(Date.now() / 1000), // Issue timestamp + exp: Math.floor(Date.now() / 1000) + (60 * 10) // Expiration time (10 minutes) + }; + + try { + // Tokens are signed with the RS256 algorithm using your private key + const token = jwt.sign(payload, privateKey, { algorithm: 'RS256' }); + res.json({ token }); + } catch (error) { + res.status(500).send('Failed to generate JWT token.'); + console.error(error.message); + } +}); + +const PORT = 3000; +app.listen(PORT, () => { + console.log(`Server running at http://localhost:${PORT}`); +}); +---- \ No newline at end of file diff --git a/modules/ROOT/partials/auth/document-converters/php/configuration-steps.adoc b/modules/ROOT/partials/auth/document-converters/php/configuration-steps.adoc new file mode 100644 index 0000000000..80142bc569 --- /dev/null +++ b/modules/ROOT/partials/auth/document-converters/php/configuration-steps.adoc @@ -0,0 +1,26 @@ +== Configuration Steps + +=== Add Your API Key + +* Replace `YOUR-API-KEY` in both files with your actual {productname} API key +* The API key should be the same in both the HTML script source and the JWT payload + +=== Add Your Private Key + +* Replace the private key placeholder in `jwt.php` with your actual private key +* Make sure it's in `PKCS8` format +* Keep this key secure and never share it publicly + +=== Running Your Project + +. Start the server: ++ +[source,bash] +---- +php -S localhost:3000 +---- + +. Open your browser to: `http://localhost:3000` +. You should see: +* The {productname} editor +* An "{pluginname}" button in the toolbar \ No newline at end of file diff --git a/modules/ROOT/partials/auth/document-converters/php/initial-project-setup.adoc b/modules/ROOT/partials/auth/document-converters/php/initial-project-setup.adoc new file mode 100644 index 0000000000..5240d90c8b --- /dev/null +++ b/modules/ROOT/partials/auth/document-converters/php/initial-project-setup.adoc @@ -0,0 +1,53 @@ +== Update PHP Configuration File + +Use the following command to locate the PHP configuration file: + +[source,bash] +---- +php --ini +---- + +Open the configuration file in a text editor and ensure the following settings are enabled: + +[source,ini] +---- +extension=openssl +extension_dir='ext' +---- + +[TIP] +The path to the extension directory may vary depending on your system. + +== Quick Start Guide + +=== Project Setup + +[source,bash] +---- +# Create and enter project directory +mkdir tinymce-app +cd tinymce-app +# Initialize Composer +composer require firebase/php-jwt +---- + +=== Create Project Structure + +[source,bash] +---- +# Create the public folder for your web files +touch index.html +touch jwt.php +---- + +Your project should look like this: + +[source] +---- +/tinymce-app + index.html (TinyMCE webpage) + jwt.php (Server code) + composer.json + composer.lock + vendor +---- diff --git a/modules/ROOT/partials/auth/document-converters/php/intro-and-prerequisites.adoc b/modules/ROOT/partials/auth/document-converters/php/intro-and-prerequisites.adoc new file mode 100644 index 0000000000..2319a3d5c0 --- /dev/null +++ b/modules/ROOT/partials/auth/document-converters/php/intro-and-prerequisites.adoc @@ -0,0 +1,33 @@ +== Introduction + +{pluginname} requires setting up JSON Web Token (JWT) authentication to maintain control over file security. A JWT endpoint generates and provides authorization tokens that verify submitted content is sent by authorized users, preventing unauthorized access. As a standard web services authorization solution, JWT is documented extensively at link:https://jwt.io/[https://jwt.io/]. + +This guide provides a comprehensive walkthrough for integrating {pluginname} with {productname}, including {pluginname} functionality, by using a PHP server for JWT token generation. It covers project setup, server configuration, and {productname} customization. + +=== What You'll Build + +Before diving into the technical details, here's what you'll achieve with this guide: + +* A working {productname} editor running the {pluginname} plugin +* A secure authentication system using JWT tokens +* A simple PHP server to handle the authentication + +[TIP] +==== +This guide is designed for developers new to JWT authentication and {productname} integration. +==== + +=== Prerequisites + +Before starting, ensure you have: + +* PHP installed on your computer (to check, run `php -v` in your terminal) +* OpenSSL installed on your computer (to check, run `openssl version` in your terminal) +* Composer installed on your computer (to check, run `composer -v` in your terminal) +* A {productname} API key (get one from link:https://www.tiny.cloud/signup[TinyMCE's website]) +* Basic familiarity with the command line + +[IMPORTANT] +==== +Make sure you have your API key ready before starting. You'll need it for both the server and client configuration. +==== \ No newline at end of file diff --git a/modules/ROOT/partials/auth/document-converters/php/server-setup-php.adoc b/modules/ROOT/partials/auth/document-converters/php/server-setup-php.adoc new file mode 100644 index 0000000000..c19845721e --- /dev/null +++ b/modules/ROOT/partials/auth/document-converters/php/server-setup-php.adoc @@ -0,0 +1,49 @@ +=== Server Setup (jwt.php) + +In the root directory, copy and paste the server setup code into the `jwt.php` file. + +[source,php] +---- + "JWT auth failed: " . $message))); +} + +// Check for OpenSSL extension +if (!extension_loaded('openssl')) { + fatalError('You need to enable the openssl extension in your php.ini.'); +} + +// Enable CORS +header("Access-Control-Allow-Origin: *"); +header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept"); + +// JWT payload +$payload = array( + "aud" => "YOUR-API-KEY", + "iat" => time(), // Issue timestamp + "exp" => time() + 60 * 10 // Expiration time (10 minutes) +); + +try { + // Tokens are signed with the RS256 algorithm your private key + $privateKey = << $token)); +} catch (Exception $e) { + fatalError($e->getMessage()); +} +?> +---- \ No newline at end of file diff --git a/modules/ROOT/partials/auth/private-public-key-pairs-for-tiny-cloud-services.adoc b/modules/ROOT/partials/auth/private-public-key-pairs-for-tiny-cloud-services.adoc index fb6cfa59f6..373aa438bc 100644 --- a/modules/ROOT/partials/auth/private-public-key-pairs-for-tiny-cloud-services.adoc +++ b/modules/ROOT/partials/auth/private-public-key-pairs-for-tiny-cloud-services.adoc @@ -1,4 +1,4 @@ -The {pluginname} Server requires a _public_ key generated from the same _private_ key that will be used on your JSON Web Token (JWT) provider endpoint. The public key(s) stored on the {pluginname} Server are used to ensure that content is sent by authorized users. +The **{pluginname}** Server requires a _public_ key generated from the same _private_ key that will be used on your JSON Web Token (JWT) provider endpoint. The public key(s) stored on the {pluginname} Server are used to ensure that content is sent by authorized users. There are two methods for generating and adding a public key to your API key: @@ -7,7 +7,7 @@ There are two methods for generating and adding a public key to your API key: == Generate a key pair using the {accountpage} JWT Keys page -The link:{accountjwturl}[{accountpage} - JWT Keys] page provides a private/public key generator, providing a quick and secure way of generating the required keys. This generator will store a copy of the _public_ key, and provide a downloadable file for both the public and private keys. {companyname} does not store the _private_ key and the key pair cannot be retrieved later. +The link:{accountjwturl}[{accountpage} - JWT Keys] page provides a private/public key generator, providing a quick and secure way of generating the required keys. This generator will store a copy of the _public_ key, and provide a downloadable file for both the public and private keys. {companyname} does **not store** the _private_ key and the key pair **cannot** be retrieved later. [[generate-a-key-pair-locally]] == Generate a key pair locally diff --git a/modules/ROOT/partials/commands/math-cmds.adoc b/modules/ROOT/partials/commands/math-cmds.adoc new file mode 100644 index 0000000000..db31fc2c0f --- /dev/null +++ b/modules/ROOT/partials/commands/math-cmds.adoc @@ -0,0 +1,11 @@ +[cols="1,3",options="header"] +|=== +|Command |Description +|Math |This command opens the Math dialog. +|=== + +.Examples +[source,js] +---- +tinymce.activeEditor.execCommand('Math'); +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/a11y_advanced_options.adoc b/modules/ROOT/partials/configuration/a11y_advanced_options.adoc index faa0684e1a..de6765c7f7 100644 --- a/modules/ROOT/partials/configuration/a11y_advanced_options.adoc +++ b/modules/ROOT/partials/configuration/a11y_advanced_options.adoc @@ -3,15 +3,20 @@ This option affects the functionality of: -* The Accessibility Checker plugin (`+a11ychecker+`). -* The Image plugin (`+image+`). +* The xref:a11ychecker.adoc[Accessibility Checker] plugin (`+a11ychecker+`). +* The xref:image.adoc[Image] plugin (`+image+`). +* The xref:uploadcare.adoc[Image Optimizer Powered by Uploadcare] plugin (`+uploadcare+`). 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. -IMPORTANT: When `+a11y_advanced_options+` is set to `+true+`, xref:a11ychecker.adoc#a11ychecker_allow_decorative_images[`+a11ychecker_allow_decorative_images+`] will default to `+true+`. +[IMPORTANT] +==== +If `xref:a11ychecker.adoc#a11ychecker_allow_decorative_images[a11ychecker_allow_decorative_images]` is not explicitly set, the value defined in `+a11y_advanced_options+` will be used. +==== *Type:* `+Boolean+` @@ -21,6 +26,20 @@ IMPORTANT: When `+a11y_advanced_options+` is set to `+true+`, xref:a11ychecker.a === Example: using `+a11y_advanced_options+` +ifeval::["{includedSection}" == "uploadcarePlugin"] + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'uploadcare', + toolbar: 'uploadcare', + uploadcare_public_key: '', + a11y_advanced_options: true, +}); +---- + +endif::[] ifeval::["{includedSection}" == "imagePlugin"] [source,js] @@ -29,7 +48,7 @@ tinymce.init({ selector: 'textarea', // change this value according to your HTML plugins: 'image', toolbar: 'image', - a11y_advanced_options: true + a11y_advanced_options: true, }); ---- @@ -42,7 +61,7 @@ tinymce.init({ selector: 'textarea', // change this value according to your HTML plugins: 'a11ychecker', toolbar: 'a11ycheck', - a11y_advanced_options: true + a11y_advanced_options: true, }); ---- @@ -55,7 +74,7 @@ tinymce.init({ selector: 'textarea', // change this value according to your HTML plugins: 'a11ychecker image', toolbar: 'a11ycheck image', - a11y_advanced_options: true + a11y_advanced_options: true, }); ---- diff --git a/modules/ROOT/partials/configuration/a11ychecker_allow_decorative_images.adoc b/modules/ROOT/partials/configuration/a11ychecker_allow_decorative_images.adoc index 4562a11330..1273b98df0 100644 --- a/modules/ROOT/partials/configuration/a11ychecker_allow_decorative_images.adoc +++ b/modules/ROOT/partials/configuration/a11ychecker_allow_decorative_images.adoc @@ -25,7 +25,10 @@ If `+a11ychecker_allow_decorative_images+` is set to `+false+`, the Accessibilit * An image has an empty alternative text attribute. * An image has the `+role="presentation"+` attribute. -NOTE: If xref:a11ychecker.adoc#a11y_advanced_options[`+a11y_advanced_options+`] is set to `+true+`, `+a11ychecker_allow_decorative_images+` will default to `+true+`. +[NOTE] +==== +If `+a11ychecker_allow_decorative_images+` is not explicitly set, the value defined in `xref:a11ychecker.adoc#a11y_advanced_options[a11y_advanced_options]` will be used. +==== *Type:* `+Boolean+` diff --git a/modules/ROOT/partials/configuration/a11ychecker_issue_url_callback.adoc b/modules/ROOT/partials/configuration/a11ychecker_issue_url_callback.adoc index 600cd36b0d..2d8c53af01 100644 --- a/modules/ROOT/partials/configuration/a11ychecker_issue_url_callback.adoc +++ b/modules/ROOT/partials/configuration/a11ychecker_issue_url_callback.adoc @@ -1,7 +1,7 @@ [[a11ychecker_issue_url_callback]] == `+a11ychecker_issue_url_callback+` -The `+a11ychecker_issue_url_callback+` option is used to change the target URL for the "Click for more info" button (image:icons/help.svg[help icon - a question mark inside a circle]) in the Accessibility Checker dialog. By default, the "more info" links will point to `+https://www.tiny.cloud/docs/tinymce/6/a11ychecker/#+`, such as `+https://www.tiny.cloud/docs/tinymce/6/a11ychecker/#D1+`. This option can be used to set the target URL to a page or pages outside {site-url}/. +The `+a11ychecker_issue_url_callback+` option is used to change the target URL for the "Click for more info" button (image:icons/help.svg[help icon - a question mark inside a circle]) in the Accessibility Checker dialog. By default, the "more info" links will point to `+https://www.tiny.cloud/docs/tinymce/7/a11ychecker/#+`, such as `+https://www.tiny.cloud/docs/tinymce/7/a11ychecker/#D1+`. This option can be used to set the target URL to a page or pages outside {site-url}/. *Type:* `+Function+` diff --git a/modules/ROOT/partials/configuration/advcode.adoc b/modules/ROOT/partials/configuration/advcode.adoc index f568c2ef71..3a2847bddb 100644 --- a/modules/ROOT/partials/configuration/advcode.adoc +++ b/modules/ROOT/partials/configuration/advcode.adoc @@ -20,3 +20,65 @@ tinymce.init({ toolbar: 'code', }); ---- + +[[advcode_prettify_getcontent]] +== `+advcode_prettify_getcontent+` + +include::partial$misc/admon-requires-7.3v.adoc[] + +As part of the {productname} 7.3 release, the {pluginname} plugin includes a new option, `advcode_prettify_getcontent`, which is set to `false` by default. + +When this option is set to `true` it will format the HTML code when `editor.getContent` is called. + +This is equivalent to retrieving formatted content by calling `+tinymce.activeEditor.getContent({ prettify: true })+`, regardless of the option's status. + +*Type:* `+Boolean+` + +*Default value:* `+false+` + +*Possible values:* `+true+`, `+false+` + +== Example: basic setup + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'advcode', + advcode_prettify_getcontent: true, + toolbar: 'code', +}); +---- + +[IMPORTANT] +If existing HTML content in the database is not well-formatted or has inconsistent indentation, enabling this option may **change the formatting** of previously saved content which may be undesirable in some cases. + +[[advcode_prettify_editor]] +== `+advcode_prettify_editor+` + +include::partial$misc/admon-requires-7.3v.adoc[] + +As part of the {productname} 7.3 release, the {pluginname} plugin includes a new option, `advcode_prettify_editor`, which is set to `true` by default. + +By default, any code rendered inside **Enhanced Coded Editor** will be formatted with correct indentation. + +Type : `boolean`, + +Default: `+true+` + +*Possible values:* `+true+`, `+false+` + +== Example: basic setup + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'advcode', + advcode_prettify_editor: true, // default value + toolbar: 'code', +}); +---- + +[NOTE] +To disable this default behavior, set the `advcode_prettify_editor` option to `false`. \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/advtemplate_list.adoc b/modules/ROOT/partials/configuration/advtemplate_list.adoc index 1ca1af3167..34148ff307 100644 --- a/modules/ROOT/partials/configuration/advtemplate_list.adoc +++ b/modules/ROOT/partials/configuration/advtemplate_list.adoc @@ -10,7 +10,32 @@ None *Return data:* `+Array+` -=== Example of `advtemplate_list` response +=== Example: using `advtemplate_list` + +[source,js] +---- +tinymce.init({ + selector: 'textarea#advtemplate', // change this value according to your html + plugins: ["advtemplate"], + advtemplate_list: () => + fetch('/categories', { + method: 'GET', + }) + .then((response) => response.json()) + .then((data) => data) + .catch((error) => console.log('Failed to get template list\n' + error)), +}); +---- + +The data returned by `advtemplate_list` must adhere to the following requirements: + +. Each list item must have a unique `id` value. +. Each list item must have a non-empty `title` value. +. Each category item is required to include an `items` sublist, which can be empty. +. Category items must not contain nested subcategories. +. Template item is not required to include a `content` value. + +=== Sample `advtemplate_list` response [source,js] ---- @@ -33,28 +58,3 @@ None } ] ---- - -The data returned by `advtemplate_list` must adhere to the following requirements: - -. Each list item must have a unique `id` value. -. Each list item must have a non-empty `title` value. -. Each category item is required to include an `items` sublist, which can be empty. -. Category items must not contain nested subcategories. -. Template item is not required to include a `content` value. - -=== Example: using `advtemplate_list` - -[source,js] ----- -tinymce.init({ - selector: 'textarea#advtemplate', // change this value according to your html - plugins: ["advtemplate"], - advtemplate_list: () => - fetch('/categories', { - method: 'GET', - }) - .then((response) => response.json()) - .then((data) => data) - .catch((error) => console.log('Failed to get template list\n' + error)), -}); ----- diff --git a/modules/ROOT/partials/configuration/ai_request.adoc b/modules/ROOT/partials/configuration/ai_request.adoc index 4343cfd330..badb897832 100644 --- a/modules/ROOT/partials/configuration/ai_request.adoc +++ b/modules/ROOT/partials/configuration/ai_request.adoc @@ -13,132 +13,50 @@ NOTE: This option is required to use the {pluginname} plugin. *Type:* `+Function+` -=== Example: using `ai_request` and the `stream` callback to interface with the OpenAI Completions API +=== Example: using `ai_request` to interface with the OpenAI Completions API [source,js] ---- -const fetchApi = import("https://unpkg.com/@microsoft/fetch-event-source@2.0.1/lib/esm/index.js").then(module => module.fetchEventSource); - // This example stores the API key in the client side integration. This is not recommended for any purpose. // Instead, an alternate method for retrieving the API key should be used. const api_key = ''; +const ai_request = (request, respondWith) => { + const openAiOptions = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${api_key}` + }, + body: JSON.stringify({ + model: 'gpt-4o', + temperature: 0.7, + max_tokens: 800, + messages: [{ role: 'user', content: request.prompt }], + }) + }; + respondWith.string((signal) => window.fetch('https://api.openai.com/v1/chat/completions', { signal, ...openAiOptions }) + .then(async (response) => { + if (response) { + const data = await response.json(); + if (data.error) { + throw new Error(`${data.error.type}: ${data.error.message}`); + } else if (response.ok) { + // Extract the response content from the data returned by the API + return data?.choices[0]?.message?.content?.trim(); + } + } else { + throw new Error('Failed to communicate with the ChatGPT API'); + } + }) + ); +}; + tinymce.init({ - selector: 'textarea', // change this value according to your html + selector: 'textarea', // Change this value according to your HTML plugins: 'ai', toolbar: 'aidialog aishortcuts', - ai_request: (request, respondWith) => { - respondWith.stream((signal, streamMessage) => { - // Adds each previous query and response as individual messages - const conversation = request.thread.flatMap((event) => { - if (event.response) { - return [ - { role: 'user', content: event.request.query }, - { role: 'assistant', content: event.response.data } - ]; - } else { - return []; - } - }); - - // System messages provided by the plugin to format the output as HTML content. - const pluginSystemMessages = request.system.map((content) => ({ - role: 'system', - content - })); - - const systemMessages = [ - ...pluginSystemMessages, - // Additional system messages to control the output of the AI - { role: 'system', content: 'Remove lines with ``` from the response start and response end.' } - ] - - // Forms the new query sent to the API - const content = request.context.length === 0 || conversation.length > 0 - ? request.query - : `Question: ${request.query} Context: """${request.context}"""`; - - const messages = [ - ...conversation, - ...systemMessages, - { role: 'user', content } - ]; - - const requestBody = { - model: 'gpt-3.5-turbo', - temperature: 0.7, - max_tokens: 800, - messages, - stream: true - }; - - const openAiOptions = { - signal, - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${api_key}` - }, - body: JSON.stringify(requestBody) - }; - - const onopen = async (response) => { - if (response) { - const contentType = response.headers.get('content-type'); - if (response.ok && contentType?.includes('text/event-stream')) { - return; - } else if (contentType?.includes('application/json')) { - const data = await response.json(); - if (data.error) { - throw new Error(`${data.error.type}: ${data.error.message}`); - } - } - } else { - throw new Error('Failed to communicate with the ChatGPT API'); - } - }; - - // This function passes each new message into the plugin via the `streamMessage` callback. - const onmessage = (ev) => { - const data = ev.data; - if (data !== '[DONE]') { - const parsedData = JSON.parse(data); - const firstChoice = parsedData?.choices[0]; - const message = firstChoice?.delta?.content; - if (message) { - streamMessage(message); - } - } - }; - - const onerror = (error) => { - // Stop operation and do not retry by the fetch-event-source - throw error; - }; - - // Use microsoft's fetch-event-source library to work around the 2000 character limit - // of the browser `EventSource` API, which requires query strings - return fetchApi - .then(fetchEventSource => - fetchEventSource('https://api.openai.com/v1/chat/completions', { - ...openAiOptions, - openWhenHidden: true, - onopen, - onmessage, - onerror - }) - ) - .then(async (response) => { - if (response && !response.ok) { - const data = await response.json(); - if (data.error) { - throw new Error(`${data.error.type}: ${data.error.message}`); - } - } - }) - .catch(onerror); - }); - } + ai_request }); ---- diff --git a/modules/ROOT/partials/configuration/ai_shortcuts.adoc b/modules/ROOT/partials/configuration/ai_shortcuts.adoc index 44a48cd4ae..c3fdc64ac1 100644 --- a/modules/ROOT/partials/configuration/ai_shortcuts.adoc +++ b/modules/ROOT/partials/configuration/ai_shortcuts.adoc @@ -24,20 +24,41 @@ When configured with an instance-specific object array, the {pluginname} shortcu { title: 'Simplify language', prompt: 'Rewrite this content with simplified language and reduce the complexity of the writing, so that the content is easier to understand.', selection: true }, { title: 'Expand upon', prompt: 'Expand upon this content with descriptive language and more detailed explanations, to make the writing easier to understand and increase the length of the content.', selection: true }, { title: 'Trim content', prompt: 'Remove any repetitive, redundant, or non-essential writing in this content without changing the meaning or losing any key information.', selection: true }, - { title: 'Change tone', subprompts: [ - { title: 'Professional', prompt: 'Rewrite this content using polished, formal, and respectful language to convey professional expertise and competence.', selection: true }, - { title: 'Casual', prompt: 'Rewrite this content with casual, informal language to convey a casual conversation with a real person.', selection: true }, - { title: 'Direct', prompt: 'Rewrite this content with direct language using only the essential information.', selection: true }, - { title: 'Confident', prompt: 'Rewrite this content using compelling, optimistic language to convey confidence in the writing.', selection: true }, - { title: 'Friendly', prompt: 'Rewrite this content using friendly, comforting language, to convey understanding and empathy.', selection: true }, - ] }, - { title: 'Change style', subprompts: [ - { title: 'Business', prompt: 'Rewrite this content as a business professional with formal language.', selection: true }, - { title: 'Legal', prompt: 'Rewrite this content as a legal professional using valid legal terminology.', selection: true }, - { title: 'Journalism', prompt: 'Rewrite this content as a journalist using engaging language to convey the importance of the information.', selection: true }, - { title: 'Medical', prompt: 'Rewrite this content as a medical professional using valid medical terminology.', selection: true }, - { title: 'Poetic', prompt: 'Rewrite this content as a poem using poetic techniques without losing the original meaning.', selection: true }, - ] } + { + title: 'Change tone', subprompts: [ + { title: 'Professional', prompt: 'Rewrite this content using polished, formal, and respectful language to convey professional expertise and competence.', selection: true }, + { title: 'Casual', prompt: 'Rewrite this content with casual, informal language to convey a casual conversation with a real person.', selection: true }, + { title: 'Direct', prompt: 'Rewrite this content with direct language using only the essential information.', selection: true }, + { title: 'Confident', prompt: 'Rewrite this content using compelling, optimistic language to convey confidence in the writing.', selection: true }, + { title: 'Friendly', prompt: 'Rewrite this content using friendly, comforting language, to convey understanding and empathy.', selection: true }, + ] + }, + { + title: 'Change style', subprompts: [ + { title: 'Business', prompt: 'Rewrite this content as a business professional with formal language.', selection: true }, + { title: 'Legal', prompt: 'Rewrite this content as a legal professional using valid legal terminology.', selection: true }, + { title: 'Journalism', prompt: 'Rewrite this content as a journalist using engaging language to convey the importance of the information.', selection: true }, + { title: 'Medical', prompt: 'Rewrite this content as a medical professional using valid medical terminology.', selection: true }, + { title: 'Poetic', prompt: 'Rewrite this content as a poem using poetic techniques without losing the original meaning.', selection: true }, + ] + }, + { + title: 'Translate', subprompts: [ + { title: 'Translate to English', prompt: 'Translate this content to English language.', selection: true }, + { title: 'Translate to Spanish', prompt: 'Translate this content to Spanish language.', selection: true }, + { title: 'Translate to Portuguese', prompt: 'Translate this content to Portuguese language.', selection: true }, + { title: 'Translate to German', prompt: 'Translate this content to German language.', selection: true }, + { title: 'Translate to French', prompt: 'Translate this content to French language.', selection: true }, + { title: 'Translate to Norwegian', prompt: 'Translate this content to Norwegian language.', selection: true }, + { title: 'Translate to Ukrainian', prompt: 'Translate this content to Ukrainian language.', selection: true }, + { title: 'Translate to Japanese', prompt: 'Translate this content to Japanese language.', selection: true }, + { title: 'Translate to Korean', prompt: 'Translate this content to Korean language.', selection: true }, + { title: 'Translate to Simplified Chinese', prompt: 'Translate this content to Simplified Chinese language.', selection: true }, + { title: 'Translate to Hebrew', prompt: 'Translate this content to Hebrew language.', selection: true }, + { title: 'Translate to Hindi', prompt: 'Translate this content to Hindi language.', selection: true }, + { title: 'Translate to Arabic', prompt: 'Translate this content to Arabic language.', selection: true }, + ] + }, ] ---- @@ -49,7 +70,7 @@ The default {pluginname} shortcuts are only available in English. They have not Also, the default {pluginname} shortcuts are subject to change. If you prefer to keep these shortcuts, include them within your integration. ==== -=== Example: using `ai_shortcuts` to present a customised set of {pluginname} shortcuts +=== Example: using `ai_shortcuts` to present a customized set of {pluginname} shortcuts [source,js] ---- diff --git a/modules/ROOT/partials/configuration/allow_mathml_annotation_encodings.adoc b/modules/ROOT/partials/configuration/allow_mathml_annotation_encodings.adoc new file mode 100644 index 0000000000..13cbd55551 --- /dev/null +++ b/modules/ROOT/partials/configuration/allow_mathml_annotation_encodings.adoc @@ -0,0 +1,18 @@ +[[allow-mathml-annotation-encodings]] +== `+allow_mathml_annotation_encodings+` + +This option allows a specific list of valid MathML annotation encodings to be used in the editor. + +*Type:* `+Array+` of `+Strings+` + +*Default value:* `+[]+` (empty array) + +=== Example: using `+allow_mathml_annotation_encodings+` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + allow_mathml_annotation_encodings: [ 'wiris', 'application/x-tex' ] +}); +---- diff --git a/modules/ROOT/partials/configuration/comments-tinycomments_access.adoc b/modules/ROOT/partials/configuration/comments-tinycomments_access.adoc new file mode 100644 index 0000000000..d21ae722a2 --- /dev/null +++ b/modules/ROOT/partials/configuration/comments-tinycomments_access.adoc @@ -0,0 +1,55 @@ +[[tinycomments-access]] +== `tinycomments_access` + +*Type:* `+String+` + +*Possible values:* `'comment'` + +This option sets the editor to the readonly mode, while still allowing comments to be made. + +[IMPORTANT] +==== +* When `tinycomments_access` is set to `comment`, the editor will automatically switch to xref:editor-important-options.adoc#readonly[Readonly Mode]. +==== + +=== Comments with `tinycomments_access` set to `'comment'` + +When `tinycomments_access` is set to `comment`, the editor will be in xref:editor-important-options.adoc#readonly[Readonly mode], but the comments will be in a **comment-only** mode. This means that users can add and delete comments, but they cannot edit the editor content. + + +.Example +[source,javascript] +---- +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'tinycomments', + tinycomments_mode: 'embedded', + toolbar: 'addcomment showcomments', + tinycomments_access: 'comment' +}); +---- + +liveDemo::comments-ui-mode[] + +=== Comments with `readonly` set to `true` + +When not using the `tinycomments_access` option, the comments sidebar will have a different state depending on the use of the xref:editor-important-options.adoc#readonly[`readonly` option]. + +With neither xref:editor-important-options.adoc#readonly[Readonly mode] nor `tinycomments: "comment"` configured, both the editor and the comments sidebar will be in their default state. By default, comments can be both viewed and added, and the editor content is editable. + +With xref:editor-important-options.adoc#readonly[Readonly mode] enabled, the comments sidebar will be in a **view-only** mode, meaning all comments can be viewed and navigated, but no new comments can be added. Also, in the **readonly** state, the editor will still not be editable. + + +.Example +[source,javascript] +---- +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'tinycomments', + tinycomments_mode: 'embedded', + toolbar: 'addcomment showcomments', + readonly: true, // set the editor to read-only mode +}); +---- + +liveDemo::comments-readonly-mode[] \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/defaultmenuitems.adoc b/modules/ROOT/partials/configuration/defaultmenuitems.adoc index f9baee5a60..dd2c811ce9 100644 --- a/modules/ROOT/partials/configuration/defaultmenuitems.adoc +++ b/modules/ROOT/partials/configuration/defaultmenuitems.adoc @@ -6,7 +6,7 @@ tinymce.init({ file: { title: 'File', items: 'newdocument restoredraft | preview | importword exportpdf exportword | print | deleteallconversations' }, edit: { title: 'Edit', items: 'undo redo | cut copy paste pastetext | selectall | searchreplace' }, view: { title: 'View', items: 'code revisionhistory | visualaid visualchars visualblocks | spellchecker | preview fullscreen | showcomments' }, - insert: { title: 'Insert', items: 'image link media addcomment pageembed codesample inserttable | charmap emoticons hr | pagebreak nonbreaking anchor tableofcontents | insertdatetime' }, + insert: { title: 'Insert', items: 'image link media addcomment pageembed codesample inserttable | math | charmap emoticons hr | pagebreak nonbreaking anchor tableofcontents | insertdatetime' }, format: { title: 'Format', items: 'bold italic underline strikethrough superscript subscript codeformat | styles blocks fontfamily fontsize align lineheight | forecolor backcolor | language | removeformat' }, tools: { title: 'Tools', items: 'spellchecker spellcheckerlanguage | a11ycheck code wordcount' }, table: { title: 'Table', items: 'inserttable | cell row column | advtablesort | tableprops deletetable' }, diff --git a/modules/ROOT/partials/configuration/disabled.adoc b/modules/ROOT/partials/configuration/disabled.adoc new file mode 100644 index 0000000000..c54b4cf306 --- /dev/null +++ b/modules/ROOT/partials/configuration/disabled.adoc @@ -0,0 +1,23 @@ +[[disabled]] + +== `+disabled+` + +Disables all user interactions with the editor (including cursor placement, content modifications, UI components). This option provides behavior similar to the changes made to {productname} in 7.4.0 readonly mode. When enabled, the editor becomes completely non-interactive. + +To programmatically enable/disable the editor, use `+tinymce.activeEditor.options.set('disabled', false/true)+`. + +*Type:* `+Boolean+` + +*Default value:* `+false+` + +*Possible values:* `+true+`, `+false+` + +=== Example: using `+disabled+` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + disabled: true +}); +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/emoticons_images_url.adoc b/modules/ROOT/partials/configuration/emoticons_images_url.adoc index 91c79c0cba..9fed184349 100644 --- a/modules/ROOT/partials/configuration/emoticons_images_url.adoc +++ b/modules/ROOT/partials/configuration/emoticons_images_url.adoc @@ -3,11 +3,11 @@ This option sets the base URL for the images used to represent emojis when using the `+emojiimages+` database. -By default, this option loads the required image _assets_ from the Twemoji CDN. To use self-hosted emoji images, download the image _assets_ from the https://github.com/twitter/twemoji/#download[Twitter Emoji (twemoji) GitHub repository]. +By default, this option loads the required image _assets_ from the Twemoji CDN. To use self-hosted emoji images, download the image _assets_ from the https://github.com/jdecked/twemoji/#download[Twitter Emoji (Twemoji) GitHub repository]. *Type:* `+String+` -*Default value:* `+'https://twemoji.maxcdn.com/v/13.0.1/72x72/'+` +*Default value:* `+'https://cdnjs.cloudflare.com/ajax/libs/twemoji/15.1.0/72x72/'+` === Example: using `+emoticons_images_url+` diff --git a/modules/ROOT/partials/configuration/exportpdf.adoc b/modules/ROOT/partials/configuration/exportpdf.adoc deleted file mode 100644 index 981c7e1198..0000000000 --- a/modules/ROOT/partials/configuration/exportpdf.adoc +++ /dev/null @@ -1,80 +0,0 @@ -[[exportpdf-service-url]] -== `exportpdf_service_url` - -The {pluginname} uses the {productname} Cloud Services HTML to PDF converter service to generate the `document-name.pdf` files. - -NOTE: The {pluginname} feature is currently only available `on-premise` and requires the `exportpdf_service_url` option to be configured. https://www.tiny.cloud/contact/[Contact us] if you require this feature. - -*Type:* `+String+` - -=== Example: using `exportpdf_service_url` - -[source,js] ----- -tinymce.init({ - selector: 'textarea', - plugins: 'exportpdf', - toolbar: 'exportpdf', - exportpdf_service_url: '' -}); ----- - -[[exportpdf-converter-options]] -== `exportpdf_converter_options` - -This option allows the editor to download a PDF document containing its content, along with the specified options defined in the `exportpdf_converter_options`. - -*Type:* `+Object+` - -*Default value:* `{}` - -=== Example: using `exportpdf_converter_options` - -[source,js] ----- -tinymce.init({ - selector: 'textarea', - plugins: 'exportpdf', - toolbar: 'exportpdf', - exportpdf_service_url: '', - exportpdf_converter_options: { - header_html: '

    HEADER

    ', // example - header_and_footer_css: 'p { color: blue }', // example - }, -}) ----- - -[NOTE] -The `exportpdf_service_url` option must be configured for the {pluginname} plugin to work. - -> For comprehensive details regarding the `exportpdf_converter_options`, please refer to the https://exportpdf.converter.tiny.cloud/docs[API documentation^] available for the {pluginname} Premium plugin. - -[[exportpdf-converter-style]] -== `exportpdf_converter_style` - -The `exportpdf_converter_style` option allow for customization of the styles applied to the exported PDF document, providing flexibility in controlling its appearance. - -*Type:* `+String+` - -*Default value:* `''` - -=== Example: using `exportpdf_converter_style` - -[source,js] ----- -tinymce.init({ - selector: 'textarea.tinymce', - plugins: 'exportpdf', - toolbar: 'exportpdf', - exportpdf_service_url: '', // required - exportpdf_converter_options: { // required to support "exportpdf_converter_style" - header: [ - { - html: '

    First page header.

    ', //example - css: 'h1 { font-size: 30px; }', //example - } - ], - }, - exportpdf_converter_style: 'p { color: cyan !important }' // requires both "exportpdf_converter_style" and "exportpdf_service_url" to be set. -}); ----- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/exportpdf_converter_options.adoc b/modules/ROOT/partials/configuration/exportpdf_converter_options.adoc new file mode 100644 index 0000000000..806eea7d6b --- /dev/null +++ b/modules/ROOT/partials/configuration/exportpdf_converter_options.adoc @@ -0,0 +1,42 @@ +[[exportpdf-converter-options]] +== `exportpdf_converter_options` + +This option allows the editor to download a PDF document containing its content, along with the specified options defined in the `exportpdf_converter_options`. + +**Type:** `+Object+` + +[NOTE] +As of {productname} 7.5.0, the `exportpdf_converter_options` setting now comes with a default value set to the following: + +.**Default value:** +[source,js] +---- +{ + format: 'Letter', + margin_top: '1in', + margin_right: '1in', + margin_bottom: '1in', + margin_left: '1in' +} +---- + +=== Example: using `exportpdf_converter_options` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'exportpdf', + toolbar: 'exportpdf', + exportpdf_service_url: '', // required if using On-premises service + exportpdf_converter_options: { + header_html: '

    HEADER

    ', // example + header_and_footer_css: 'p { color: blue }', // example + }, +}) +---- + +[NOTE] +The `exportpdf_service_url` option must be configured for the {pluginname} plugin to work. + +> For comprehensive details regarding the `exportpdf_converter_options`, please refer to the https://exportpdf.api.tiny.cloud/docs[API documentation^] available for the {pluginname} Premium plugin. \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/exportpdf_converter_style.adoc b/modules/ROOT/partials/configuration/exportpdf_converter_style.adoc new file mode 100644 index 0000000000..c71f611982 --- /dev/null +++ b/modules/ROOT/partials/configuration/exportpdf_converter_style.adoc @@ -0,0 +1,29 @@ +[[exportpdf-converter-style]] +== `exportpdf_converter_style` + +The `exportpdf_converter_style` option allow for customization of the styles applied to the exported PDF document, providing flexibility in controlling its appearance. + +*Type:* `+String+` + +*Default value:* `''` + +=== Example: using `exportpdf_converter_style` + +[source,js] +---- +tinymce.init({ + selector: 'textarea.tinymce', + plugins: 'exportpdf', + toolbar: 'exportpdf', + exportpdf_service_url: '', // required if using On-premises service + exportpdf_converter_options: { // required to support "exportpdf_converter_style" + header: [ + { + html: '

    First page header.

    ', //example + css: 'h1 { font-size: 30px; }', //example + } + ], + }, + exportpdf_converter_style: 'p { color: cyan !important }' // requires both "exportpdf_converter_style" and "exportpdf_service_url" to be set. +}); +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/exportpdf_service_url.adoc b/modules/ROOT/partials/configuration/exportpdf_service_url.adoc new file mode 100644 index 0000000000..1348e22c2b --- /dev/null +++ b/modules/ROOT/partials/configuration/exportpdf_service_url.adoc @@ -0,0 +1,23 @@ +[[exportpdf-service-url]] +== `exportpdf_service_url` + +The {pluginname} plugin uses an HTML-to-PDF converter service to generate `document-name.pdf` files. + +This option is **required** when configuring the {pluginname} plugin for `on-premise` setups. If you require access to this feature, please link:https://www.tiny.cloud/contact/[contact us]. For detailed instructions on deploying the {pluginname} service server-side component using Docker, refer to the xref:individual-export-to-pdf-on-premises.adoc[on-premises documentation]. + +[TIP] +When using a custom host, set the `exportpdf_service_url` option in your {productname} configuration to match your host. For example, if your custom host is `mycustomhost.com`, set the URL to `https://mycustomhost.com/`. + +*Type:* `+String+` + +=== Example: Setting up `exportpdf_service_url` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'exportpdf', + toolbar: 'exportpdf', + exportpdf_service_url: '' // required for On-premise setups only +}); +---- diff --git a/modules/ROOT/partials/configuration/exportpdf_token_provider.adoc b/modules/ROOT/partials/configuration/exportpdf_token_provider.adoc new file mode 100644 index 0000000000..4f4077a310 --- /dev/null +++ b/modules/ROOT/partials/configuration/exportpdf_token_provider.adoc @@ -0,0 +1,31 @@ +[[exportpdf-token-provider]] +== `exportpdf_token_provider` + +The `exportpdf_token_provider` option enables integration with a token-based authentication service for exporting PDF documents. It provides a mechanism to fetch an authentication token from a specified endpoint. This ensures that the export process can securely communicate with the server. + +*Type:* `+Function+` + +*Default value:* `undefined` + +=== Example: using `exportpdf_token_provider` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'exportpdf', + toolbar: 'exportpdf', + exportpdf_token_provider: () => { + return fetch('http://localhost:3000/jwt', { // specify your token endpoint + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }).then(response => response.json()); + }, +}); +---- + +[NOTE] +The `exportpdf_token_provider` option is required when using the {companyname} Cloud service. For more information on how to set up JWT authentication with {pluginname}, see examples: + +* xref:export-to-pdf-with-jwt-authentication-nodejs.adoc[Export to PDF with JWT authentication (Node.js)] +* xref:export-to-pdf-with-jwt-authentication-php.adoc[Export to PDF with JWT authentication (PHP)] \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/exportword.adoc b/modules/ROOT/partials/configuration/exportword.adoc deleted file mode 100644 index 23a6163a7f..0000000000 --- a/modules/ROOT/partials/configuration/exportword.adoc +++ /dev/null @@ -1,84 +0,0 @@ -[[exportword-service-url]] -== `exportword_service_url` - -The {pluginname} uses the {productname} Cloud Services HTML to DOCX converter service to generate the Word files. - -NOTE: The {pluginname} feature is currently only available `on-premise` and requires the `exportword_service_url` option to be configured. https://www.tiny.cloud/contact/[Contact us] if you require this feature. - -*Type:* `+String+` - -=== Example: using `exportword_service_url` - -[source,js] ----- -tinymce.init({ - selector: 'textarea', - plugins: 'exportword', - toolbar: 'exportword', - exportword_service_url: '' -}); ----- - -[[exportword-converter-options]] -== `exportword_converter_options` - -The `exportword_converter_options` option, is used to specify and configure various options related to the process of converting and exporting content from the editor to `.docx` Word file. - -*Type:* `+Object+` - -*Default value:* `{}` - -=== Example: using `exportword_converter_options` - -[source,js] ----- -tinymce.init({ - selector: 'textarea', - plugins: 'exportword', - toolbar: 'exportword', - exportword_service_url: '', - exportword_converter_options: { - header: [ - { - html: '

    First page header.

    ', //example - css: 'h1 { font-size: 30px; }', //example - } - ], - }, -}); ----- - -[NOTE] -To use this option, the Export to Word plugin requires the `exportword_service_url` option to be configured. - -> For comprehensive details regarding the `exportword_converter_options`, please refer to the https://exportdocx.converter.tiny.cloud/docs#section/Export-to-Word[API documentation^] available for the {pluginname} Premium plugin. - -[[exportword-converter-style]] -== `exportword_converter_style` - -The `exportword_converter_style` option allow for customization of the styles applied to the exported Word document, providing flexibility in controlling its appearance. - -*Type:* `+String+` - -*Default value:* `''` - -=== Example: using `exportword_converter_style` - -[source,js] ----- -tinymce.init({ - selector: 'textarea.tinymce', - plugins: 'exportword', - toolbar: 'exportword', - exportword_service_url: '', // required - exportword_converter_options: { // required to support "exportword_converter_style" - header: [ - { - html: '

    First page header.

    ', //example - css: 'h1 { font-size: 30px; }', //example - } - ], - }, - exportword_converter_style: 'p { color: cyan !important }' -}); ----- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/exportword_converter_options.adoc b/modules/ROOT/partials/configuration/exportword_converter_options.adoc new file mode 100644 index 0000000000..9ca4223cad --- /dev/null +++ b/modules/ROOT/partials/configuration/exportword_converter_options.adoc @@ -0,0 +1,68 @@ +[[exportword-converter-options]] +== `exportword_converter_options` + +The `exportword_converter_options` option, is used to specify and configure various options related to the process of converting and exporting content from the editor to `.docx` Word file. + +**Type:** `+Object+` + +[NOTE] +As of {productname} 7.5.0, the default value of the `exportword_converter_options` setting has been updated to the following: + +.**Default value:** +[source,js] +---- +exportword_converter_options: { + document: { + size: 'letter' + } +} +---- + +=== Example: using `exportword_converter_options` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'exportword', + toolbar: 'exportword', + exportword_service_url: '', // required if using On-premises service + exportword_converter_options: { + headers: { + first: { + html: "

    My document header

    ", + css: "p { color: gray; }" + }, + default: { + html: "

    My default header

    ", + css: "p { color: blue; }" + } + }, + footers: { + odd: { + html: "

    My odd footer

    ", + css: "p { font-size: 10px; }" + }, + even: { + html: "

    My even footer

    ", + css: "p { font-size: 12px; }" + } + }, + document: { + orientation: "landscape", + size: "a3", + margins: { + top: "10mm", + bottom: "10mm", + left: "20mm", + right: "15mm" + } + }, + }, +}); +---- + +[NOTE] +To use this option, the Export to Word plugin requires the `exportword_service_url` option to be configured. + +> For comprehensive details regarding the `exportword_converter_options`, please refer to the link:https://exportdocx.api.tiny.cloud/v2/convert/docs#section/Export-to-Word[API documentation^] available for the {pluginname} Premium plugin. diff --git a/modules/ROOT/partials/configuration/exportword_converter_style.adoc b/modules/ROOT/partials/configuration/exportword_converter_style.adoc new file mode 100644 index 0000000000..adde763c35 --- /dev/null +++ b/modules/ROOT/partials/configuration/exportword_converter_style.adoc @@ -0,0 +1,33 @@ +[[exportword-converter-style]] +== `exportword_converter_style` + +The `exportword_converter_style` option allows for customization of the styles applied to the exported Word document, providing flexibility in controlling its appearance; however, this option does **not affect** the distinct styling of the `header` and `footer`. + +*Type:* `+String+` + +*Default value:* `''` + +=== Example: using `exportword_converter_style` + +[source,js] +---- +tinymce.init({ + selector: 'textarea.tinymce', + plugins: 'exportword', + toolbar: 'exportword', + exportword_service_url: '', // required if using On-premises service + exportword_converter_options: { + headers: { + first: { + html: "

    My document header

    ", + css: "p { color: gray; }" + }, + default: { + html: "

    My default header

    ", + css: "p { color: blue; }" + } + }, + }, + exportword_converter_style: 'p { color: cyan !important }' // will override the set

    tag styles in the HTML content +}); +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/exportword_service_url.adoc b/modules/ROOT/partials/configuration/exportword_service_url.adoc new file mode 100644 index 0000000000..3e78553598 --- /dev/null +++ b/modules/ROOT/partials/configuration/exportword_service_url.adoc @@ -0,0 +1,23 @@ +[[exportword-service-url]] +== `exportword_service_url` + +The {pluginname} plugin uses an HTML-to-DOCX converter service to generate Word files. + +This option is **required** when configuring the {pluginname} plugin for `on-premise` setups. If you require access to this feature, please link:https://www.tiny.cloud/contact/[contact us]. For detailed instructions on deploying the {pluginname} service server-side component using Docker, refer to the xref:individual-import-from-word-and-export-to-word-on-premises.adoc[on-premises documentation]. + +[TIP] +When using a custom host, set the `exportword_service_url` option in your {productname} configuration to match your host. For example, if your custom host is `mycustomhost.com`, set the URL to `https://mycustomhost.com/`. + +*Type:* `+String+` + +=== Example: Setting up `exportword_service_url` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'exportword', + toolbar: 'exportword', + exportword_service_url: '' // required for On-premise setups only +}); +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/exportword_token_provider.adoc b/modules/ROOT/partials/configuration/exportword_token_provider.adoc new file mode 100644 index 0000000000..0638af7164 --- /dev/null +++ b/modules/ROOT/partials/configuration/exportword_token_provider.adoc @@ -0,0 +1,32 @@ +[[exportword-token-provider]] +== `exportword_token_provider` + +The `exportword_token_provider` option enables integration with a token-based authentication service for exporting Word documents. It provides a mechanism to fetch an authentication token from a specified endpoint. This ensures that the export process can securely communicate with the server. + +*Type:* `+Function+` + +*Default value:* `undefined` + +=== Example: using `exportword_token_provider` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'exportword', + toolbar: 'exportword', + exportword_token_provider: () => { + return fetch('http://localhost:3000/jwt', { // specify your token endpoint + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }).then(response => response.json()); + }, +}); +---- + + +[NOTE] +The `exportword_token_provider` option is required when using the {companyname} Cloud service. For more information on how to set up JWT authentication with {pluginname}, see examples: + +* xref:export-to-word-with-jwt-authentication-nodejs.adoc[Export to Word with JWT authentication (Node.js)] +* xref:export-to-word-with-jwt-authentication-php.adoc[Export to Word with JWT authentication (PHP)] \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/force_hex_color.adoc b/modules/ROOT/partials/configuration/force_hex_color.adoc deleted file mode 100644 index b46ab9677a..0000000000 --- a/modules/ROOT/partials/configuration/force_hex_color.adoc +++ /dev/null @@ -1,25 +0,0 @@ -[[force_hex_color]] -== `+force_hex_color+` - -This option allows the integrator to optionally force the conversion of either RGB or RGBA colors into HEX colors. - -*Type:* `+String+` - -*Default value:* `+'off'+` - -*Possible values:* `+'always'+`, `+'rgb_only'+`, `+'off'+` - -=== Example: using `+force_hex_color+` - -[source,js] ----- -// Output elements in XHTML style -tinymce.init({ - selector: 'textarea', // change this value according to your HTML - force_hex_color: 'always' -}); ----- - -* **force_hex_color: 'always'**: all colors are converted and applied as HEX format. -* **force_hex_color: 'rgb_only'**: only RGB and not RGBA colors are converted and applied as HEX. -* **force_hex_color: 'off'**: (default option) no conversion to hex is applied, and they are left as their input format. \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/icon_list.adoc b/modules/ROOT/partials/configuration/icon_list.adoc index 17270ee9d3..d656230b70 100644 --- a/modules/ROOT/partials/configuration/icon_list.adoc +++ b/modules/ROOT/partials/configuration/icon_list.adoc @@ -6,7 +6,9 @@ | `+accordion+` | image:icons/accordion.svg[accordion.svg] | `+accordion.svg+` | `+action-next+` | image:icons/action-next.svg[action-next.svg] | `+action-next.svg+` | `+action-prev+` | image:icons/action-prev.svg[action-prev.svg] | `+action-prev.svg+` +| `+add-file+` | image:icons/add-file.svg[add-file.svg] | `+add-file.svg+` | `+addtag+` | image:icons/addtag.svg[addtag.svg] | `+addtag.svg+` +| `+adjustments+` | image:icons/adjustments.svg[adjustments.svg] | `+adjustments.svg+` | `+ai-prompt+` | image:icons/ai-prompt.svg[ai-prompt.svg] | `+ai-prompt.svg+` | `+ai+` | image:icons/ai.svg[ai.svg] | `+ai.svg+` | `+align-center+` | image:icons/align-center.svg[align-center.svg] | `+align-center.svg+` @@ -14,15 +16,20 @@ | `+align-left+` | image:icons/align-left.svg[align-left.svg] | `+align-left.svg+` | `+align-none+` | image:icons/align-none.svg[align-none.svg] | `+align-none.svg+` | `+align-right+` | image:icons/align-right.svg[align-right.svg] | `+align-right.svg+` +| `+alt-text+` | image:icons/alt-text.svg[alt-text.svg] | `+alt-text.svg+` | `+arrow-left+` | image:icons/arrow-left.svg[arrow-left.svg] | `+arrow-left.svg+` | `+arrow-right+` | image:icons/arrow-right.svg[arrow-right.svg] | `+arrow-right.svg+` +| `+blur+` | image:icons/blur.svg[blur.svg] | `+blur.svg+` | `+bold+` | image:icons/bold.svg[bold.svg] | `+bold.svg+` | `+bookmark+` | image:icons/bookmark.svg[bookmark.svg] | `+bookmark.svg+` | `+border-style+` | image:icons/border-style.svg[border-style.svg] | `+border-style.svg+` | `+border-width+` | image:icons/border-width.svg[border-width.svg] | `+border-width.svg+` +| `+box+` | image:icons/box.svg[box.svg] | `+box.svg+` | `+brightness+` | image:icons/brightness.svg[brightness.svg] | `+brightness.svg+` | `+browse+` | image:icons/browse.svg[browse.svg] | `+browse.svg+` +| `+camera+` | image:icons/camera.svg[camera.svg] | `+camera.svg+` | `+cancel+` | image:icons/cancel.svg[cancel.svg] | `+cancel.svg+` +| `+caption+` | image:icons/caption.svg[caption.svg] | `+caption.svg+` | `+cell-background-color+` | image:icons/cell-background-color.svg[cell-background-color.svg] | `+cell-background-color.svg+` | `+cell-border-color+` | image:icons/cell-border-color.svg[cell-border-color.svg] | `+cell-border-color.svg+` | `+change-case+` | image:icons/change-case.svg[change-case.svg] | `+change-case.svg+` @@ -50,6 +57,7 @@ | `+cut+` | image:icons/cut.svg[cut.svg] | `+cut.svg+` | `+document-properties+` | image:icons/document-properties.svg[document-properties.svg] | `+document-properties.svg+` | `+drag+` | image:icons/drag.svg[drag.svg] | `+drag.svg+` +| `+dropbox+` | image:icons/dropbox.svg[dropbox.svg] | `+dropbox.svg+` | `+duplicate-column+` | image:icons/duplicate-column.svg[duplicate-column.svg] | `+duplicate-column.svg+` | `+duplicate-row+` | image:icons/duplicate-row.svg[duplicate-row.svg] | `+duplicate-row.svg+` | `+duplicate+` | image:icons/duplicate.svg[duplicate.svg] | `+duplicate.svg+` @@ -58,21 +66,33 @@ | `+embed-page+` | image:icons/embed-page.svg[embed-page.svg] | `+embed-page.svg+` | `+embed+` | image:icons/embed.svg[embed.svg] | `+embed.svg+` | `+emoji+` | image:icons/emoji.svg[emoji.svg] | `+emoji.svg+` +| `+evernote+` | image:icons/evernote.svg[evernote.svg] | `+evernote.svg+` | `+export-pdf+` | image:icons/export-pdf.svg[export-pdf.svg] | `+export-pdf.svg+` | `+export-word+` | image:icons/export-word.svg[export-word.svg] | `+export-word.svg+` +| `+exposure+` | image:icons/exposure.svg[exposure.svg] | `+exposure.svg+` +| `+fb+` | image:icons/fb.svg[fb.svg] | `+fb.svg+` | `+fill+` | image:icons/fill.svg[fill.svg] | `+fill.svg+` +| `+flickr+` | image:icons/flickr.svg[flickr.svg] | `+flickr.svg+` | `+flip-horizontally+` | image:icons/flip-horizontally.svg[flip-horizontally.svg] | `+flip-horizontally.svg+` | `+flip-vertically+` | image:icons/flip-vertically.svg[flip-vertically.svg] | `+flip-vertically.svg+` +| `+folder+` | image:icons/folder.svg[folder.svg] | `+folder.svg+` | `+footnote+` | image:icons/footnote.svg[footnote.svg] | `+footnote.svg+` +| `+format-code+` | image:icons/format-code.svg[format-code.svg] | `+format-code.svg+` | `+format-painter+` | image:icons/format-painter.svg[format-painter.svg] | `+format-painter.svg+` | `+format+` | image:icons/format.svg[format.svg] | `+format.svg+` | `+fullscreen+` | image:icons/fullscreen.svg[fullscreen.svg] | `+fullscreen.svg+` | `+gallery+` | image:icons/gallery.svg[gallery.svg] | `+gallery.svg+` | `+gamma+` | image:icons/gamma.svg[gamma.svg] | `+gamma.svg+` +| `+google-drive+` | image:icons/google-drive.svg[google-drive.svg] | `+google-drive.svg+` +| `+google-photos+` | image:icons/google-photos.svg[google-photos.svg] | `+google-photos.svg+` +| `+grayscale+` | image:icons/grayscale.svg[grayscale.svg] | `+grayscale.svg+` | `+help+` | image:icons/help.svg[help.svg] | `+help.svg+` | `+highlight-bg-color+` | image:icons/highlight-bg-color.svg[highlight-bg-color.svg] | `+highlight-bg-color.svg+` | `+home+` | image:icons/home.svg[home.svg] | `+home.svg+` | `+horizontal-rule+` | image:icons/horizontal-rule.svg[horizontal-rule.svg] | `+horizontal-rule.svg+` +| `+huddle+` | image:icons/huddle.svg[huddle.svg] | `+huddle.svg+` +| `+image-decorative+` | image:icons/image-decorative.svg[image-decorative.svg] | `+image-decorative.svg+` +| `+image-enhancements+` | image:icons/image-enhancements.svg[image-enhancements.svg] | `+image-enhancements.svg+` | `+image-options+` | image:icons/image-options.svg[image-options.svg] | `+image-options.svg+` | `+image+` | image:icons/image.svg[image.svg] | `+image.svg+` | `+import-word+` | image:icons/import-word.svg[import-word.svg] | `+import-word.svg+` @@ -80,6 +100,7 @@ | `+info+` | image:icons/info.svg[info.svg] | `+info.svg+` | `+insert-character+` | image:icons/insert-character.svg[insert-character.svg] | `+insert-character.svg+` | `+insert-time+` | image:icons/insert-time.svg[insert-time.svg] | `+insert-time.svg+` +| `+instagram+` | image:icons/instagram.svg[instagram.svg] | `+instagram.svg+` | `+invert+` | image:icons/invert.svg[invert.svg] | `+invert.svg+` | `+italic+` | image:icons/italic.svg[italic.svg] | `+italic.svg+` | `+language+` | image:icons/language.svg[language.svg] | `+language.svg+` @@ -103,12 +124,14 @@ | `+list-num-upper-roman+` | image:icons/list-num-upper-roman.svg[list-num-upper-roman.svg] | `+list-num-upper-roman.svg+` | `+lock+` | image:icons/lock.svg[lock.svg] | `+lock.svg+` | `+ltr+` | image:icons/ltr.svg[ltr.svg] | `+ltr.svg+` +| `+math+` | image:icons/math-equation.svg[math-equation.svg] | `+math-equation.svg+` | `+minus+` | image:icons/minus.svg[minus.svg] | `+minus.svg+` | `+more-drawer+` | image:icons/more-drawer.svg[more-drawer.svg] | `+more-drawer.svg+` | `+new-document+` | image:icons/new-document.svg[new-document.svg] | `+new-document.svg+` | `+new-tab+` | image:icons/new-tab.svg[new-tab.svg] | `+new-tab.svg+` | `+non-breaking+` | image:icons/non-breaking.svg[non-breaking.svg] | `+non-breaking.svg+` | `+notice+` | image:icons/notice.svg[notice.svg] | `+notice.svg+` +| `+onedrive+` | image:icons/onedrive.svg[onedrive.svg] | `+onedrive.svg+` | `+ordered-list-rtl+` | image:icons/ordered-list-rtl.svg[ordered-list-rtl.svg] | `+ordered-list-rtl.svg+` | `+ordered-list+` | image:icons/ordered-list.svg[ordered-list.svg] | `+ordered-list.svg+` | `+orientation+` | image:icons/orientation.svg[orientation.svg] | `+orientation.svg+` @@ -131,13 +154,15 @@ | `+reload+` | image:icons/reload.svg[reload.svg] | `+reload.svg+` | `+remove-formatting+` | image:icons/remove-formatting.svg[remove-formatting.svg] | `+remove-formatting.svg+` | `+remove+` | image:icons/remove.svg[remove.svg] | `+remove.svg+` -| `+revision-history+` | image:icons/revision-history.svg[revision-history.svg] | `+revision-history.svg+` | `+resize-handle+` | image:icons/resize-handle.svg[resize-handle.svg] | `+resize-handle.svg+` | `+resize+` | image:icons/resize.svg[resize.svg] | `+resize.svg+` | `+restore-draft+` | image:icons/restore-draft.svg[restore-draft.svg] | `+restore-draft.svg+` +| `+revert+` | image:icons/revert.svg[revert.svg] | `+revert.svg+` +| `+revision-history+` | image:icons/revision-history.svg[revision-history.svg] | `+revision-history.svg+` | `+rotate-left+` | image:icons/rotate-left.svg[rotate-left.svg] | `+rotate-left.svg+` | `+rotate-right+` | image:icons/rotate-right.svg[rotate-right.svg] | `+rotate-right.svg+` | `+rtl+` | image:icons/rtl.svg[rtl.svg] | `+rtl.svg+` +| `+saturation+` | image:icons/saturation.svg[saturation.svg] | `+saturation.svg+` | `+save+` | image:icons/save.svg[save.svg] | `+save.svg+` | `+search+` | image:icons/search.svg[search.svg] | `+search.svg+` | `+select-all+` | image:icons/select-all.svg[select-all.svg] | `+select-all.svg+` @@ -178,6 +203,7 @@ | `+text-size-decrease+` | image:icons/text-size-decrease.svg[text-size-decrease.svg] | `+text-size-decrease.svg+` | `+text-size-increase+` | image:icons/text-size-increase.svg[text-size-increase.svg] | `+text-size-increase.svg+` | `+toc+` | image:icons/toc.svg[toc.svg] | `+toc.svg+` +| `+transform-image+` | image:icons/transform-image.svg[transform-image.svg] | `+transform-image.svg+` | `+translate+` | image:icons/translate.svg[translate.svg] | `+translate.svg+` | `+typography+` | image:icons/typography.svg[typography.svg] | `+typography.svg+` | `+underline+` | image:icons/underline.svg[underline.svg] | `+underline.svg+` @@ -189,9 +215,12 @@ | `+upload+` | image:icons/upload.svg[upload.svg] | `+upload.svg+` | `+user+` | image:icons/user.svg[user.svg] | `+user.svg+` | `+vertical-align+` | image:icons/vertical-align.svg[vertical-align.svg] | `+vertical-align.svg+` +| `+vibrance+` | image:icons/vibrance.svg[vibrance.svg] | `+vibrance.svg+` | `+visualblocks+` | image:icons/visualblocks.svg[visualblocks.svg] | `+visualblocks.svg+` | `+visualchars+` | image:icons/visualchars.svg[visualchars.svg] | `+visualchars.svg+` +| `+vk+` | image:icons/vk.svg[vk.svg] | `+vk.svg+` +| `+warmth+` | image:icons/warmth.svg[warmth.svg] | `+warmth.svg+` | `+warning+` | image:icons/warning.svg[warning.svg] | `+warning.svg+` | `+zoom-in+` | image:icons/zoom-in.svg[zoom-in.svg] | `+zoom-in.svg+` | `+zoom-out+` | image:icons/zoom-out.svg[zoom-out.svg] | `+zoom-out.svg+` -|=== +|=== \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/importword.adoc b/modules/ROOT/partials/configuration/importword.adoc deleted file mode 100644 index 54b0102a9e..0000000000 --- a/modules/ROOT/partials/configuration/importword.adoc +++ /dev/null @@ -1,22 +0,0 @@ -[[importword-service-url-option]] -== `importword_service_url` option - -This option is used for setting the URL endpoint for the conversion service. - -[IMPORTANT] -If this string value is **not configured** it will return a console.error: -_The {pluginname} plugin requires the `importword_service_url` to be configured_. If the editor detects an `invalid_URL`, it will return a console.error: _The value provided in `importword_service_url` is not a valid URL_. - -*Type:* `+String+` - -=== Example: using `importword_service_url` - -[source,js] ----- -tinymce.init({ - selector: 'textarea', - plugins: 'code importword', - toolbar: 'importword code', - importword_service_url: '' -}); ----- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/importword_converter_options.adoc b/modules/ROOT/partials/configuration/importword_converter_options.adoc new file mode 100644 index 0000000000..5e8ff26dd5 --- /dev/null +++ b/modules/ROOT/partials/configuration/importword_converter_options.adoc @@ -0,0 +1,42 @@ +[[importword-converter-options]] +== `importword_converter_options` + +**Type:** `String` + +[NOTE] +As of {productname} 7.5.0, the default value of the `importword_converter_options` setting has been updated to the following: + +.**Default value:** +[source,js] +---- +importword_converter_options: { + formatting: { + styles: 'inline', + resets: 'inline', + defaults: 'inline', + } +} +---- + +The `importword_converter_options` setting allows you to customize the behavior of the {pluginname} plugin when converting Word documents to HTML. + +.Example: using `importword_converter_options` +[source, js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'importword', + toolbar: 'importword', + importword_service_url: '', // required if using On-premises service + importword_converter_options: { + formatting: { + resets: 'inline', + defaults: 'inline', + styles: 'none', + } + } +}); +---- + +[NOTE] +For more information on the available converter options, refer to the link:https://importdocx.api.tiny.cloud/v2/convert/docs#section/Import-from-Word/Configuration[Import from Word API documentation]. \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/importword_service_url.adoc b/modules/ROOT/partials/configuration/importword_service_url.adoc new file mode 100644 index 0000000000..954ebb4cbb --- /dev/null +++ b/modules/ROOT/partials/configuration/importword_service_url.adoc @@ -0,0 +1,29 @@ +[[importword-service-url]] +== `importword_service_url` + +The `importword_service_url` option sets the URL endpoint for the DOCX-to-HTML conversion service. + +This option is **required** when configuring the {pluginname} plugin for `on-premise` setups. If you require access to this feature, please link:https://www.tiny.cloud/contact/[contact us]. For detailed instructions on deploying the {pluginname} service server-side component using Docker, refer to the xref:individual-import-from-word-and-export-to-word-on-premises.adoc[on-premises documentation]. + +[TIP] +When using a custom host, set the `importword_service_url` option in your {productname} configuration to match your host. For example, if your custom host is `mycustomhost.com`, set the URL to `https://mycustomhost.com/`. + +*Type:* `+String+` + +=== Example: Setting up `importword_service_url` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'importword', + toolbar: 'importword', + importword_service_url: '' // required for On-premise setups only +}); +---- + +[IMPORTANT] +==== +* If the `importword_service_url` option is **not configured**, a `console.error` will display: _The {pluginname} plugin requires the `importword_service_url` to be configured_. +* If the URL provided is invalid, a `console.error` will display: _The value provided in `importword_service_url` is not a valid URL_. +==== \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/importword_token_provider.adoc b/modules/ROOT/partials/configuration/importword_token_provider.adoc new file mode 100644 index 0000000000..cb4bff5dc4 --- /dev/null +++ b/modules/ROOT/partials/configuration/importword_token_provider.adoc @@ -0,0 +1,31 @@ +[[importword-token-provider]] +== `importword_token_provider` + +The `importword_token_provider` option enables integration with a token-based authentication service for importing Word documents. It provides a mechanism to fetch an authentication token from a specified endpoint. This ensures that the import process can securely communicate with the server. + +*Type:* `+Function+` + +*Default value:* `undefined` + +=== Example: using `importword_token_provider` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'importword', + toolbar: 'importword', + importword_token_provider: () => { + return fetch('http://localhost:3000/jwt', { // specify your token endpoint + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }).then(response => response.json()); + }, +}); +---- + +[NOTE] +The `importword_token_provider` option is required when using the {companyname} Cloud service. For more information on how to set up JWT authentication with {pluginname}, see examples: + +* xref:import-from-word-with-jwt-authentication-nodejs.adoc[Import to Word with JWT authentication (Node.js)] +* xref:import-from-word-with-jwt-authentication-php.adoc[Import to Word with JWT authentication (PHP)] \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/inline-css.adoc b/modules/ROOT/partials/configuration/inline-css.adoc index 2a6df5bd3d..d982a18c5f 100644 --- a/modules/ROOT/partials/configuration/inline-css.adoc +++ b/modules/ROOT/partials/configuration/inline-css.adoc @@ -1,8 +1,8 @@ -=== inline_selector_filter +=== inlinecss_selector_filter -Determines whether it is valid for a given CSS selector to have its CSS properties inlined into the HTML content +Determines whether it is valid for a given CSS selector to have its CSS properties inlined into the HTML content. -Default: All selectors are considered valid to have their CSS inlined +Default: All selectors are considered valid to have their CSS inlined. Type: `String` `RegExp` or `Function` @@ -13,11 +13,11 @@ inlinecss_selector_filter: (selector: string): boolean => { } ---- -=== inline_file_filter +=== inlinecss_file_filter -Determines whether it is valid for a given CSS stylesheet to have its CSS inspected and inlined into the HTML content +Determines whether it is valid for a given CSS stylesheet to have its CSS inspected and inlined into the HTML content. -Default: All CSS stylesheet are considered valid to have their CSS inspected and inlined +Default: All CSS stylesheet are considered valid to have their CSS inspected and inlined. Type: `String` `RegExp` or `Function` @@ -27,4 +27,3 @@ inlinecss_file_filter: (href: string): boolean => { return selector.indexOf('mystyles') !== -1; } ---- - diff --git a/modules/ROOT/partials/configuration/mentions_fetch.adoc b/modules/ROOT/partials/configuration/mentions_fetch.adoc index 40c59bf62c..4836dc0aef 100644 --- a/modules/ROOT/partials/configuration/mentions_fetch.adoc +++ b/modules/ROOT/partials/configuration/mentions_fetch.adoc @@ -26,9 +26,9 @@ tinymce.init({ usersRequest = fetch('/users'); } usersRequest.then((users) => { - // query.term is the text the user typed after the '@' + // `query.term` is the text the user typed after the '@' users = users.filter((user) => { - return user.name.indexOf(query.term.toLowerCase()) !== -1; + return user.name.toLowerCase().includes(query.term.toLowerCase()); }); users = users.slice(0, 10); diff --git a/modules/ROOT/partials/configuration/menu.adoc b/modules/ROOT/partials/configuration/menu.adoc index 5093605616..3bec6eee89 100644 --- a/modules/ROOT/partials/configuration/menu.adoc +++ b/modules/ROOT/partials/configuration/menu.adoc @@ -1,13 +1,11 @@ [[menu]] == `+menu+` -This option allows you to specify which menus should appear on {productname}'s menu bar and the xref:available-menu-items.adoc[items] that should appear within the menus themselves. +The `+menu+` option allows integrators to define the available menus for the xref:menus-configuration-options.adoc#menubar[menubar option] and specify the xref:available-menu-items.adoc[menu items] that appear within those menus. -To specify the menus that should appear on {productname}'s menu bar, the menu option should be provided with a JavaScript object containing a property for each menu. These properties should contain a JavaScript object themselves with properties `+title+` and `+items+`. +To configure the menus, provide a JavaScript object where each property represents a menu. Each menu object should contain `+title+` and `+items+` properties. The `+title+` property is a string that defines the display name, while the `+items+` property is a space-separated list of the xref:available-menu-items.adoc[menu items] that should populate the menu. -The `+title+` property should contain a string with the name of the `+menu+`. The `+items+` field should contain a space separated list of the controls that should populate the `+menu+`. - -If you would like to group these menu items, please insert a `+|+` pipe character between the menu items. +To group certain menu items, insert a `+|+` pipe character between the menu items. *Type:* `+Object+` @@ -18,4 +16,5 @@ include::partial$configuration/defaultmenuitems.adoc[] include::partial$misc/admon-different-default-for-mobile.adoc[] -If all you need is to control which menus are available and/or in what order, see the xref:menus-configuration-options.adoc#menubar[menubar parameter]. +[NOTE] +This option alone does not control which menus appear in the menu bar or the order in which they appear. To control the menu bar and the order of the menus in the menu bar, see the xref:menus-configuration-options.adoc#menubar[menubar option]. diff --git a/modules/ROOT/partials/configuration/menubar.adoc b/modules/ROOT/partials/configuration/menubar.adoc index 93c0141c75..963a5f03da 100644 --- a/modules/ROOT/partials/configuration/menubar.adoc +++ b/modules/ROOT/partials/configuration/menubar.adoc @@ -1,9 +1,9 @@ [[menubar]] == `+menubar+` -This option allows you to specify which menus should appear and the order that they appear in the menu bar at the top of {productname}. +This option specifies which menus appear and their order in the menu bar at the top of {productname}. -To specify the menus that should appear on {productname}'s menu bar, the menubar option should be provided with a space separated list of menus. +To define the menus on {productname}'s menu bar, provide the menubar option with a space-separated list of menus. *Type:* `+String+` or `+Boolean+` @@ -25,7 +25,7 @@ tinymce.init({ === Example: disabling/removing the menu bar -To disable the menu bar, the menubar option should be provided a boolean value of `+false+`. +To disable the menu bar, set the `+menubar+` option to `+false+`. [source,js] ---- @@ -35,4 +35,4 @@ tinymce.init({ }); ---- -If you need more control over the contents of the menus, see the xref:menus-configuration-options.adoc#menu[menu parameter]. +For more granular control over the contents of the menus, refer to the xref:menus-configuration-options.adoc#menu[menu option] documentation. diff --git a/modules/ROOT/partials/configuration/mergetags_prefix.adoc b/modules/ROOT/partials/configuration/mergetags_prefix.adoc index 1030f12087..3b22e26659 100644 --- a/modules/ROOT/partials/configuration/mergetags_prefix.adoc +++ b/modules/ROOT/partials/configuration/mergetags_prefix.adoc @@ -19,6 +19,4 @@ tinymce.init({ toolbar: 'mergetags', mergetags_prefix: '{{' }); ----- - -IMPORTANT: Whatever character or characters are set as the Merge Tags prefix, it or they must be different to the characters set as the Merge Tags suffix. For example, if the Merge Tags prefix is set to `%`, the Merge Tags suffix cannot also be `%`. +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/mergetags_suffix.adoc b/modules/ROOT/partials/configuration/mergetags_suffix.adoc index dc041cf340..715e9c45c8 100644 --- a/modules/ROOT/partials/configuration/mergetags_suffix.adoc +++ b/modules/ROOT/partials/configuration/mergetags_suffix.adoc @@ -17,6 +17,4 @@ tinymce.init({ toolbar: 'mergetags', mergetags_suffix: '}}' }); ----- - -IMPORTANT: Whatever character or characters are set as the Merge Tags suffix, it or they must be different to the characters set as the Merge Tags prefix. For example, if the Merge Tags suffix is set to `%`, the Merge Tags prefix cannot also be `%`. +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/powerpaste_autolink_urls.adoc b/modules/ROOT/partials/configuration/powerpaste_autolink_urls.adoc new file mode 100644 index 0000000000..9a71d1e86e --- /dev/null +++ b/modules/ROOT/partials/configuration/powerpaste_autolink_urls.adoc @@ -0,0 +1,23 @@ +[[powerpaste_autolink_urls]] +== `+powerpaste_autolink_urls+` + +This option enables or disables the automatic linking of text that resembles URLs in pasted content. + +*Type:* `+Boolean+` + +*Default value:* `+true+` + +*Possible values:* `+true+`, `+false+` + +NOTE: Setting the `+powerpaste_autolink_urls+` option to `+false+` overrides the auto-linking behavior of the xref:smart_paste[`+smart_paste+`] option. + +=== Example: Disable auto-linking of URLs + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'powerpaste', + powerpaste_autolink_urls: false, +}); +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/readonly.adoc b/modules/ROOT/partials/configuration/readonly.adoc index 9d75eb273a..680c04f421 100644 --- a/modules/ROOT/partials/configuration/readonly.adoc +++ b/modules/ROOT/partials/configuration/readonly.adoc @@ -1,15 +1,15 @@ [[readonly]] -== `+readonly+` +== `readonly` -Setting the `+readonly+` option to `+true+` will initialize the editor in `+"readonly"+` mode instead of editing (`+"design"+`) mode. Once initialized, the editor can be set to editing (`+"design"+`) mode using the xref:apis/tinymce.editormode.adoc#set[`+tinymce.editor.mode.set+` API]. +Setting the `readonly` option to `true` initializes the editor in **readonly** mode instead of editing (**design**) mode. Once initialized, the editor can be switched to **design** mode using the xref:apis/tinymce.editormode.adoc#set[`tinymce.editor.mode.set` API]. -*Type:* `+Boolean+` +*Type:* `Boolean` -*Default value:* `+false+` +*Default value:* `false` -*Possible values:* `+true+`, `+false+` +*Possible values:* `true`, `false` -=== Example: using `+readonly+` +=== Example: Using `readonly` [source,js] ---- @@ -20,3 +20,61 @@ tinymce.init({ ---- liveDemo::readonly-demo[] + +=== Behavior in `readonly` mode + +[cols="1,3,1", options="header"] +|=== +| **Behavior** | **Details** | **Allowed (True/False)** + +| Navigation and Interaction +a| +* Users can place the cursor within the editor +* Navigation behaves the same as in design mode, including: + ** Moving through block elements (table of contents, images, media elements) + ** Using arrow keys, Home, End, Page Up, Page Down +* Media elements can be played +* Users can select and copy text +* Users can interact with links +| True +| Prevented Actions +a| +* All input events (keyboard and IME input) +* Content modifications: + ** Pasting content + ** Cutting content + ** Deleting content + ** Drag and drop operations +* Formatting changes: + ** Keyboard shortcuts for formatting (e.g., Cmd/Ctrl + B) + ** Auto-linking when pressing space after URLs +* Element modifications: + ** Toggling checklists (via click or Cmd/Ctrl + Enter) + ** Indenting lists + ** Adding new table rows via Tab key + ** Resizing tables, media elements, or images +| False +| Toolbar and UI Behavior +a| +* Most toolbar buttons are disabled +* Fields in dialogs (e.g., link dialog) are disabled +* When switching from **design** to **readonly** mode: + ** All open dialogs and UI components adjust to reflect readonly state +| False + +| Enabled Features +a| +* The following toolbar/menu items remain enabled in **readonly** mode: +** xref:fullscreen.adoc[Full Screen] +** xref:help.adoc[Help] +** xref:preview.adoc[Preview] +** xref:visualblocks.adoc[Visual Blocks] +** xref:visualchars.adoc[Visual Characters] +** xref:wordcount.adoc[Word Count] +** xref:exportpdf.adoc[Export to PDF] +** xref:exportword.adoc[Export to Word] +** xref:content-appearance.adoc#visual[Visual Aid] +** Copy +** Select all +| True +|=== \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/removed_menuitems.adoc b/modules/ROOT/partials/configuration/removed_menuitems.adoc index 552599655f..cd97dcb101 100644 --- a/modules/ROOT/partials/configuration/removed_menuitems.adoc +++ b/modules/ROOT/partials/configuration/removed_menuitems.adoc @@ -1,7 +1,7 @@ [[removed_menuitems]] == `+removed_menuitems+` -This option allows you to remove items from {productname}'s drop down menus. This is useful if you are using the xref:menus-configuration-options.adoc#menubar[menubar] option to set your menus rather than the more specific xref:menus-configuration-options.adoc#menu[menu] option. +This option enables the exclusion of items from {productname}'s menus. It is especially useful when configuring menus using only the xref:menus-configuration-options.adoc#menubar[menubar] option without defining custom menu items through the xref:menus-configuration-options.adoc#menu[menu] option. *Type:* `+String+` diff --git a/modules/ROOT/partials/configuration/revisionhistory_author.adoc b/modules/ROOT/partials/configuration/revisionhistory_author.adoc new file mode 100644 index 0000000000..5e9d867c4e --- /dev/null +++ b/modules/ROOT/partials/configuration/revisionhistory_author.adoc @@ -0,0 +1,24 @@ +[[revisionhistory_author]] +== `revisionhistory_author` + +This option configures the author for the `initial` and `draft` revisions. + +*Type:* xref:#author[Author] `+Object+` + +=== Example: using `revisionhistory_author` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'revisionhistory', + toolbar: 'revisionhistory', + revisionhistory_fetch: () => Promise.resolve([]), + revisionhistory_display_author: true, + revisionhistory_author: { + id: 'john.doe', + name: 'John Doe', + avatar: 'https://example.com/avatar.jpg' + } +}); +---- diff --git a/modules/ROOT/partials/configuration/revisionhistory_css_url.adoc b/modules/ROOT/partials/configuration/revisionhistory_css_url.adoc index 8dde046723..d2ccd5a871 100644 --- a/modules/ROOT/partials/configuration/revisionhistory_css_url.adoc +++ b/modules/ROOT/partials/configuration/revisionhistory_css_url.adoc @@ -18,6 +18,7 @@ tinymce.init({ selector: 'textarea', // change this value according to your HTML plugins: 'revisionhistory', toolbar: 'revisionhistory', + revisionhistory_fetch: () => Promise.resolve([]), // Required option for the plugin - replace with actual API request revisionhistory_css_url: './revisionhistory.css' }); ---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/revisionhistory_diff_classes.adoc b/modules/ROOT/partials/configuration/revisionhistory_diff_classes.adoc index a43582b02c..a0eb0778bb 100644 --- a/modules/ROOT/partials/configuration/revisionhistory_diff_classes.adoc +++ b/modules/ROOT/partials/configuration/revisionhistory_diff_classes.adoc @@ -26,12 +26,12 @@ tinymce.init({ selector: 'textarea', // change this value according to your HTML plugins: 'revisionhistory', toolbar: 'revisionhistory', + revisionhistory_fetch: () => Promise.resolve([]), // Required option for the plugin - replace with actual API request revisionhistory_css_url: './revisionhistory.css', revisionhistory_diff_classes: { addition: 'added', removal: 'removed', modification: 'modified' - }, - revisionhistory_fetch: () => Promise.resolve([]) + } }); ---- diff --git a/modules/ROOT/partials/configuration/revisionhistory_display_author.adoc b/modules/ROOT/partials/configuration/revisionhistory_display_author.adoc new file mode 100644 index 0000000000..007e042deb --- /dev/null +++ b/modules/ROOT/partials/configuration/revisionhistory_display_author.adoc @@ -0,0 +1,21 @@ +[[revisionhistory_display_author]] +== `revisionhistory_display_author` + +This option configures the display of the revision's author. When set to `+true+`, the author's name appears in each revision within the Revision History sidebar. If the author's name is not provided, it defaults to `Anonymous`. + +*Type:* `+Boolean+` + +*Default value:* `+false+` + +=== Example: using `revisionhistory_display_author` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'revisionhistory', + toolbar: 'revisionhistory', + revisionhistory_fetch: () => Promise.resolve([]), + revisionhistory_display_author: true +}); +---- diff --git a/modules/ROOT/partials/configuration/revisionhistory_fetch.adoc b/modules/ROOT/partials/configuration/revisionhistory_fetch.adoc index ee5801b7eb..9861d28d54 100644 --- a/modules/ROOT/partials/configuration/revisionhistory_fetch.adoc +++ b/modules/ROOT/partials/configuration/revisionhistory_fetch.adoc @@ -1,18 +1,22 @@ [[revisionhistory_fetch]] == `revisionhistory_fetch` -The plugin uses the `revisionhistory_fetch` function to retrieve the saved versions. +The `revisionhistory_fetch` function retrieves saved revisions and is called when the user opens the Revision History view. -The `revisionhistory_fetch` option is an asynchronous function that returns a https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise] which resolves to an array of revisions. +[IMPORTANT] +The `revisionhistory_fetch` function is required for the Revision History plugin to function. + + +It expects an asynchronous function that returns a link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise] which resolves to an array of revisions. [NOTE] -The {pluginname} plugin does not sort the result before displaying. This allows the integrators to sort the result according to their preference. It is recommended that the result should be sorted in reverse chronological order because it is more intuitive for the users when they can only identify a version by its date. +The {pluginname} plugin does not sort results before displaying them, allowing integrators to sort the results according to their preference. {companyname} recommends to sort the results in reverse chronological order, as this makes it easier for users to identify revisions by date. *Type:* `+Function+` (Returns a https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise]) *Input parameters:* None -*Return data:* `+Array+` +*Return data:* `+Array+` of xref:#revision[Revision] `+Objects+` === Example of `revisionhistory_fetch` response @@ -42,16 +46,10 @@ const revisions = [

    Welcome to Tinymce!

    `, } -] +]; ---- -The data returned by `revisionhistory_fetch` requires the following fields for the {pluginname} to work: - -. `revisionId`: Unique string Id. -. `createdAt`: A UTC datetime string in ISO-8061 format. For example: `2019-11-14T10:55:31.820Z`. -. `content`: HTML string. - -=== Example: using `revisionhistory_fetch` +=== Example: Using `revisionhistory_fetch` [source,js] ---- @@ -63,6 +61,6 @@ tinymce.init({ fetch('') // Update the URL and response handling code according to your API .then((response) => response.json()) .then((data) => data) - .catch((error) => console.log('Failed to get versions\n' + error)) + .catch((error) => console.log('Failed to get revisions\n' + error)) }); ---- diff --git a/modules/ROOT/partials/configuration/revisionhistory_fetch_revision.adoc b/modules/ROOT/partials/configuration/revisionhistory_fetch_revision.adoc new file mode 100644 index 0000000000..d729459112 --- /dev/null +++ b/modules/ROOT/partials/configuration/revisionhistory_fetch_revision.adoc @@ -0,0 +1,79 @@ +[[revisionhistory_fetch_revision]] +== `revisionhistory_fetch_revision` +When a revision is selected, the plugin uses this option to update the selected or closest revision that has no content. The function is expected to return a Promise that resolves with an updated revision. + +*Type:* `+Function+` (Returns a link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise]) + +*Input parameters:* +[cols="1,1,1,3",options="header"] +|=== +|Field |Type |Required? |Description +|`+editor+` | `+Editor+` | required | The current editor instance (useful if there are multiple editors on the page). +|`+revision+` | xref:#revision[Revision] `+Object+` | required | The targeted revision. +|=== + +*Return data:* xref:#revision[Revision] `+Object+` + +=== Example: Using `revisionhistory_fetch_revision` + +[source,js] +---- +const lightRevisions = [ + { + revisionId: '3', + createdAt: '2023-11-29T10:11:21.578Z', + }, + { + revisionId: '2', + createdAt: '2023-11-25T08:30:21.578Z', + }, + { + revisionId: '1', + createdAt: '2023-11-24T22:26:21.578Z', + } +]; + +const revisions = [ + { + revisionId: '3', + createdAt: '2023-11-29T10:11:21.578Z', + content: ` +

    Welcome to TinyMCE Docs!

    +

    Here is some content that is bold and italic.

    + `, + }, + { + revisionId: '2', + createdAt: '2023-11-25T08:30:21.578Z', + content: ` +

    Welcome to TinyMCE Docs!

    +

    Here is some content that is bold and italic.

    + `, + }, + { + revisionId: '1', + createdAt: '2023-11-24T22:26:21.578Z', + content: ` +

    Welcome to Tinymce!

    + `, + } +]; + +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'revisionhistory', + toolbar: 'revisionhistory', + revisionhistory_fetch: () => Promise.resolve(lightRevisions), + revisionhistory_fetch_revision: (_editor, revision) => new Promise((resolve) => { + let newRevision = null; + for (let i = 0; i < revisions.length; i++) { + const temp = revisions[i]; + if (temp.revisionId === revision.revisionId) { + newRevision = temp; + break; + } + } + resolve(newRevision); + }) +}); +---- diff --git a/modules/ROOT/partials/configuration/smart_paste.adoc b/modules/ROOT/partials/configuration/smart_paste.adoc index a3beabff10..185eec6089 100644 --- a/modules/ROOT/partials/configuration/smart_paste.adoc +++ b/modules/ROOT/partials/configuration/smart_paste.adoc @@ -14,6 +14,8 @@ To disable the `+smart_paste+` functionality, set `+smart_paste+` to `+false+`. *Possible values:* `+true+`, `+false+` +NOTE: Setting the xref:powerpaste_autolink_urls[`+powerpaste_autolink_urls+`] option to `+false+` overrides the auto-linking feature of the `+smart_paste+` option. + === Example: using `+smart_paste+` ifdef::plugincode[] diff --git a/modules/ROOT/partials/configuration/spellchecker_languages.adoc b/modules/ROOT/partials/configuration/spellchecker_languages.adoc index 9a72e15343..d44edd128f 100644 --- a/modules/ROOT/partials/configuration/spellchecker_languages.adoc +++ b/modules/ROOT/partials/configuration/spellchecker_languages.adoc @@ -8,9 +8,10 @@ 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=nb,Portuguese=pt,Portuguese (Portugal)=pt_PT,Spanish=es,Swedish=sv' +'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' ---- + === Example: using `spellchecker_languages` [source,js] @@ -18,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=nb,Brazilian Portuguese=pt,Iberian Portuguese=pt_PT,Spanish=es,Swedish=sv' + 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/configuration/text_color.adoc b/modules/ROOT/partials/configuration/text_color.adoc index b320feba93..1f793eedbf 100644 --- a/modules/ROOT/partials/configuration/text_color.adoc +++ b/modules/ROOT/partials/configuration/text_color.adoc @@ -145,6 +145,32 @@ tinymce.init({ }); ---- +[[color_map_raw]] +=== `+color_map_raw+` + +The `color_map_raw` option specifies a map of text colors that appear in the color picker grid. This configuration provides detailed control over the colors available for the `forecolor` and `backcolor` toolbar options. The following example shows how to set the color map using CSS variables, color functions, and hex codes. + +*Type:* `+Array+` + +==== Example: using `+color_map_raw+` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Adjust this value according to your HTML + toolbar: 'forecolor backcolor', + color_map_raw: [ + 'var(--black)', 'Black', // CSS variable-based colors + 'var(--red)', 'Red', + 'hsb(0, 100%, 100%)', 'White hsb', // Color functions like hsb() and hsl() + 'hsl(0, 100%, 50%)', 'Red hsl', + '#ff00ff', 'Pink', // Hex code-based colors + '#00ffff', 'Cyan', + 'var(--purple)', 'Purple', // User-friendly labels for easy identification such as 'Purple'. + '#00FF7F', 'Spring Green' + ], +}); +---- [[color_map_background]] === `color_map_background` diff --git a/modules/ROOT/partials/configuration/tinycomments_author.adoc b/modules/ROOT/partials/configuration/tinycomments_author.adoc index 7280f8fce8..2fd8b7f9a1 100644 --- a/modules/ROOT/partials/configuration/tinycomments_author.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_author.adoc @@ -14,6 +14,7 @@ This option sets the author id to be used when creating or replying to comments. tinymce.init({ selector: 'textarea', // change this value according to your html plugins: 'tinycomments', + toolbar: 'addcomment showcomments', tinycomments_mode: 'embedded', tinycomments_author: 'embedded_journalist', }); diff --git a/modules/ROOT/partials/configuration/tinycomments_author_avatar.adoc b/modules/ROOT/partials/configuration/tinycomments_author_avatar.adoc index 2e74822352..47f3052aa3 100644 --- a/modules/ROOT/partials/configuration/tinycomments_author_avatar.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_author_avatar.adoc @@ -3,12 +3,13 @@ include::partial$misc/admon-requires-6.1v.adoc[] -_Optional_ - This option sets the URL for the author's avatar to be used when creating or replying to comments. If this option is omitted, a generated avatar will be used instead. The avatar, if provided: +_Optional_: This option sets the URL for the author's avatar to be used when creating or replying to comments. If this option is omitted, a generated avatar will be used instead. The avatar, if provided: * will be scaled to a 36px diameter circle; and -* can be any filetype able to be wrapped in an `` element. +* can be any filetype able to be wrapped in an `++` element. -IMPORTANT: The avatar will be stored alongside the embedded comment data when a new comment is created and cannot be changed later by changing this options value. To change the avatar image, the image on the server that the URL points to should be updated instead. +[IMPORTANT] +The avatar will be stored alongside the embedded comment data when a new comment is created and cannot be changed later by changing this options value. To change the avatar image, the image on the server that the URL points to should be updated instead. *Type:* `+String+` @@ -19,9 +20,10 @@ IMPORTANT: The avatar will be stored alongside the embedded comment data when a tinymce.init({ selector: 'textarea', // change this value according to your html plugins: 'tinycomments', + toolbar: 'addcomment showcomments', tinycomments_mode: 'embedded', tinycomments_author: 'embedded_journalist', tinycomments_author_name: 'Embedded Journalist', tinycomments_author_avatar: 'https://example.com/image.ext' }); ----- +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/tinycomments_author_name.adoc b/modules/ROOT/partials/configuration/tinycomments_author_name.adoc index 8e943c2146..e13792222b 100644 --- a/modules/ROOT/partials/configuration/tinycomments_author_name.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_author_name.adoc @@ -1,7 +1,7 @@ [[tinycomments_author_name]] == `+tinycomments_author_name+` -_Optional_ - This option sets the author's display name to be used when creating or replying to comments. If this option is omitted, then the author id is used instead. +_Optional_: This option sets the author's display name to be used when creating or replying to comments. If this option is omitted, the author `+id+` is used instead. *Type:* `+String+` @@ -12,8 +12,9 @@ _Optional_ - This option sets the author's display name to be used when creating tinymce.init({ selector: 'textarea', // change this value according to your html plugins: 'tinycomments', + toolbar: 'addcomment showcomments', tinycomments_mode: 'embedded', tinycomments_author: 'embedded_journalist', tinycomments_author_name: 'Embedded Journalist', }); ----- +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/tinycomments_can_delete.adoc b/modules/ROOT/partials/configuration/tinycomments_can_delete.adoc index 67357f5907..d4b795e43c 100644 --- a/modules/ROOT/partials/configuration/tinycomments_can_delete.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_can_delete.adoc @@ -1,7 +1,7 @@ [[tinycomments_can_delete]] == `+tinycomments_can_delete+` -_Optional_ - This option sets the author permissions for _deleting comment conversations_. If the `+tinycomments_can_delete+` option is not included, the current author (`+tinycomments_author+`) cannot delete comment conversations created by other authors. +_Optional_: This option sets the author permissions for _deleting comment conversations_. If the `+tinycomments_can_delete+` option is not included, the current author (`+tinycomments_author+`) cannot delete comment conversations created by other authors. *Type:* `+Function+` @@ -9,15 +9,15 @@ _Optional_ - This option sets the author permissions for _deleting comment conve [source,js] ---- (req, done, fail) => { - const allowed = req.comments.length > 0 && - req.comments[0].author === ; + const allowed = req.comments.length > 0 && req.comments[0].author === ; done({ canDelete: allowed }); } ---- -The following example extends the default behavior to allow the author `` to delete other author's comment conversations by adding `|| currentAuthor === ''`. +[NOTE] +The following example extends the default behavior to allow the author `++` to delete other author's comment conversations by adding `|| currentAuthor === ''`. === Example: using `tinycomments_can_delete` @@ -28,14 +28,14 @@ const currentAuthor = 'embedded_journalist'; tinymce.init({ selector: 'textarea', // change this value according to your html plugins: 'tinycomments', + toolbar: 'addcomment showcomments', tinycomments_mode: 'embedded', tinycomments_author: currentAuthor, tinycomments_can_delete: (req, done, fail) => { - const allowed = req.comments.length > 0 && - req.comments[0].author === currentAuthor; + const allowed = req.comments.length > 0 && req.comments[0].author === currentAuthor; done({ canDelete: allowed || currentAuthor === '' }); } }); ----- +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/tinycomments_can_delete_comment.adoc b/modules/ROOT/partials/configuration/tinycomments_can_delete_comment.adoc index f2e2047d44..3d7f0e6be5 100644 --- a/modules/ROOT/partials/configuration/tinycomments_can_delete_comment.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_can_delete_comment.adoc @@ -1,7 +1,7 @@ [[tinycomments_can_delete_comment]] == `+tinycomments_can_delete_comment+` -_Optional_ - This option sets the author permissions for _deleting comments_. If the `+tinycomments_can_delete_comment+` option is not included, the current author (`+tinycomments_author+`) cannot delete comments added by other authors. +_Optional_: This option sets the author permissions for _deleting comments_. If the `+tinycomments_can_delete_comment+` option is not included, the current author (`+tinycomments_author+`) **cannot** delete comments added by other authors. *Type:* `+Function+` @@ -16,7 +16,8 @@ _Optional_ - This option sets the author permissions for _deleting comments_. If } ---- -The following example extends the default behavior to allow the author `` to delete other author's comments by adding `|| currentAuthor === ''`. +[NOTE] +The following example extends the default behavior to allow the author `++` to delete other author's comments by adding `+|| currentAuthor === ''+`. === Example: using `tinycomments_can_delete_comment` @@ -27,6 +28,7 @@ const currentAuthor = 'embedded_journalist'; tinymce.init({ selector: 'textarea', // change this value according to your html plugins: 'tinycomments', + toolbar: 'addcomment showcomments', tinycomments_mode: 'embedded', tinycomments_author: currentAuthor, tinycomments_can_delete_comment: (req, done, fail) => { @@ -36,4 +38,4 @@ tinymce.init({ }); } }); ----- +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/tinycomments_can_edit_comment.adoc b/modules/ROOT/partials/configuration/tinycomments_can_edit_comment.adoc index 6cbbe45dfe..dcf1339e64 100644 --- a/modules/ROOT/partials/configuration/tinycomments_can_edit_comment.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_can_edit_comment.adoc @@ -1,7 +1,7 @@ [[tinycomments_can_edit_comment]] == `+tinycomments_can_edit_comment+` -_Optional_ - This option sets the author permissions for _editing comments_. If the `+tinycomments_can_edit_comment+` option is not included, the current author (`+tinycomments_author+`) cannot edit comments added by other authors. +_Optional_: This option sets the author permissions for _editing comments_. If the `+tinycomments_can_edit_comment+` option is not included, the current author (`+tinycomments_author+`) cannot edit comments added by other authors. *Type:* `+Function+` @@ -16,7 +16,7 @@ _Optional_ - This option sets the author permissions for _editing comments_. If } ---- -The following example extends the default behavior to allow the author `` to edit other author's comments by adding `|| currentAuthor === ''`. +The following example extends the default behavior to allow the author `++` to edit other author's comments by adding `|| currentAuthor === ''`. === Example: using `tinycomments_can_edit_comment` @@ -27,6 +27,7 @@ const currentAuthor = 'embedded_journalist'; tinymce.init({ selector: 'textarea', // change this value according to your html plugins: 'tinycomments', + toolbar: 'addcomment showcomments', tinycomments_mode: 'embedded', tinycomments_author: currentAuthor, tinycomments_can_edit_comment: (req, done, fail) => { @@ -36,4 +37,4 @@ tinymce.init({ }); } }); ----- +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/tinycomments_can_resolve.adoc b/modules/ROOT/partials/configuration/tinycomments_can_resolve.adoc index aef881fe8e..491cb7ba97 100644 --- a/modules/ROOT/partials/configuration/tinycomments_can_resolve.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_can_resolve.adoc @@ -1,7 +1,7 @@ [[tinycomments_can_resolve]] == `+tinycomments_can_resolve+` -_Optional_ - This option adds a _Resolve Conversation_ item to the dropdown menu of the first comment in a conversation. This callback sets the author permissions for _resolving comment conversations_. +_Optional_: This option adds a _Resolve Conversation_ item to the dropdown menu of the first comment in a conversation. This callback sets the author permissions for _resolving comment conversations_. *Type:* `+Function+` @@ -14,14 +14,14 @@ const currentAuthor = 'embedded_journalist'; tinymce.init({ selector: 'textarea', // change this value according to your html plugins: 'tinycomments', + toolbar: 'addcomment showcomments', tinycomments_mode: 'embedded', tinycomments_author: currentAuthor, tinycomments_can_resolve: (req, done, fail) => { - const allowed = req.comments.length > 0 && - req.comments[0].author === currentAuthor; + const allowed = req.comments.length > 0 && req.comments[0].author === currentAuthor; done({ canResolve: allowed || currentAuthor === '' }); } }); ----- +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/tinycomments_create.adoc b/modules/ROOT/partials/configuration/tinycomments_create.adoc index bd33613356..939fd3101d 100644 --- a/modules/ROOT/partials/configuration/tinycomments_create.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_create.adoc @@ -1,15 +1,14 @@ [[tinycomments_create]] == `+tinycomments_create+` -The Comments plugin uses the `+tinycomments_create+` function to create a comment. +The {pluginname} plugin uses the `+tinycomments_create+` function to create a comment. The `+tinycomments_create+` function saves the comment as a new conversation and returns a unique conversation ID via the `+done+` callback. If an unrecoverable error occurs, it should indicate this with the fail callback. The `+tinycomments_create+` function is given a request (req) object as the first parameter, which has these fields: -`+content+`:: The content of the comment to create. - -`+createdAt+`:: The date the comment was created. +* `+content+`: The content of the comment to create. +* `+createdAt+`: The date the comment was created. The `+done+` callback should accept the following object: @@ -24,8 +23,7 @@ The `+done+` callback should accept the following object: } ---- -For example: - +.For example: [source,js] ---- const create_comment = (ref, done, fail) => { @@ -64,6 +62,7 @@ tinymce.init({ tinycomments_delete: delete_comment_thread, tinycomments_delete_all: delete_all_comment_threads, tinycomments_delete_comment: delete_comment, - tinycomments_lookup: lookup_comment + tinycomments_lookup: lookup_comment, + tinycomments_fetch: fetch_comments // Optional callback }); ----- +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/tinycomments_delete.adoc b/modules/ROOT/partials/configuration/tinycomments_delete.adoc index 2b529986d2..af6a95cfdf 100644 --- a/modules/ROOT/partials/configuration/tinycomments_delete.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_delete.adoc @@ -5,7 +5,7 @@ The `+tinycomments_delete+` function should asynchronously return a flag indicat The `+tinycomments_delete+` function is passed a (`+req+`) object as the first parameter, which contains the following key-value pair: -`+conversationUid+`:: The uid of the conversation the reply is targeting. +* `+conversationUid+`: The uid of the conversation the reply is targeting. The `+done+` callback should accept the following object: @@ -17,7 +17,8 @@ The `+done+` callback should accept the following object: } ---- -NOTE: Failure to delete due to permissions or business rules is indicated by "false", while unexpected errors should be indicated using the "fail" callback. +[NOTE] +Failure to delete due to permissions or business rules is indicated by "false", while unexpected errors should be indicated using the "fail" callback. For example: @@ -48,6 +49,7 @@ tinymce.init({ tinycomments_delete: delete_comment_thread, // Add the callback to TinyMCE tinycomments_delete_all: delete_all_comment_threads, tinycomments_delete_comment: delete_comment, - tinycomments_lookup: lookup_comment + tinycomments_lookup: lookup_comment, + tinycomments_fetch: fetch_comments // Optional callback }); ---- diff --git a/modules/ROOT/partials/configuration/tinycomments_delete_all.adoc b/modules/ROOT/partials/configuration/tinycomments_delete_all.adoc index 06d2e96754..4417b157cb 100644 --- a/modules/ROOT/partials/configuration/tinycomments_delete_all.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_delete_all.adoc @@ -15,10 +15,10 @@ The `+done+` callback should accept the following object: } ---- -NOTE: Failure to delete due to permissions or business rules should be indicated by `+canDelete: false+`, while unexpected errors should be indicated using the `+fail+` callback. - -For example: +[NOTE] +Failure to delete due to permissions or business rules should be indicated by `+canDelete: false+`, while unexpected errors should be indicated using the `+fail+` callback. +.For example: [source,js] ---- const delete_all_comment_threads = (_req, done, fail) => { @@ -45,6 +45,7 @@ tinymce.init({ tinycomments_delete: delete_comment_thread, tinycomments_delete_all: delete_all_comment_threads, // Add the callback to TinyMCE tinycomments_delete_comment: delete_comment, - tinycomments_lookup: lookup_comment + tinycomments_lookup: lookup_comment, + tinycomments_fetch: fetch_comments // Optional callback }); ----- +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/tinycomments_delete_comment.adoc b/modules/ROOT/partials/configuration/tinycomments_delete_comment.adoc index d3c73f71d3..1c3bf997b6 100644 --- a/modules/ROOT/partials/configuration/tinycomments_delete_comment.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_delete_comment.adoc @@ -5,9 +5,8 @@ The `+tinycomments_delete_comment+` function should asynchronously return a flag The `+tinycomments_delete_comment+` function is given a request (req) object as the first parameter, which has these fields: -`+conversationUid+`:: The uid of the conversation the reply is targeting. - -`+commentUid+`:: The uid of the comment to delete (cannot be the same as `+conversationUid+`). +* `+conversationUid+`: The uid of the conversation the reply is targeting. +* `+commentUid+`: The uid of the comment to delete (cannot be the same as `+conversationUid+`). The `+done+` callback should accept the following object: @@ -19,10 +18,10 @@ The `+done+` callback should accept the following object: } ---- -NOTE: Failure to delete due to permissions or business rules is indicated by "false", while unexpected errors should be indicated using the "fail" callback. - -For example: +[NOTE] +Failure to delete due to permissions or business rules is indicated by "false", while unexpected errors should be indicated using the "fail" callback. +.For example: [source,js] ---- const delete_comment = (ref, done, fail) => { @@ -54,6 +53,7 @@ tinymce.init({ tinycomments_delete: delete_comment_thread, // Add the callback to TinyMCE tinycomments_delete_all: delete_all_comment_threads, tinycomments_delete_comment: delete_comment, - tinycomments_lookup: lookup_comment + tinycomments_lookup: lookup_comment, + tinycomments_fetch: fetch_comments // Optional callback }); ----- +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/tinycomments_edit_comment.adoc b/modules/ROOT/partials/configuration/tinycomments_edit_comment.adoc index 8decfe6e45..c2b94d42a1 100644 --- a/modules/ROOT/partials/configuration/tinycomments_edit_comment.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_edit_comment.adoc @@ -1,19 +1,16 @@ [[tinycomments_edit_comment]] == `+tinycomments_edit_comment+` -The Comments plugin uses the `+tinycomments_edit_comment+` function to edit a comment. +The {pluginname} plugin uses the `+tinycomments_edit_comment+` function to edit a comment. The `+tinycomments_edit_comment+` function allows updating or changing existing comments and returns via the `+done+` callback once successful. Unrecoverable errors are communicated to {productname} by calling the `+fail+` callback instead. The `+tinycomments_edit_comment+` function is given a request (req) object as the first parameter, which has these fields: -`+conversationUid+`:: The uid of the conversation the reply is targeting. - -`+commentUid+`:: The uid of the comment to edit (it can be the same as `+conversationUid+` if editing the first comment in a conversation). - -`+content+`:: The content of the comment to create. - -`+modifiedAt+`:: The date the comment was modified. +* `+conversationUid+`: The uid of the conversation the reply is targeting. +* `+commentUid+`: The uid of the comment to edit (it can be the same as `+conversationUid+` if editing the first comment in a conversation). +* `+content+`: The content of the comment to create. +* `+modifiedAt+`: The date the comment was modified. The `+done+` callback should accept the following object: @@ -25,8 +22,7 @@ The `+done+` callback should accept the following object: } ---- -For example: - +.For example: [source,js] ---- const edit_comment = (ref, done, fail) => { @@ -68,6 +64,7 @@ tinymce.init({ tinycomments_delete: delete_comment_thread, tinycomments_delete_all: delete_all_comment_threads, tinycomments_delete_comment: delete_comment, - tinycomments_lookup: lookup_comment + tinycomments_lookup: lookup_comment, + tinycomments_fetch: fetch_comments // Optional callback }); ---- diff --git a/modules/ROOT/partials/configuration/tinycomments_fetch.adoc b/modules/ROOT/partials/configuration/tinycomments_fetch.adoc new file mode 100644 index 0000000000..cf747c8ad8 --- /dev/null +++ b/modules/ROOT/partials/configuration/tinycomments_fetch.adoc @@ -0,0 +1,85 @@ +[[tinycomments_fetch]] +== `+tinycomments_fetch+` + +The {pluginname} plugin uses the `+tinycomments_fetch+` callback function retrieves multiple conversations based on their unique identifiers. + +The conventional conversation object structure that should be returned via the `+done+` callback is as follows: + +The `+tinycomments_fetch+` function is passed a (`+req+`) object as the first parameter, which contains the following key-value pair: + +* `+conversationUids+`: An array of strings representing the unique identifiers of the conversations to fetch. + +The `+done+` callback should accept the following object: + +[source,js] +---- +{ + conversations: { + [conversationUid: string]: { + uid: string, + comments: [ + { + uid: string, + author: string, + authorName?: string, + authorAvatar?: string, + content: string, + createdAt: string, // ISO 8601 date string + modifiedAt: string // ISO 8601 date string + }, + // ... more comments + ] + }, + // ... more conversations + } +} +---- + +.For example: +[source,js] +---- +const tinycomments_fetch = (conversationUids, done, fail) => { + const requests = conversationUids.map((uid) => fetch(`https://api.example/conversations/${uid}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }}) + .then((response) => response.json()) + .then((data) => ({ + [uid]: { + uid: uid, + comments: data + } + })) + ); + + Promise.all(requests) + .then((data) => { + console.log('data', data); + const conversations = data.reduce((conv, d) => ({ + ...conv, + ...d + }) + , {}); + console.log(`Fetch success ${conversationUids}`, conversations); + done({ conversations }); + }) + .catch((err) => { + console.error(`Fetch failure ${conversationUids}`, err); + fail('Fetching conversations failed'); + }); + +tinymce.init({ + selector: '#editor', + plugins: 'tinycomments', + tinycomments_mode: 'callback', + tinycomments_create: create_comment, + tinycomments_reply: reply_comment, + tinycomments_edit_comment: edit_comment, + tinycomments_delete: delete_comment_thread, + tinycomments_delete_all: delete_all_comment_threads, + tinycomments_delete_comment: delete_comment, + tinycomments_lookup: lookup_comment, + tinycomments_fetch: fetch_comments // Add the callback to TinyMCE +}); +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/tinycomments_lookup.adoc b/modules/ROOT/partials/configuration/tinycomments_lookup.adoc index 389bd4d390..10ae9595b3 100644 --- a/modules/ROOT/partials/configuration/tinycomments_lookup.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_lookup.adoc @@ -1,7 +1,7 @@ [[tinycomments_lookup]] == `+tinycomments_lookup+` -The Comments plugin uses the `+tinycomments_lookup+` function to retrieve an existing conversation using a conversation's unique ID. +The {pluginname} plugin uses the `+tinycomments_lookup+` function to retrieve one existing conversation using a conversation's unique ID. The *Display names* configuration must be considered for the `+tinycomments_lookup+` function: @@ -54,8 +54,7 @@ The author avatar feature is only available in {productname} 6.1 or higher and i * can be any filetype able to be wrapped in an `` element. ==== -For example: - +.For example: [source,js] ---- const lookup_comment = ({ conversationUid }, done, fail) => { @@ -110,6 +109,7 @@ tinymce.init({ tinycomments_delete: delete_comment_thread, tinycomments_delete_all: delete_all_comment_threads, tinycomments_delete_comment: delete_comment, - tinycomments_lookup: lookup_comment // Add the callback to TinyMCE + tinycomments_lookup: lookup_comment, // Add the callback to TinyMCE + tinycomments_fetch: fetch_comments // Optional callback }); ----- +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/tinycomments_mentions_enabled.adoc b/modules/ROOT/partials/configuration/tinycomments_mentions_enabled.adoc new file mode 100644 index 0000000000..45e0df05ce --- /dev/null +++ b/modules/ROOT/partials/configuration/tinycomments_mentions_enabled.adoc @@ -0,0 +1,29 @@ +[[tinycomments_mentions_enabled]] +== `+tinycomments_mentions_enabled+` + +The {pluginname} plugin offers the `+tinycomments_mentions_enabled+` option to control whether the xref:mentions.adoc[Mentions] plugin will be incorporated into the {pluginname} plugin, when both plugins are included in the configuration. + +*Type:* `+Boolean+` + +*Possible values:* `true`, `false` + +*Default value:* `true` + +=== Example: using `tinycomments_mentions_enabled` option + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // change this value according to your html + plugins: 'tinycomments mentions', + toolbar: 'addcomment showcomments', + tinycomments_mentions_enabled: true, + tinycomments_mode: 'embedded', + tinycomments_author: 'johnsmith', + tinycomments_author_name: 'John Smith', + mentions_fetch, + mentions_menu_complete, + mentions_menu_hover, + mentions_select +}); +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/tinycomments_reply.adoc b/modules/ROOT/partials/configuration/tinycomments_reply.adoc index 6f3b89ed10..99d0283433 100644 --- a/modules/ROOT/partials/configuration/tinycomments_reply.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_reply.adoc @@ -1,29 +1,28 @@ [[tinycomments_reply]] == `+tinycomments_reply+` -The Comments plugin uses the `+tinycomments_reply+` function to reply to a comment. +The {pluginname} plugin uses the `+tinycomments_reply+` function to reply to a comment. The `+tinycomments_reply+` function saves the comment as a reply to an existing conversation and returns via the `+done+` callback once successful. Unrecoverable errors are communicated to {productname} by calling the `+fail+` callback instead. The `+tinycomments_reply+` function is given a request (req) object as the first parameter, which has these fields: -`+conversationUid+`:: The uid of the conversation the reply is targeting. - -`+content+`:: The content of the comment to create. - -`+createdAt+`:: The date the comment was created. +* `+conversationUid+`: The uid of the conversation the reply is targeting. +* `+content+`: The content of the comment to create. +* `+createdAt+`: The date the comment was created (ISO 8601 date string) format. The `+done+` callback should accept the following object: [source,js] ---- { - commentUid: string // the value of the new comment uid + commentUid: string, // the new comment uid + author: string, // the id of the current author + authorName: string // the name of the current author } ---- -For example: - +.For example: [source,js] ---- const reply_comment = (ref, done, fail) => { @@ -45,7 +44,11 @@ const reply_comment = (ref, done, fail) => { }) .then((ref2) => { let commentUid = ref2.commentUid; - done({ commentUid: commentUid }); + done({ + commentUid: replyUid, + author: currentUser.id, + authorName: currentUser.fullName + }); }) .catch((e) => { fail(e); @@ -62,6 +65,7 @@ tinymce.init({ tinycomments_delete: delete_comment_thread, tinycomments_delete_all: delete_all_comment_threads, tinycomments_delete_comment: delete_comment, - tinycomments_lookup: lookup_comment + tinycomments_lookup: lookup_comment, + tinycomments_fetch: fetch_comments // Optional callback }); ----- +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/tinycomments_resolve.adoc b/modules/ROOT/partials/configuration/tinycomments_resolve.adoc index eabcf0305d..8b3c0ee555 100644 --- a/modules/ROOT/partials/configuration/tinycomments_resolve.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_resolve.adoc @@ -7,7 +7,7 @@ The `+tinycomments_resolve+` function should asynchronously return a flag indica The `+tinycomments_resolve+` function is passed a (`+req+`) object as the first parameter, which contains the following key-value pair: -`+conversationUid+`:: The uid of the conversation the reply is targeting. +* `+conversationUid+`: The uid of the targeting conversation The `+done+` callback should accept the following object: @@ -19,10 +19,10 @@ The `+done+` callback should accept the following object: } ---- -NOTE: Failure to resolve due to permissions or business rules should be indicated by `+canResolve: false+`, while unexpected errors should be indicated using the `+fail+` callback. - -For example: +[NOTE] +Failure to resolve due to permissions or business rules should be indicated by `+canResolve: false+`, while unexpected errors should be indicated using the `+fail+` callback. +.For example: [source,js] ---- const resolve_comment_thread = (ref, done, fail) => { @@ -51,6 +51,7 @@ tinymce.init({ tinycomments_delete: delete_comment_thread, tinycomments_delete_all: delete_all_comment_threads, tinycomments_delete_comment: delete_comment, - tinycomments_lookup: lookup_comment + tinycomments_lookup: lookup_comment, + tinycomments_fetch: fetch_comments }); ----- +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/uploadcare_cdn_base_url.adoc b/modules/ROOT/partials/configuration/uploadcare_cdn_base_url.adoc new file mode 100644 index 0000000000..e21808e46d --- /dev/null +++ b/modules/ROOT/partials/configuration/uploadcare_cdn_base_url.adoc @@ -0,0 +1,21 @@ +[[uploadcare-cdn-base-url]] +== `uploadcare_cdn_base_url` + +Specifies the domain used for the Uploadcare service. This domain determines where your files are uploaded and accessed. By default, the plugin uses the Uploadcare CDN `ucarecdn.com` to host and deliver your files. If you use a custom domain, update this option to match your configuration. + +*Type:* `+String+` + +*Default:* `+https://ucarecdn.com/+` + +=== Example: Customizing `uploadcare_cdn_base_url` + +[source,js] +---- +tinymce.init({ + selector: "textarea", + plugins: 'uploadcare', + toolbar: 'uploadcare', + uploadcare_public_key: '', + uploadcare_cdn_base_url: 'https://cdn.mydomain.com', +}); +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/uploadcare_public_key.adoc b/modules/ROOT/partials/configuration/uploadcare_public_key.adoc new file mode 100644 index 0000000000..97d032f693 --- /dev/null +++ b/modules/ROOT/partials/configuration/uploadcare_public_key.adoc @@ -0,0 +1,21 @@ +[[uploadcare-public-key]] +== `uploadcare_public_key` + +Defines the public API key required to authenticate and interact with the Uploadcare API. This key identifies your account and ensures that uploads and operations are associated with your project. Without setting this key, the Uploadcare integration will not function. + +[IMPORTANT] +This option is mandatory for using Uploadcare. + +*Type:* `+String+` + +=== Example: Setting `uploadcare_public_key` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'uploadcare', + toolbar: 'uploadcare', + uploadcare_public_key: '', +}); +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/uploadcare_signed_upload_auth_provider.adoc b/modules/ROOT/partials/configuration/uploadcare_signed_upload_auth_provider.adoc new file mode 100644 index 0000000000..7d760afd5f --- /dev/null +++ b/modules/ROOT/partials/configuration/uploadcare_signed_upload_auth_provider.adoc @@ -0,0 +1,37 @@ +[[uploadcare-signed-upload-auth-provider]] +== `uploadcare_signed_upload_auth_provider` + +Specifies a function used to generate secure signatures for authenticated requests to Uploadcare. This function is required when enabling Uploadcare's signed uploads feature, which ensures that only authorized users can upload files using your `uploadcare_public_key`. The function should return a `Promise` that resolves with an object containing the signature and expiration timestamp. + +Use this option to enforce secure uploads, preventing unauthorized users from uploading files via your application. + +*Type:* `+Function+` + +=== Example: Setting `uploadcare_signed_upload_auth_provider` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'uploadcare', + toolbar: 'uploadcare', + uploadcare_public_key: '', + uploadcare_signed_upload_auth_provider: (_publicKey) => Promise.resolve({ + signature: 'sig', + expire: 123 + }), +}); +---- + +[IMPORTANT] +==== +{companyname} recommends configuring the `uploadcare_signed_upload_auth_provider` option to secure uploads and prevent misuse of your Uploadcare `uploadcare_public_key`. This option is essential for applications requiring: + +* Prevention of unauthorized file uploads via your `uploadcare_public_key`. +* Enforcement of secure upload practices for application integrity. + +[NOTE] +This option **only** secures unauthorized access to upload files to the uploadcare storage by verifying signatures during uploads. + +For most integrations, enabling signed uploads by configuring this option ensures that only authorized uploads occur, reducing the risk of abuse and maintaining secure usage of your `uploadcare_public_key`. +==== diff --git a/modules/ROOT/partials/configuration/uploadcare_srcset_steps.adoc b/modules/ROOT/partials/configuration/uploadcare_srcset_steps.adoc new file mode 100644 index 0000000000..9def602a33 --- /dev/null +++ b/modules/ROOT/partials/configuration/uploadcare_srcset_steps.adoc @@ -0,0 +1,48 @@ +[[uploadcare-srcset-steps]] +== `uploadcare_srcset_steps` + +Specifies an array of numeric values representing the widths used to generate the `srcset` attribute for responsive images. This enables browsers to select the most suitable resolution based on the device’s display and network conditions. + +Customize this array to include **only** the widths required for your application. Reducing the number of resolutions can improve processing speed, while adding specific sizes can accommodate unique layout needs. + +*Type:* `+Array+` + +*Default:* `+[100, 200, 300, 500, 750, 1000, 1250, 1500, 2000, 2500, 3000]+` + +=== Example: Generated `srcset` Attribute with Custom Widths + +When an image is uploaded, its original width is used to create a `srcset` attribute with downscaled images for the defined widths. For instance, if the image width is 780 pixels and `uploadcare_srcset_steps` is set to `[100, 200, 300, 500, 750]`, the resulting `srcset` will look like this: + +.Example: Responsive 780px Image with Custom Widths in `srcset` +[source,html] +---- + +---- + +This ensures the browser selects the optimal image size based on the viewport and device characteristics, enhancing performance and user experience. On devices with narrower viewports, smaller images (e.g., 100w or 200w) will be prioritized, reducing bandwidth usage. + +=== Example: Customizing `uploadcare_srcset_steps` + +To customize the array, update the configuration as shown below: + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'uploadcare', + toolbar: 'uploadcare', + uploadcare_public_key: '', + uploadcare_srcset_steps: [100, 200, 300, 500, 750], +}); +---- diff --git a/modules/ROOT/partials/configuration/uploadcare_store_type.adoc b/modules/ROOT/partials/configuration/uploadcare_store_type.adoc new file mode 100644 index 0000000000..eb42668f69 --- /dev/null +++ b/modules/ROOT/partials/configuration/uploadcare_store_type.adoc @@ -0,0 +1,29 @@ +[[uploadcare-store-type]] +== `uploadcare_store_type` + +Specifies the storage type for uploaded files. Use this option to control whether files are stored temporarily or permanently, or allow Uploadcare to decide automatically based on your account settings. + +* `auto`: Uploadcare decides the storage type. +* `temporary`: Files are stored temporarily and will expire after a certain period. +* `permanent`: Files are stored permanently in your Uploadcare account. + +Select the appropriate value based on your application's requirements, such as whether files should persist for long-term use or be available for a limited time. + +*Type:* `+String+` + +*Default:* `permanent` + +*Possible values:* `auto`, `temporary`, `permanent` + +=== Example: Using `uploadcare_store_type` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', + plugins: 'uploadcare', + toolbar: 'uploadcare', + uploadcare_public_key: '', + uploadcare_store_type: 'permanent', +}); +---- \ No newline at end of file diff --git a/modules/ROOT/partials/events/a11ychecker-events.adoc b/modules/ROOT/partials/events/a11ychecker-events.adoc new file mode 100644 index 0000000000..a037dcdd8f --- /dev/null +++ b/modules/ROOT/partials/events/a11ychecker-events.adoc @@ -0,0 +1,9 @@ +[cols="1,1,2",options="header"] +|=== +|Name |Data |Description +|A11ycheckStart |N/A |Fired when the Accessibility Checker is `opened` +|A11ycheckStop |N/A |Fired when the Accessibility Checker is `closed` +|A11ycheckIgnore |N/A |Fired when the `Ignore` button is pressed +|A11ycheckRepair |N/A |Fired when the `Repair` button is pressed +|A11ycheckShowDetails |N/A |Fired when the `Click for more info` button is pressed +|=== \ No newline at end of file diff --git a/modules/ROOT/partials/index-pages/opensource-plugins.adoc b/modules/ROOT/partials/index-pages/opensource-plugins.adoc index 6d47dac8bf..751bc0c5f5 100644 --- a/modules/ROOT/partials/index-pages/opensource-plugins.adoc +++ b/modules/ROOT/partials/index-pages/opensource-plugins.adoc @@ -183,7 +183,7 @@ Show a word count in the {productname} status bar. // odd. // 2. Prepend the inline comment markup to this element // when the number of cells in the table is even. -//a| +a| |=== diff --git a/modules/ROOT/partials/index-pages/premium-plugins.adoc b/modules/ROOT/partials/index-pages/premium-plugins.adoc index 1d5a92f74b..3d76fe8cc5 100644 --- a/modules/ROOT/partials/index-pages/premium-plugins.adoc +++ b/modules/ROOT/partials/index-pages/premium-plugins.adoc @@ -99,12 +99,24 @@ xref:editimage.adoc[Image Editing] Image Editing features for {productname}. +a| +[.lead] +xref:uploadcare.adoc[Image Optimizer Powered by Uploadcare] + +Image optimization features for {productname}. + a| [.lead] xref:linkchecker.adoc[Link Checker] Validate links, as they are typed. +a| +[.lead] +xref:math.adoc[Math] + +Enable insertion of math formulas using Latex or MathML markup. + a| [.lead] xref:markdown.adoc[Markdown] @@ -189,7 +201,7 @@ Cloud-based file and image management for {productname}. // odd. // 2. Prepend the inline comment markup to this element // when the number of cells in the table is even. -// a| +a| |=== diff --git a/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-api-usage.adoc b/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-api-usage.adoc new file mode 100644 index 0000000000..f79a093ec6 --- /dev/null +++ b/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-api-usage.adoc @@ -0,0 +1,42 @@ +[[api-usage]] +== API Usage + +The {pluginname} On-Premises converter provides the ability to convert an HTML document to a PDF file via Restful API. + +The API is available on `+http://localhost:[port]+` (by default the `port` is `8080`). + +[NOTE] +The REST API documentation is available at `+http://localhost:[port]/docs+`. +Alternatively, refer to the specifications in link:https://exportpdf.api.tiny.cloud/docs[https://exportpdf.api.tiny.cloud/docs^]. + +If the authorization for the API is enabled, provided an authorization token. More instructions can be found in the xref:individual-export-to-pdf-on-premises.adoc#authorization[authorization] section. + +=== Using additional HTTP headers + +If fetching some resources (e.g. images) used in a generated PDF requires passing an additional authorization factor in the form of additional HTTP headers: + +. It can be defined on the application startup by setting `EXTRA_HTTP_HEADERS` environmental variable where the value is a stringified JSON object with required headers. +. It can be defined in a request sent to the PDF Converter API in `options`: + +[source, js, subs="attributes+"] +---- +const data = { + html: '

    I am a teapot

    ', + css: 'p { color: red; }', + options: { + extra_http_headers: { + authorization: 'Bearer ' + } + } +}; + +axios.post( '{exportpdf_service_url}', data, config ) + .then( response => { + fs.writeFileSync('./file.pdf', response.data, 'binary') + }).catch( error => { + console.log( error ); + }); +---- + +[TIP] +Headers defined in the application config and from the request are merged. If the same header is defined in both places, a header value from PDF options is prioritized over the value from the application config. \ No newline at end of file diff --git a/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-autorization.adoc b/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-autorization.adoc new file mode 100644 index 0000000000..eba8d6e67b --- /dev/null +++ b/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-autorization.adoc @@ -0,0 +1,97 @@ +[[authorization]] +== Authorization + +To enable authorization, set the `SECRET_KEY` environment variable during the xref:individual-export-to-pdf-on-premises.adoc#installation[installation]. + +If the `SECRET_KEY` variable is set, then all requests must have a header with a JWT (JSON Web Token) signed with this key. The token should be passed as a value of the `Authorization` header for each request sent to the {pluginname} REST API. + +[NOTE] +If the `SECRET_KEY` is not setup during the installation, then {pluginname} On-Premises will not require any headers with tokens when sending requests to the {pluginname} REST API. However, this it is not recommend to skip the authorization when running {pluginname} On-Premises in a public network. + +=== Generating the token + +{companyname} recommends using the libraries listed on link:http://jwt.io/[jwt.io] to generate the token. The token is considered valid, when: + +* it is signed with the same `SECRET_KEY` as passed to the {pluginname} On-Premises instance, +* it was created within the last 24 hours, +* it is not issued in the future (e.i. the iat timestamp cannot be newer than the current time), +* it has not expired yet. + + +If the specific use case involves sending requests from a backend server, then JWT tokens can be generated locally, as shown in the below request example. + +In the case of editor plugins or other frontend usages, a token endpoint should be created, that returns a valid JWT token for authorized users. + +.Example of a endpoint implementation. +[source, js] +---- +const express = require( 'express' ); +const jwt = require( 'jsonwebtoken' ); + +const SECRET_KEY = 'secret_key'; + +const app = express(); + +app.use( ( req, res, next ) => { + res.setHeader( 'Access-Control-Allow-Origin', '*' ); + res.setHeader( 'Access-Control-Allow-Methods', 'GET' ); + + next(); +}); + +app.get( '/', ( req, res ) => { + const result = jwt.sign( {}, SECRET_KEY, { algorithm: 'HS256' } ); + + res.send( result ); +}); + +app.listen( 8080, () => console.log( 'Listening on port 8080' ) ); +---- + +=== Using editor plugins + +Plugins for {productname} will automatically request the token from the given `tokenUrl` variable and set the `Authorization` header when making an export request. + +[NOTE] +Refer to the xref:exportpdf.adoc[{pluginname}] plugin documentation for details on adding the {pluginname} feature to the editor. + +=== Request example with an Authorization header + +The following example presents a request that generates valid JWT token and sets it as `Authorization` header: + +[source, js] +---- +const fs = require( 'fs' ); +const jwt = require( 'jsonwebtoken' ); +const axios = require( 'axios' ); + +const SECRET_KEY = 'secret'; + +const token = jwt.sign( {}, SECRET_KEY, { algorithm: 'HS256' } ); + +const data = { + html: "

    I am a teapot

    ", + css: "p { color: red; }", +}; + +const config = { + headers: { + 'Authorization': token + }, + responseType: 'arraybuffer', +}; + +axios.post( 'http://localhost:8080/v1/convert', data, config ) + .then( response => { + fs.writeFileSync('./file.pdf', response.data, 'binary'); + }).catch( error => { + console.log( error ); + }); +---- + +`SECRET_KEY` it’s the key which has been passed to the {pluginname} On-Premises instance + +Please refer to the link:https://exportpdf.api.tiny.cloud/docs[{pluginname} REST API documentation] to start using the service. + +[NOTE] +If API clients like Postman or Insomnia are used, then set the JWT token as an `Authorization` header in the `Headers` tab. Do not use the built-in token authorization as this will generate invalid header with a `Bearer` prefix added to the token. \ No newline at end of file diff --git a/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-fonts.adoc b/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-fonts.adoc new file mode 100644 index 0000000000..648b948eee --- /dev/null +++ b/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-fonts.adoc @@ -0,0 +1,65 @@ +[[fonts]] +== Fonts + +During document writing, the possibility of using many different fonts can be very important to users. + +Using the appropriate font can change the appearance of the document and emphasize its style. + +{pluginname} Converter allows link:https://exportpdf.api.tiny.cloud/docs#section/Web-Fonts[Web Fonts^] to be used, which provided the integrator with the ability to use standard operating system fonts or use custom fonts without the need to import them using CSS. + +Below is a list of the basic fonts included in the image: + +[source] +---- +OpenSans-Bold.ttf +OpenSans-BoldItalic.ttf +OpenSans-ExtraBold.ttf +OpenSans-ExtraBoldItalic.ttf +OpenSans-Italic.ttf +OpenSans-Light.ttf +OpenSans-LightItalic.ttf +OpenSans-Regular.ttf +OpenSans-Semibold.ttf +OpenSans-SemiboldItalic.ttf +---- + +However, additional fonts can be added to {pluginname} Converter in two ways: + +* Use Unix-like PDF-Converter image `{dockerimageexporttopdf}` and mount fonts directory to it. +** See xref:individual-export-to-pdf-on-premises.adoc#add-custom-fonts-to-pdf-converter[Add custom fonts to PDF Converter] section. +* Use Windows PDF-Converter image `{dockerimageexporttopdf}` and mount to it fonts directory from the Windows operating system on which the container is running. +** See Use Windows fonts in PDF Converter section. + +[NOTE] +The fonts inside the mounted volume will be installed on the docker image operating system. Only the `.ttf` and `.otf` font formats are supported. If other font formats are used, these will need to be converted to the supported format prior or use fonts such as link:https://exportpdf.api.tiny.cloud/docs#section/Web-Fonts[Web Fonts^]. + +[TIP] +Ensure that the converted fonts can be installed and used on your local machine first, before installing them on the docker container. + +[[add-custom-fonts-to-pdf-converter]] +=== Add custom fonts to PDF Converter + +If custom fonts are being used in PDF files, use the `pdf-converter-tiny` Docker image and mount the directory with the custom fonts for the PDF Converter application running on a machine with a Unix-like system (this includes Docker on Windows with a WSL backend). + +The `{dockerimageexporttopdf}` Docker image need to be run on a Unix-like operating system and mount the `~/your_fonts_dir:/usr/share/fonts/your_fonts_dir` volume. + +Launch the Docker container on Unix-like operating system example: + +[source, bash, subs="attributes+"] +---- +docker run --init -v ~/your_fonts_dir:/usr/share/fonts/your_fonts_dir -p 8080:8080 -e LICENSE_KEY=[your_license_key] {dockerimageexporttopdf}:[version] +---- + +[[use-windows-fonts-in-pdf-converter]] +=== Use Windows fonts in PDF Converter + +If using Windows fonts like Arial, Verdana, etc. in PDF files, use `pdf-converter-windows-tiny` Docker image that allows you to run the application on a machine with Windows operating system and mount fonts from the system. + +You just need to run `{dockerimageexporttopdf}` Docker image on Windows operating system and mount `C:\Windows\Fonts:C:\Windows\Fonts` volume. + +Launch the Docker container on Windows operating system example: + +[source, bash, subs="attributes+"] +---- +docker run -v C:\Windows\Fonts:C:\Windows\Fonts -p 8080:8080 --env LICENSE_KEY=[your_license_key] {dockerimageexporttopdfwindows}:[version] +---- \ No newline at end of file diff --git a/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-installation.adoc b/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-installation.adoc new file mode 100644 index 0000000000..45195b0e28 --- /dev/null +++ b/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-installation.adoc @@ -0,0 +1,98 @@ +[[installation]] +== Installation + +[NOTE] +A valid license key is needed in order to install {pluginname} On-Premises. +link:https://www.tiny.cloud/contact/[Contact us] for a trial license key. + +=== Supported technologies + +The application is provided as a docker image by default. + +It can be run with any Open Container runtime tool e.g. link:https://kubernetes.io/[Kubernetes], link:https://www.redhat.com/en/technologies/cloud-computing/openshift[OpenShift], link:https://podman.io/[Podman], link:https://docs.docker.com/[Docker] and many others. + +Refer to the xref:individual-export-to-pdf-on-premises.adoc#requirements[Requirements guide] for more information about the hardware and software requirements to run the {pluginname} On-Premises. + +=== Setting up the application using a Docker container + +. The username and password credentials supplied by Tiny are utilized for logging into the Docker registry and retrieving the Docker image. +. Containerize the application using `docker` or `docker-compose`. +. Use a demo page to verify if the application works properly. + +==== Containerize example using docker + +Login to Docker registry: + +[source, sh, subs="attributes+"] +---- +docker login -u [username] -p [password] registry.containers.tiny.cloud +---- + +Launch the Docker container: + +[source, sh, subs="attributes+"] +---- +docker run --init -p 8080:8080 -e LICENSE_KEY=[your_license_key] {dockerimageexporttopdf}:[version] +---- + +If using authorization provide the SECRET_KEY: + +[source, sh, subs="attributes+"] +---- +docker run --init -p 8080:8080 -e LICENSE_KEY=[your_license_key] -e SECRET_KEY=[your_secret_key] {dockerimageexporttopdf}:[version] +---- + +Read more about using authorization in the xref:individual-export-to-pdf-on-premises.adoc#authorization[authorization] section. + +==== Containerize example using docker-compose + +. Create the docker-compose.yml file: ++ +[source, yml, subs="attributes+"] +---- +version: "3.8" +services: + pdf-converter-tiny: + image: {dockerimageexporttopdf}:[version] + ports: + - "8080:8080" + restart: always + init: true + environment: + LICENSE_KEY: "license_key" + # Secret Key is optional + SECRET_KEY: "secret_key" + # Custom request origin is optional + CUSTOM_REQUEST_ORIGIN: "https://your_custom_origin" +---- ++ +For details on `SECRET_KEY` usage check the xref:individual-export-to-pdf-on-premises.adoc#authorization[authorization] section. ++ +. Run: + +[source, bash] +---- +docker-compose up +---- + +[NOTE] +==== +* Without a correct `LICENSE_KEY` the application will not start. +** If the license is invalid, a wrong license key error will display in the logs and the application will not run. +* It is advisable to override the SECRET_KEY variable using a unique and hard to guess string for security reasons. +* If the specific infrastructure has strict CORS enabled, then use the `CUSTOM_REQUEST_ORIGIN` variable to set the origin of requests made by the converter. The default value is `https://pdf-internal`. +==== + +=== Windows fonts support + +If using Windows fonts like Calibri, Verdana, etc. in PDF files, use the `pdf-converter-windows-tiny` Docker image and run it on a Windows operating system. + +See xref:individual-export-to-pdf-on-premises.adoc#fonts[Fonts] section for more details. + +=== Next steps + +Use the link:http://localhost:8080/v1/convert[http://localhost:8080/v1/convert] endpoint to export PDF files. Check out the xref:individual-export-to-pdf-on-premises.adoc#authorization[authorization] section to learn more about tokens and token endpoints. + +Use the demo page available on link:http://localhost:8080/demo[http://localhost:8080/demo] to generate an example PDF file. + +Refer to the {pluginname} REST API documentation on link:http://localhost:8080/docs[http://localhost:8080/docs] for more details. \ No newline at end of file diff --git a/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-logs.adoc b/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-logs.adoc new file mode 100644 index 0000000000..6a23a39e6d --- /dev/null +++ b/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-logs.adoc @@ -0,0 +1,212 @@ +[[logs]] +== Logs + +The logs from {pluginname} On-Premises are written to `stdout` and `stderr`. Most of them are formatted in JSON. They can be used for monitoring or debugging purposes. In production environments, It is recommend storing the logs to files or using a distributed logging system (like ELK or CloudWatch). + +=== Monitoring {pluginname} with logs + +To get more insight into how the {pluginname} On-Premises is performing, logs can be used for monitoring. To enable these, add the `ENABLE_METRIC_LOGS=true` environment variable. + +=== Log structure + +The log structure contains the following information: + +* `handler`: A unified identifier of action. Use this field to identify calls. +* `traceId`: A unique RPC call ID. +* `tags`: A semicolon-separated list of tags. Use this field to filter metrics logs. +* `data`: An object containing additional information. It might vary between different transports. +* `data.duration`: The request duration in milliseconds. +* `data.transport`: The type of the request transport. It could be http or ws (websocket). +* `data.status`: The request status. It can be equal to success, fail, warning. +* `data.statusCode`: The response status in HTTP status code standard. + +Additionally, for the HTTP transport, the following information is included: + +* `data.url`: The URL path. +* `data.method`: The request method. + +In case of an error, `data.status` will be equal to failed and `data.message` will contain the error message. + +An example log for HTTP transport: + +[source] +---- +{ + "level": 30, + "time": "2021-03-09T11:15:09.154Z", + "msg": "Request summary", + "handler": "convertHtmlToPdf", + "traceId": "85f13d92-57df-4b3b-98bb-0ca41a5ae601", + "data": { + "duration": 2470, + "transport": "http", + "statusCode": 200, + "status": "success", + "url": "/v1/convert", + "method": "POST" + }, + "tags": "metrics" +} +---- +// verify if this is something we will add. +//// +See example charts to check how to use logs for monitoring purposes. +//// + +=== Docker + +The docker has built-in logging mechanisms that capture logs from the output of the containers. The default logging driver writes the logs to files. + +When using this driver, use the `docker logs` command to show logs from a container. The `-f` flag can be added to view logs in real time. Refer to the link:https://docs.docker.com/engine/reference/commandline/logs/[official Docker documentation^] for more information about the logs command. + +[NOTE] +When a container is running for a long period of time, the logs can take up a lot of space. To avoid this problem, make sure that the log rotation is enabled. This can be set with the `max-size` option. + +=== Distributed logging + +If running more than one instance of {pluginname} On-Premises, It is recommend using a distributed logging system. It allows for viewing and analyzing logs from all instances in one place. + +==== AWS CloudWatch and other cloud solutions + +If running {pluginname} On-Premises in the cloud, the simplest and recommended way is to use a service that is available at the selected provider. + +Here are some of the available services: + +* AWS: link:https://aws.amazon.com/CloudWatch[CloudWatch^] +* Google Cloud: link:https://cloud.google.com/logging[Cloud Logging^] +* Azure: link:https://azure.microsoft.com/en-us/services/monitor/[Azure Monitor^] + +To use CloudWatch with AWS ECS, a log group must be created before, and the log driver must be changed to `awslogs`. When the log driver is configured properly, logs will be streamed directly to CloudWatch. + +The `logConfiguration` may look similar to this: + +[source, json] +---- +"logConfiguration": { + "logDriver": "awslogs", + "options": { + "awslogs-region": "us-west-2", + "awslogs-group": "tinysource", + "awslogs-stream-prefix": "tiny-pdf-converter-logs" + } +} +---- + +Refer to the link:https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_awslogs.html[Using the awslogs Log Driver] article for more information. + +=== On-Premises solutions + +If using a specific infrastructure such as your own or for some reason cannot use the service offered by a provider, some on-premises distributed logging system can be used. + +There are a lot of solutions available, including: + +* link:https://www.elastic.co/what-is/elk-stack[ELK^] + link:https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-getting-started.html[Filebeat^] + +This is a stack built on top of Elasticsearch, Logstash and Kibana. In this configuration, Elasticsearch stores logs, Filebeat reads logs from Docker and sends them to Elasticsearch, and Kibana is used to view them. Logstash is not necessary because logs are already structured. + +* link:https://www.fluentd.org/[Fluentd^] + +It uses a dedicated link:https://docs.docker.com/config/containers/logging/fluentd[Docker log driver^] to send the logs. It has a built-in frontend, but can also be integrated with Elasticsearch and Kibana for better filtering. + +* link:https://www.graylog.org/[Graylog^] + +It uses a dedicated link:https://docs.docker.com/config/containers/logging/gelf[Docker^] log driver to send the logs. It has a built-in frontend and needs Elasticsearch to store the logs as well as a MongoDB database to store the configuration. + +==== Example configuration + +The example configuration uses Fluentd, Elasticsearch, and Kibana to capture logs from Docker. + +Before running {pluginname} On-Premises, prepare the logging services. For the purposes of this example, Docker Compose is used. Create the fluentd, elasticsearch and kibana services inside the docker-compose.yml file: + +[source, yaml] +---- +version: '3.7' +services: + fluentd: + build: ./fluentd + volumes: + - ./fluentd/fluent.conf:/fluentd/etc/fluent.conf + ports: + - "24224:24224" + - "24224:24224/udp" + + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:6.8.5 + expose: + - 9200 + ports: + - "9200:9200" + + kibana: + image: docker.elastic.co/kibana/kibana:6.8.5 + environment: + ELASTICSEARCH_HOSTS: "http://elasticsearch:9200" + ports: + - "5601:5601" +---- + +To integrate Fluentd with Elasticsearch, first install `fluent-plugin-elasticsearch` in the Fluentd image. To do this, create a `fluentd/Dockerfile` with the following content: + +[source, dockerfile] +---- +FROM fluent/fluentd:v1.10-1 + +USER root + +RUN apk add --no-cache --update build-base ruby-dev \ + && gem install fluent-plugin-elasticsearch \ + && gem sources --clear-all +---- + +Next, configure the input server and connection to Elasticsearch in the `fluentd/fluent.conf` file: + +[source, xml] +---- + + @type forward + port 24224 + bind 0.0.0.0 + + + @type copy + + @type elasticsearch + host elasticsearch + port 9200 + logstash_format true + logstash_prefix fluentd + logstash_dateformat %Y%m%d + include_tag_key true + type_name access_log + tag_key @log_name + flush_interval 1s + + + @type stdout + + +---- + +The services are now ready to run: + +[source, bash] +---- +docker-compose up --build +---- + +When the services are ready, start {pluginname} On-Premises. + +[source, bash, subs="attributes+"] +---- +docker run --init -p 8080:8080 \ +--log-driver=fluentd \ +--log-opt fluentd-address=[Fluentd address]:24224 \ +[Your config here] \ +{dockerimageexporttopdf}:[version] +---- + +* Open Kibana in your browser. +** It is available at link:http://localhost:5601/[http://localhost:5601/]. +* During the first run, you may be asked about creating an index. +* Use the `fluentd-*` pattern and press the “Create” button. +* After this step, the logs should appear in the “Discover” tab. \ No newline at end of file diff --git a/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-overview.adoc b/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-overview.adoc new file mode 100644 index 0000000000..578111b725 --- /dev/null +++ b/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-overview.adoc @@ -0,0 +1,10 @@ +[[overview]] +== Overview + +The On-Premises version of the {pluginname} Converter is an application that can be installed and run on the customer’s in-house servers and computing infrastructure, including a private cloud. It contains all the features of the {pluginname} Converter available as SaaS. + +A valid license key is required in order to install {pluginname} Converter On-Premises. +link:https://www.tiny.cloud/contact/[Contact us] for a trial license key. + + +The only requirement to run {pluginname} On-Premises is a container runtime or orchestration tool e.g. Docker, Kubernetes, Podman. \ No newline at end of file diff --git a/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-requirements.adoc b/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-requirements.adoc new file mode 100644 index 0000000000..e7dc513c9e --- /dev/null +++ b/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-requirements.adoc @@ -0,0 +1,23 @@ +[[requirements]] +== Requirements + +To run {pluginname} On-Premises a Docker environment is required. Alternatively, use CaaS available from your cloud provider, like AWS ECS, Google GKE, or Azure ACS. + +There are many factors affecting {pluginname} On-Premises performance. The most influential are the size of exported content, the size of images, and the number of concurrent requests. Also, because your application can prioritize fast response times, or it should handle high load, it is impossible to provide one recommended server specification, that will fit all use cases. + +Assuming response time below 10 seconds, one server (2CPU 2GB RAM) with 1 docker container can handle: + +* up to 40 concurrent requests with an average content of 1 A4 page (~1k characters and 1 image) +* up to 25 concurrent requests with an average content of 5 A4 pages (~7,5k characters and 5 images) +* up to 10 concurrent requests with an average content of 20 A4 pages (~30k characters and 20 images) + +[NOTE] +The above concurrent requests numbers are not a hard limit of {pluginname} On-Premises instance. It can handle more concurrent requests, but the response time will be longer. + +=== High availability + +One docker container with {pluginname} On-Premises benefits from additional CPUs on the machine. To scale your app on a single machine, increase the number of CPUs, however, {companyname} recommends scaling on at least three hosts to ensure the reliability of the system. + +A load balancer, like HAProxy or NGINX (see the load balancer configuration examples in the SSL communication guide), is required for scaling on several machines. Of course, it is possible to use any cloud provider for scaling, like Amazon ECS, Azure Container Instances, or Kubernetes. + +link:https://www.tiny.cloud/contact/[Contact us] if you have any questions about server resources needed for your use case of {pluginname} On-Premises. \ No newline at end of file diff --git a/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-ssl-communication.adoc b/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-ssl-communication.adoc new file mode 100644 index 0000000000..193cb88f60 --- /dev/null +++ b/modules/ROOT/partials/individually-licensed-components/export-to-pdf/export-to-pdf-ssl-communication.adoc @@ -0,0 +1,68 @@ +[[ssl-communication]] +== SSL Communication + +Its possible to communicate with {pluginname} On-Premises using secure connections. To achieve this, the load balancer like `NGINX` or `HAProxy` needs to be setup with your SSL certificate. + +`HAProxy` and `NGINX` configuration examples below. + +=== HAProxy example + +Here is a basic `HAProxy` configuration: + +[source, nginx] +---- +global + daemon + maxconn 256 + tune.ssl.default-dh-param 2048 + +defaults + mode http + timeout connect 5000ms + timeout client 50000ms + timeout server 50000ms + +frontend http-in + bind *:80 + bind *:443 ssl crt /etc/ssl/your_certificate.pem + http-request set-header X-Forwarded-Proto https if { ssl_fc } + http-request set-header X-Forwarded-Proto http if !{ ssl_fc } + redirect scheme https if !{ ssl_fc } + + default_backend servers + +backend servers + server server1 127.0.0.1:8000 maxconn 32 +---- + +=== NGINX example + +Here is a basic `NGINX` configuration: + +[source, nginx] +---- +events { + worker_connections 1024; +} + +http { + server { + server_name your.domain.name; + + listen 443; + ssl on; + ssl_certificate /etc/ssl/your_cert.crt; + ssl_certificate_key /etc/ssl/your_cert_key.key; + + location / { + proxy_pass http://127.0.0.1:8000; + + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_http_version 1.1; + } + } +} +---- \ No newline at end of file diff --git a/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-api-usage-on-premises.adoc b/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-api-usage-on-premises.adoc new file mode 100644 index 0000000000..425460082d --- /dev/null +++ b/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-api-usage-on-premises.adoc @@ -0,0 +1,15 @@ +[[api-usage]] +== API usage + +{pluginname} On-Premises consists of two services: + +* xref:exportword.adoc[Export to Word] provides conversion from an HTML document to a `.docx` file via Restful API. +* xref:importword.adoc[Import from Word] allows importing `.docx` file and converting it into a styled HTML document with comments and suggestions attached. + +The API is available on `+http://localhost:[port]+` (by default the port is 8080). + +[NOTE] +The REST API documentation is available at `+http://localhost:[port]/v2/convert/docs+`. +Alternatively you can check specification in our public resources for link:https://importdocx.api.tiny.cloud/v2/convert/docs#section/Import-from-Word[Import from Word^] and the link:https://exportdocx.api.tiny.cloud/v2/convert/docs#section/Export-to-Word[Export to Word^] plugins. + +If you have the authorization for the API enabled, you should provide an authorization token. More instructions you can find in the authorization section. \ No newline at end of file diff --git a/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-autorization-on-premises.adoc b/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-autorization-on-premises.adoc new file mode 100644 index 0000000000..093bc075ec --- /dev/null +++ b/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-autorization-on-premises.adoc @@ -0,0 +1,69 @@ +[[authorization]] +== Authorization + +To enable authorization, set the `SECRET_KEY` environment variable during the xref:individual-import-from-word-and-export-to-word-on-premises.adoc#installation[installation]. + +If the `SECRET_KEY` variable is set, then all requests must have a header with a JWT (JSON Web Token) signed with this key. The token should be passed as a value of the `Authorization` header for each request sent to the {pluginname} REST API. + +[NOTE] +If the `SECRET_KEY` is not setup during the installation, then {pluginname} On-Premises will not require any headers with tokens when sending requests to the {pluginname} REST API. However, this it is not recommend to skip the authorization when running {pluginname} On-Premises in a public network. + +=== Generating the token + +{companyname} recommends using the libraries listed on link:http://jwt.io/[jwt.io] to generate the token. The token is considered valid, when: + +* it is signed with the same `SECRET_KEY` as passed to the {pluginname} On-Premises instance, +* it was created within the last 24 hours, +* it is not issued in the future (e.i. the `iat` timestamp cannot be newer than the current time), +* it has not expired yet. + +Tokens for the {pluginname} On-Premises do not require any additional claims such as the environment ID (which is specific for Collaboration Server On-Premises), the token can be created with an empty payload. + +If the specific use case involves sending requests from a backend server, then JWT tokens can be generated locally, as shown in the below request example. + +In the case of editor plugins or other frontend usages, a token endpoint should be created, that returns a valid JWT token for authorized users. + +=== Using editor plugins + +The are are two plugins available for {productname}: the xref:importword.adoc[Import from Word] and the xref:exportword.adoc[Export to Word] plugins. The plugins will automatically request the token from the given `tokenUrl` variable and will set the `Authorization` header when making an export request. Refer to the respective guides for details on adding the {pluginname} features to your WYSIWYG editor! + +=== Request example with an Authorization header + +The following example presents a request that generates a valid JWT token and sets it as an `Authorization` header: + +[source, js] +---- +const fs = require( 'fs' ); +const jwt = require( 'jsonwebtoken' ); +const axios = require( 'axios' ); + +const SECRET_KEY = 'secret'; + +const token = jwt.sign( {}, SECRET_KEY, { algorithm: 'HS256' } ); + +const data = { + html: "

    I am a teapot

    ", + css: "p { color: red; }", +}; + +const config = { + headers: { + Authorization: token + }, + responseType: 'arraybuffer', +}; + +axios.post( 'http://localhost:8080/v2/convert/html-docx', data, config ) + .then( response => { + fs.writeFileSync('./file.docx', response.data, 'binary'); + } ).catch( error => { + console.log( error ); + } ); +---- + +`SECRET_KEY`: This is the key what has been passed to the {pluginname} On-Premises instance. + +Please refer to the link:https://importdocx.api.tiny.cloud/v2/convert/docs#section/Import-from-Word[Import from Word^] and the link:https://exportdocx.api.tiny.cloud/v2/convert/docs#section/Export-to-Word[Export to Word^] REST API documentation to start using the service. + +[NOTE] +If API clients like Postman or Insomnia are used, then set the JWT token as an `Authorization` header in the `Headers` tab. Do not use the built-in token authorization as this will generate invalid header with a `Bearer` prefix added to the token. \ No newline at end of file diff --git a/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-installation-on-premises.adoc b/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-installation-on-premises.adoc new file mode 100644 index 0000000000..1888f97a9a --- /dev/null +++ b/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-installation-on-premises.adoc @@ -0,0 +1,89 @@ +[[installation]] +== Installation + +[NOTE] +A valid license key is needed in order to install {pluginname} On-Premises. +link:https://www.tiny.cloud/contact/[Contact us] for a trial license key. + +=== Supported technologies + +The application is provided as a docker image by default. + +It can be run with any Open Container runtime tool e.g. link:https://kubernetes.io/[Kubernetes], link:https://www.redhat.com/en/technologies/cloud-computing/openshift[OpenShift], link:https://podman.io/[Podman], link:https://docs.docker.com/[Docker] and many others. + +Refer to the xref:individual-import-from-word-and-export-to-word-on-premises.adoc#requirements[Requirements guide] for more information about the hardware and software requirements to run the {pluginname} On-Premises. + +=== Setting up the application using a Docker container + +. The username and password credentials supplied by Tiny are utilized for logging into the Docker registry and retrieving the Docker image. +. Containerize the application using `docker` or `docker-compose`. +. Use a demo page to verify if the application works properly. + +==== Containerize example using docker + +Login to Docker registry: + +[source, sh, subs="attributes+"] +---- +docker login -u [username] -p [password] registry.containers.tiny.cloud +---- + +Launch the Docker container: + +[source, sh, subs="attributes+"] +---- +docker run --init -p 8080:8080 -e LICENSE_KEY=[your_license_key] {dockerimageimportfromwordexporttoword}:[version] +---- + +If using authorization provide the SECRET_KEY: + +[source, sh, subs="attributes+"] +---- +docker run --init -p 8080:8080 -e LICENSE_KEY=[your_license_key] -e SECRET_KEY=[your_secret_key] {dockerimageimportfromwordexporttoword}:[version] +---- + +Read more about using authorization in the xref:individual-import-from-word-and-export-to-word-on-premises.adoc#authorization[authorization] section. + +==== Containerize example using docker-compose + +. Create the docker-compose.yml file: ++ +[source, yml, subs="attributes+"] +---- +version: "3.8" +services: + doc-converter: + image: {dockerimageimportfromwordexporttoword}:[version] + ports: + - "8080:8080" + restart: always + init: true + environment: + LICENSE_KEY: "licensekey" + # Secret Key is optional + SECRET_KEY: "secret_key" +---- ++ +For details on `SECRET_KEY` usage check the xref:individual-import-from-word-and-export-to-word-on-premises.adoc#authorization[authorization] section. ++ +. Run: + +[source, bash] +---- +docker-compose up +---- + +[NOTE] +==== +* Without a correct `LICENSE_KEY` the application will not start. +** If the license is invalid, a wrong license key error will display in the logs and the application will not run. +* It is advisable to override the `SECRET_KEY` variable using a unique and hard to guess string for security reasons. +==== + +=== Next steps + +Use the link:http://localhost:8080/v2/convert/html-docx[http://localhost:8080/v2/convert/html-docx] endpoint to export DOCX files. Check out the xref:individual-import-from-word-and-export-to-word-on-premises.adoc#authorization[authorization] section to learn more about tokens and token endpoints. + +Use the demo page available on link:http://localhost:8080/demo[http://localhost:8080/demo] to generate an example DOCX file. + +Refer to the {pluginname} REST API documentation on link:http://localhost:8080/docs[http://localhost:8080/docs] for more details. \ No newline at end of file diff --git a/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-logs-on-premises.adoc b/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-logs-on-premises.adoc new file mode 100644 index 0000000000..40c33a8887 --- /dev/null +++ b/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-logs-on-premises.adoc @@ -0,0 +1,208 @@ +[[logs]] +== Logs + +The logs from {pluginname} On-Premises are written to `stdout` and `stderr`. Most of them are formatted in JSON. They can be used for monitoring or debugging purposes. In production environments, It is recommend storing the logs to files or using a distributed logging system (like ELK or CloudWatch). + +=== Monitoring {pluginname} with logs + +To get more insight into how the {pluginname} On-Premises is performing, logs can be used for monitoring. To enable these, add the `ENABLE_METRIC_LOGS=true` environment variable. + +=== Log structure + +The log structure contains the following information: + +* `handler`: A unified identifier of action. Use this field to identify calls. +* `traceId`: A unique RPC call ID. +* `tags`: A semicolon-separated list of tags. Use this field to filter metrics logs. +* `data`: An object containing additional information. It might vary between different transports. +* `data.duration`: The request duration in milliseconds. +* `data.transport`: The type of the request transport. It could be http or ws (websocket). +* `data.status`: The request status. It can be equal to success, fail, warning. +* `data.statusCode`: The response status in HTTP status code standard. + +Additionally, for the HTTP transport, the following information is included: + +* `data.url`: The URL path. +* `data.method`: The request method. + +In case of an error, `data.status` will be equal to `failed` and `data.message` will contain the error message. + +An example log for HTTP transport: + +[source] +---- +{ + "level": 30, + "time": "2021-03-09T11:15:09.154Z", + "msg": "Request summary", + "handler": "postConvert", + "traceId": "85f13d92-57df-4b3b-98bb-0ca41a5ae601", + "data": { + "duration": 752, + "transport": "http", + "statusCode": 200, + "status": "success", + "url": "/v2/convert/html-docx", + "method": "POST" + }, + "tags": "metrics" +} +---- + +=== Docker + +The docker has built-in logging mechanisms that capture logs from the output of the containers. The default logging driver writes the logs to files. + +When using this driver, use the `docker logs` command to show logs from a container. Use the `-f` flag to view logs in real time. Refer to the link:https://docs.docker.com/engine/reference/commandline/logs/[official Docker documentation] for more information about the logs command. + +[NOTE] +When a container is running for a long period of time, the logs can take up a lot of space. To avoid this problem, you should make sure that the log rotation is enabled. This can be set with the `max-size` option. + +=== Distributed logging + +If running more than one instance of {pluginname} On-Premises, It is recommend using a distributed logging system. It allows for viewing and analyzing logs from all instances in one place. + +=== AWS CloudWatch and other cloud solutions + +If running {pluginname} On-Premises in the cloud, the simplest and recommended way is to use a service that is available at the selected provider. + +Here are some of the available services: + +* AWS: link:https://aws.amazon.com/CloudWatch[CloudWatch^] +* Google Cloud: link:https://cloud.google.com/logging[Cloud Logging^] +* Azure: link:https://azure.microsoft.com/en-us/services/monitor/[Azure Monitor^] + +To use CloudWatch with AWS ECS, a log group must be created before, and the log driver must be changed to `awslogs`. When the log driver is configured properly, logs will be streamed directly to CloudWatch. + +The `logConfiguration` may look similar to this: + +[source, json] +---- +"logConfiguration": { + "logDriver": "awslogs", + "options": { + "awslogs-region": "us-west-2", + "awslogs-group": "tinysource", + "awslogs-stream-prefix": "tiny-docx-converter-logs" + } +} +---- + +Refer to the link:https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_awslogs.html[Using the awslogs Log Driver] article for more information. + +=== On-Premises solutions + +If using a specific infrastructure such as your own or for some reason cannot use the service offered by a provider, some on-premises distributed logging system can be used. + +There are a lot of solutions available, including: + +* link:https://www.elastic.co/what-is/elk-stack[ELK^] + link:https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-getting-started.html[Filebeat^] + +This is a stack built on top of Elasticsearch, Logstash and Kibana. In this configuration, Elasticsearch stores logs, Filebeat reads logs from Docker and sends them to Elasticsearch, and Kibana is used to view them. Logstash is not necessary because logs are already structured. + +* link:https://www.fluentd.org/[Fluentd^] + +It uses a dedicated link:https://docs.docker.com/config/containers/logging/fluentd[Docker log driver^] to send the logs. It has a built-in frontend, but can also be integrated with Elasticsearch and Kibana for better filtering. + +* link:https://www.graylog.org/[Graylog^] + +It uses a dedicated link:https://docs.docker.com/config/containers/logging/gelf[Docker^] log driver to send the logs. It has a built-in frontend and needs Elasticsearch to store the logs as well as a MongoDB database to store the configuration. + +==== Example configuration + +The example configuration uses Fluentd, Elasticsearch and Kibana to capture logs from Docker. + +Before running {pluginname} On-Premises, prepare the logging services. For the purposes of this example, Docker Compose is used. Create the `fluentd`, `elasticsearch` and `kibana` services inside the `docker-compose.yml` file: + +[source, yaml] +---- +version: '3.7' +services: + fluentd: + build: ./fluentd + volumes: + - ./fluentd/fluent.conf:/fluentd/etc/fluent.conf + ports: + - "24224:24224" + - "24224:24224/udp" + + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:6.8.5 + expose: + - 9200 + ports: + - "9200:9200" + + kibana: + image: docker.elastic.co/kibana/kibana:6.8.5 + environment: + ELASTICSEARCH_HOSTS: "http://elasticsearch:9200" + ports: + - "5601:5601" +---- + +To integrate Fluentd with Elasticsearch, you first need to install `fluent-plugin-elasticsearch` in the Fluentd image. To do this, create a `fluentd/Dockerfile` with the following content: + +[source, dockerfile] +---- +FROM fluent/fluentd:v1.10-1 + +USER root + +RUN apk add --no-cache --update build-base ruby-dev \ + && gem install fluent-plugin-elasticsearch \ + && gem sources --clear-all +---- + +Next, configure the input server and connection to Elasticsearch in the `fluentd/fluent.conf` file: + +[source, xml] +---- + + @type forward + port 24224 + bind 0.0.0.0 + + + @type copy + + @type elasticsearch + host elasticsearch + port 9200 + logstash_format true + logstash_prefix fluentd + logstash_dateformat %Y%m%d + include_tag_key true + type_name access_log + tag_key @log_name + flush_interval 1s + + + @type stdout + + +---- + +The services are now ready to run: + +[source, bash] +---- +docker-compose up --build +---- + +When the services are ready, start the {pluginname} On-Premises. + +[source, bash, subs="attributes+"] +---- +docker run --init -p 8080:8080 \ +--log-driver=fluentd \ +--log-opt fluentd-address=[Fluentd address]:24224 \ +[Your config here] \ +{dockerimageimportfromwordexporttoword}:[version] +---- + +* Open Kibana in your browser. +** It is available at link:http://localhost:5601/[http://localhost:5601/]. +* During the first run, you may be asked about creating an index. +* Use the `fluentd-*` pattern and press the “Create” button. +* After this step, the logs should appear in the “Discover” tab. \ No newline at end of file diff --git a/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-overview-on-premises.adoc b/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-overview-on-premises.adoc new file mode 100644 index 0000000000..c6f59f086d --- /dev/null +++ b/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-overview-on-premises.adoc @@ -0,0 +1,10 @@ +[[overview]] +== Overview + +{pluginname} is a set of two converter services that allow for both exporting a structured HTML content (e.g. created with {productname} WYSIWYG editor) into a `.docx` Microsoft Word file and for importing content from `.docx` and `.dotx` files and converting it into a styled HTML document. + +A valid license key is needed in order to install {pluginname} On-Premises. link:https://www.tiny.cloud/contact/[Contact us] for a trial license key. + +The documentation in this section refers to a simplified version of the {pluginname} On-Premises which was designed to be easy to set up and maintain (while preserving all the features). It also lowers the running costs by reducing the number of servers required to run the whole application to the minimum. + +The only requirement to run {pluginname} On-Premises is a container runtime or orchestration tool e.g. Docker, Kubernetes, Podman. \ No newline at end of file diff --git a/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-requirements-on-premises.adoc b/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-requirements-on-premises.adoc new file mode 100644 index 0000000000..b315d08898 --- /dev/null +++ b/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-requirements-on-premises.adoc @@ -0,0 +1,23 @@ +[[requirements]] +== Requirements + +To run {pluginname} On-Premises, a Docker environment is required. Alternatively, use a CaaS available from your cloud provider, such as AWS ECS, Google GKE or Azure ACS. + +There are many factors that may affect Export to Word On-Premises performance. The most influential are: the size of exported content, the size of images, and the number of concurrent requests. Also, because your application can prioritize fast response times, or it should handle high load, it is impossible to provide one recommended server specification, that will fit all use cases. + +Assuming response time below 10 seconds, one server (2CPU 2GB RAM) with 1 docker container can handle: + +* up to 45 concurrent requests with an average content of 1 A4 page (~1k characters) +* up to 30 concurrent requests with an average content of 5 A4 pages (~7,5k characters) +* up to 10 concurrent requests with an average content of 20 A4 pages (~30k characters) + +[NOTE] +The listed concurrent requests numbers are not a hard limit of a {pluginname} On-Premises instance. It can handle more concurrent requests, but the response time will be longer. + +=== High availability + +One docker container with {pluginname} On-Premises benefits from additional CPUs on the machine. It is recommended that 2 CPUs are allocated for every docker container. To scale your app on a single machine, increase the number of CPUs and docker containers, however, {productname} recommends scaling on at least three hosts to ensure the reliability of the system. + +A load balancer, like HAProxy or NGINX (see the load balancer configuration examples in the SSL communication guide), is required for scaling on several machines. Of course, it is possible to use any cloud provider for scaling, like Amazon ECS, Azure Container Instances or Kubernetes. + +link:https://www.tiny.cloud/contact/[Contact us] if you have any questions about server resources needed for your use case of {pluginname} On-Premises. \ No newline at end of file diff --git a/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-ssl-communication-on-premises.adoc b/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-ssl-communication-on-premises.adoc new file mode 100644 index 0000000000..83c159e7f6 --- /dev/null +++ b/modules/ROOT/partials/individually-licensed-components/import-from-word-and-export-to-word/import-from-word-and-export-to-word-ssl-communication-on-premises.adoc @@ -0,0 +1,68 @@ +[[sll-communication]] +== SSL Communication + +Its possible to communicate with {pluginname} On-Premises using secure connections. To achieve this, the load balancer like `NGINX` or `HAProxy` needs to be setup with your SSL certificate. + +`HAProxy` and `NGINX` configuration examples below. + +=== HAProxy example + +Here is a basic `HAProxy` configuration: + +[source, nginx] +---- +global + daemon + maxconn 256 + tune.ssl.default-dh-param 2048 + +defaults + mode http + timeout connect 5000ms + timeout client 50000ms + timeout server 50000ms + +frontend http-in + bind *:80 + bind *:443 ssl crt /etc/ssl/your_certificate.pem + http-request set-header X-Forwarded-Proto https if { ssl_fc } + http-request set-header X-Forwarded-Proto http if !{ ssl_fc } + redirect scheme https if !{ ssl_fc } + + default_backend servers + +backend servers + server server1 127.0.0.1:8000 maxconn 32 +---- + +=== NGINX example + +Here is a basic NGINX configuration: + +[source, nginx] +---- +events { + worker_connections 1024; +} + +http { + server { + server_name your.domain.name; + + listen 443; + ssl on; + ssl_certificate /etc/ssl/your_cert.crt; + ssl_certificate_key /etc/ssl/your_cert_key.key; + + location / { + proxy_pass http://127.0.0.1:8000; + + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_http_version 1.1; + } + } +} +---- \ No newline at end of file diff --git a/modules/ROOT/partials/integrations/angular-quick-start.adoc b/modules/ROOT/partials/integrations/angular-quick-start.adoc index 90bd0a0615..76d2c8b6b4 100644 --- a/modules/ROOT/partials/integrations/angular-quick-start.adoc +++ b/modules/ROOT/partials/integrations/angular-quick-start.adoc @@ -1,6 +1,8 @@ :packageName: tinymce-angular -The https://github.com/tinymce/tinymce-angular[Official {productname} Angular component] integrates {productname} into Angular projects. This procedure creates a https://angular.io/guide/setup-local[basic Angular application] containing a {productname} editor. +The https://github.com/tinymce/tinymce-angular[Official {productname} Angular component] integrates {productname} into Angular projects. This procedure creates a https://angular.dev/tools/cli/setup-local[basic Angular application] containing a {productname} editor. + +This procedure uses standalone components. If using Angular Modules, see xref:angular-modules[Angular Modules]. For examples of the {productname} Angular integration, visit https://tinymce.github.io/tinymce-angular/[the tinymce-angular storybook]. @@ -45,44 +47,36 @@ ifeval::["{productSource}" != "package-manager"] npm install --save @tinymce/tinymce-angular ---- endif::[] -. Using a text editor, open `+/path/to/tinymce-angular-demo/src/app/app.module.ts+` and replace the contents with: -+ -[source,ts] ----- -import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; -import { EditorModule } from '@tinymce/tinymce-angular'; -import { AppComponent } from './app.component'; - -@NgModule({ - declarations: [ - AppComponent - ], - imports: [ - BrowserModule, - EditorModule - ], - providers: [], - bootstrap: [AppComponent] +. Using a text editor, open `+/path/to/tinymce-angular-demo/src/app/app.component.ts+` and replace the contents with: ++ +[source,ts,subs="attributes+"] +---- +import { Component } from '@angular/core'; +import { EditorComponent } from '@tinymce/tinymce-angular'; + +@Component({ + selector: 'app-root', + standalone: true, + imports: [EditorComponent], + template: ` +

    {productname} {productmajorversion} Angular Demo

    + + ` }) -export class AppModule { } +export class AppComponent { + init: EditorComponent['init'] = { + plugins: 'lists link image table code help wordcount' + }; +} ---- -. Using a text editor, open `+/path/to/tinymce-angular-demo/src/app/app.component.html+` and replace the contents with: -+ -[source,tsx,subs="attributes+"] ----- -

    {productname} {productmajorversion} Angular Demo

    - ----- - ifeval::["{productSource}" == "cloud"] . Include the `+apiKey+` option in the editor element and include your link:{accountsignup}/[{cloudname} API key]. Such as: + [source,tsx] ---- - + ---- endif::[] ifeval::["{productSource}" == "package-manager"] @@ -96,17 +90,16 @@ ifeval::["{productSource}" == "package-manager"] ---- . Load TinyMCE. -* To load TinyMCE when the editor is initialized (also known as lazy loading), add a dependency provider to the module using the `+TINYMCE_SCRIPT_SRC+` token. +* To load {productname} when the editor is initialized (also known as lazy loading), add a dependency provider to the component using the `+TINYMCE_SCRIPT_SRC+` token. + [source,ts] ---- -import { EditorModule, TINYMCE_SCRIPT_SRC } from '@tinymce/tinymce-angular'; +import { EditorComponent, TINYMCE_SCRIPT_SRC } from '@tinymce/tinymce-angular'; /* ... */ -@NgModule({ +@Component({ /* ... */ - imports: [ - EditorModule - ], + standalone: true, + imports: [EditorComponent], providers: [ { provide: TINYMCE_SCRIPT_SRC, useValue: 'tinymce/tinymce.min.js' } ] @@ -123,12 +116,16 @@ import { EditorModule, TINYMCE_SCRIPT_SRC } from '@tinymce/tinymce-angular'; ---- .. Update the editor configuration to include the `+base_url+` and `+suffix+` options. + -[source,html] +[source,ts] ---- - +export class AppComponent { + /* ... */ + init: EditorComponent['init'] = { + /* ... */ + base_url: '/tinymce', // Root for resources + suffix: '.min' // Suffix to use when loading resources + }; +} ---- endif::[] ifeval::["{productSource}" == "zip"] @@ -143,8 +140,6 @@ To use an independent deployment of {productname}, add a script to either the `+ ---- + -To use an independent deployment of {productname} with the create a Angular application, add the script to `+/path/to/tinymce-angular-demo/src/app/app.component.html+`. -+ * Bundling {productname} with the Angular application using a module loader (such as Webpack). + -- @@ -174,7 +169,7 @@ endif::[] == Deploying the application to a HTTP server -The application will require further configuration before it can be deployed to a production environment. For information on configuring the application for deployment, see: https://angular.io/guide/build[Angular Docs - Building and serving Angular apps] or https://angular.io/guide/deployment[Angular Docs - Deployment]. +The application will require further configuration before it can be deployed to a production environment. For information on configuring the application for deployment, see: link:https://angular.dev/tools/cli/build[Angular Docs - Building Angular Apps] or link:https://angular.dev/tools/cli/deployment[Angular Docs - Deployment]. To deploy the application to a local HTTP Server: @@ -190,10 +185,33 @@ The application has now been deployed on the web server. NOTE: Additional configuration is required to deploy the application outside the web server root directory, such as +http://localhost:/my_angular_application+. +[[angular-modules]] +== Angular Modules +`+EditorModule+` is available to import from `+@tinymce/tinymce-angular+`. Which should be included in your `+my.module.ts+` file. + +[source,ts] +---- +import { NgModule } from '@angular/core'; +import { EditorModule, TINYMCE_SCRIPT_SRC } from '@tinymce/tinymce-angular'; + +@NgModule({ + /* ... */ + imports: [ + EditorModule + ], + providers: [ + // If you're self hosting and lazy loading TinyMCE from node_modules: + { provide: TINYMCE_SCRIPT_SRC, useValue: 'tinymce/tinymce.min.js' } + ], + /* ... */ +}) +export class MyModule {} +---- + == Next Steps * For examples of the {productname} integration, see: https://tinymce.github.io/tinymce-angular/[the tinymce-angular storybook]. * For information on customizing: ** {productname} integration, see: xref:angular-ref.adoc[Angular framework Technical Reference]. ** {productname}, see: xref:basic-setup.adoc[Basic setup]. -** The Angular application, see: https://angular.io/docs[the Angular documentation]. +** The Angular application, see: https://angular.dev[the Angular documentation]. diff --git a/modules/ROOT/partials/integrations/angular-tech-ref.adoc b/modules/ROOT/partials/integrations/angular-tech-ref.adoc index bad6fddeb7..f915cab951 100644 --- a/modules/ROOT/partials/integrations/angular-tech-ref.adoc +++ b/modules/ROOT/partials/integrations/angular-tech-ref.adoc @@ -5,6 +5,7 @@ * xref:using-the-tinymce-angular-integration[Using the TinyMCE Angular integration] * xref:configuring-the-editor[Configuring the editor] ** xref:apikey[`+apiKey+`] +** xref:licensekey[`+licenseKey+`] ** xref:cloudchannel[`+cloudChannel+`] ** xref:disabled[`+disabled+`] ** xref:id[`+id+`] @@ -32,7 +33,9 @@ The following table shows the supported versions of Angular and the required ver [cols="^,^",options="header"] |=== |Angular Version |`+tinymce-angular+` version -|13+ |5.x or newer +|16+ |8.x +|14 or 15 |7.x +|13 |6.x |9 to 12 |4.x |5 to 8 |3.x |4 or older |Not Supported @@ -126,6 +129,28 @@ include::partial$misc/get-an-api-key.adoc[] > ---- +[[licensekey]] +=== `+licenseKey+` + +{cloudname} License key. + +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+` + +[source,jsx] +---- + +---- + [[cloudchannel]] === `+cloudChannel+` @@ -406,6 +431,9 @@ The following events are available: * `+onBlur+` * `+onClick+` * `+onContextMenu+` +* `+onCompositionEnd+` +* `+onCompositionStart+` +* `+onCompositionUpdate+` * `+onCopy+` * `+onCut+` * `+onDblclick+` @@ -418,6 +446,7 @@ The following events are available: * `+onFocus+` * `+onFocusIn+` * `+onFocusOut+` +* `+onInput+` * `+onKeyDown+` * `+onKeyPress+` * `+onKeyUp+` diff --git a/modules/ROOT/partials/integrations/blazor-tech-ref.adoc b/modules/ROOT/partials/integrations/blazor-tech-ref.adoc index 9f2cc84635..3af7d14c5b 100644 --- a/modules/ROOT/partials/integrations/blazor-tech-ref.adoc +++ b/modules/ROOT/partials/integrations/blazor-tech-ref.adoc @@ -8,18 +8,19 @@ Covered in this section: The `+TinyMCE.Blazor+` `+Editor+` component accepts the following properties: -[source,cs] +[source,cs,subs="attributes+"] ---- ---- @@ -167,6 +168,21 @@ 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+` + +==== Example using LicenseKey + +[source,cs] +---- + +---- + === `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/react-bundling.adoc b/modules/ROOT/partials/integrations/react-bundling.adoc index 6881c67c94..e7fa085598 100644 --- a/modules/ROOT/partials/integrations/react-bundling.adoc +++ b/modules/ROOT/partials/integrations/react-bundling.adoc @@ -5,8 +5,7 @@ import { Editor } from '@tinymce/tinymce-react'; // TinyMCE so the global var exists -// eslint-disable-next-line no-unused-vars -import tinymce from 'tinymce/tinymce'; +import 'tinymce/tinymce'; // Theme import 'tinymce/themes/silver'; @@ -33,22 +32,17 @@ import 'tinymce/plugins/media'; import 'tinymce/plugins/nonbreaking'; import 'tinymce/plugins/table'; import 'tinymce/plugins/help'; +import 'tinymce/plugins/help/js/i18n/keynav/en'; // Content styles, including inline UI like fake cursors -/* eslint import/no-webpack-loader-syntax: off */ -import contentCss from '!!raw-loader!tinymce/skins/content/default/content.min.css'; -import contentUiCss from '!!raw-loader!tinymce/skins/ui/oxide/content.min.css'; +import 'tinymce/skins/content/default/content.js'; +import 'tinymce/skins/ui/oxide/content.js'; export default function TinyEditorComponent(props) { - // note that skin and content_css is disabled to avoid the normal - // loading process and is instead loaded as a string via content_style return ( ); } diff --git a/modules/ROOT/partials/integrations/react-quick-start.adoc b/modules/ROOT/partials/integrations/react-quick-start.adoc index b8697eadec..20e60ed330 100644 --- a/modules/ROOT/partials/integrations/react-quick-start.adoc +++ b/modules/ROOT/partials/integrations/react-quick-start.adoc @@ -4,7 +4,7 @@ ifeval::["{productUse}" == "bundle"] IMPORTANT: {companyname} does not recommend bundling the `tinymce` package. Bundling {productname} can be complex and error prone. endif::[] -The https://github.com/tinymce/tinymce-react[Official {productname} React component] integrates {productname} into React projects. This procedure creates a https://github.com/facebook/create-react-app[basic React application] containing a {productname} editor. +The https://github.com/tinymce/tinymce-react[Official {productname} React component] integrates {productname} into React projects. This procedure creates a https://github.com/vitejs/vite-plugin-react-swc[basic React application] containing a {productname} editor. For examples of the {productname} integration, visit https://tinymce.github.io/tinymce-react/[the tinymce-react storybook]. @@ -14,11 +14,11 @@ This procedure requires https://nodejs.org/[Node.js (and npm)]. == Procedure -. Use the https://github.com/facebook/create-react-app[Create React App] package to create a new React project named `+tinymce-react-demo+`. +. Use the https://github.com/vitejs/vite[Vite] package and the https://github.com/vitejs/vite-plugin-react-swc[React SWC plugin] to create a new React project named `+tinymce-react-demo+`. + [source,sh] ---- -npx create-react-app tinymce-react-demo +npm create vite@5 tinymce-react-demo -- --template react-swc ---- . Change to the newly created directory. + @@ -28,19 +28,20 @@ cd tinymce-react-demo ---- ifeval::["{productSource}" == "cloud"] -. Install the `+tinymce-react+` package and save it to your `+package.json+` with `+--save+`. +. Install the `+@tinymce/tinymce-react+` package and save it to your `+package.json+` with `+--save+`. + [source,sh] ---- npm install --save @tinymce/tinymce-react ---- -. Using a text editor, open `+./src/App.js+` and replace the contents with: +. Using a text editor, open `+./src/App.jsx+` and replace the contents with: + [source,jsx] ---- -import React, { useRef } from 'react'; +import { useRef } from 'react'; import { Editor } from '@tinymce/tinymce-react'; +import './App.css'; export default function App() { const editorRef = useRef(null); @@ -53,7 +54,7 @@ export default function App() { <> editorRef.current = editor} + onInit={(_evt, editor) => editorRef.current = editor} initialValue="

    This is the initial content of the editor.

    " init={{ height: 500, @@ -82,7 +83,7 @@ This JavaScript file will create a component "`+App+`" containing a {productname endif::[] ifeval::["{productSource}" == "package-manager"] ifeval::["{productUse}" == "host"] -. Install the `+tinymce+`, `+tinymce-react+` and `+fs-extra+` packages and save them to your `+package.json+` with `+--save+`. +. Install the `+tinymce+`, `+@tinymce/tinymce-react+` and `+fs-extra+` packages and save them to your `+package.json+` with `+--save+`. + [source,sh] ---- @@ -94,9 +95,9 @@ npm install --save tinymce @tinymce/tinymce-react fs-extra .postinstall.js [source,js] ---- -const fse = require('fs-extra'); -const path = require('path'); -const topDir = __dirname; +import fse from 'fs-extra'; +import path from 'path'; +const topDir = import.meta.dirname; fse.emptyDirSync(path.join(topDir, 'public', 'tinymce')); fse.copySync(path.join(topDir, 'node_modules', 'tinymce'), path.join(topDir, 'public', 'tinymce'), { overwrite: true }); ---- @@ -127,12 +128,13 @@ fse.copySync(path.join(topDir, 'node_modules', 'tinymce'), path.join(topDir, 'pu npm run postinstall ---- -. Using a text editor, open `+./src/App.js+` and replace the contents with: +. Using a text editor, open `+./src/App.jsx+` and replace the contents with: + [source,jsx] ---- -import React, { useRef } from 'react'; +import { useRef } from 'react'; import { Editor } from '@tinymce/tinymce-react'; +import './App.css'; export default function App() { const editorRef = useRef(null); @@ -144,8 +146,9 @@ export default function App() { return ( <> editorRef.current = editor} + tinymceScriptSrc='/tinymce/tinymce.min.js' + licenseKey='your-license-key' + onInit={(_evt, editor) => editorRef.current = editor} initialValue='

    This is the initial content of the editor.

    ' init={{ height: 500, @@ -167,24 +170,26 @@ export default function App() { ); } ---- + +. Update the `+licenseKey+` option in the editor element and include your xref:license-key.adoc[License Key]. + endif::[] ifeval::["{productUse}" == "bundle"] -. Install the `+tinymce+`, `+tinymce-react+` and `+raw-loader+` packages and save them to your `+package.json+` with `+--save+`. +. Install the `+tinymce+` and `+@tinymce/tinymce-react+` packages and save them to your `+package.json+` with `+--save+`. + [source,sh] ---- -npm install --save tinymce @tinymce/tinymce-react raw-loader +npm install --save tinymce @tinymce/tinymce-react ---- -. Using a text editor, create `+./src/BundledEditor.js+` and set the contents to: +. Using a text editor, create `+./src/BundledEditor.jsx+` and set the contents to: + [source,jsx] ---- import { Editor } from '@tinymce/tinymce-react'; // TinyMCE so the global var exists -// eslint-disable-next-line no-unused-vars -import tinymce from 'tinymce/tinymce'; +import 'tinymce/tinymce'; // DOM model import 'tinymce/models/dom/model' // Theme @@ -192,7 +197,7 @@ import 'tinymce/themes/silver'; // Toolbar icons import 'tinymce/icons/default'; // Editor styles -import 'tinymce/skins/ui/oxide/skin.min.css'; +import 'tinymce/skins/ui/oxide/skin'; // importing the plugin js. // if you use a plugin that is not listed here the editor will fail to load @@ -208,6 +213,7 @@ import 'tinymce/plugins/directionality'; import 'tinymce/plugins/emoticons'; import 'tinymce/plugins/fullscreen'; import 'tinymce/plugins/help'; +import 'tinymce/plugins/help/js/i18n/keynav/en'; import 'tinymce/plugins/image'; import 'tinymce/plugins/importcss'; import 'tinymce/plugins/insertdatetime'; @@ -229,34 +235,28 @@ import 'tinymce/plugins/wordcount'; import 'tinymce/plugins/emoticons/js/emojis'; // Content styles, including inline UI like fake cursors -/* eslint import/no-webpack-loader-syntax: off */ -import contentCss from '!!raw-loader!tinymce/skins/content/default/content.min.css'; -import contentUiCss from '!!raw-loader!tinymce/skins/ui/oxide/content.min.css'; +import 'tinymce/skins/content/default/content'; +import 'tinymce/skins/ui/oxide/content'; export default function BundledEditor(props) { - const {init, ...rest} = props; - // note that skin and content_css is disabled to avoid the normal - // loading process and is instead loaded as a string via content_style return ( ); } ---- -. Using a text editor, open `+./src/App.js+` and replace the contents with: +. Update the `+licenseKey+` option in the editor element and include your xref:license-key.adoc[License Key]. + +. Using a text editor, open `+./src/App.jsx+` and replace the contents with: + [source,jsx] ---- -import React, { useRef } from 'react'; +import { useRef } from 'react'; import BundledEditor from './BundledEditor' +import './App.css'; export default function App() { const editorRef = useRef(null); @@ -268,7 +268,7 @@ export default function App() { return ( <> editorRef.current = editor} + onInit={(_evt, editor) => editorRef.current = editor} initialValue='

    This is the initial content of the editor.

    ' init={{ height: 500, @@ -293,7 +293,7 @@ endif::[] endif::[] ifeval::["{productSource}" == "zip"] ifeval::["{productUse}" == "host"] -. Install the `+tinymce-react+` package and save it to your `+package.json+` with `+--save+`. +. Install the `+@tinymce/tinymce-react+` package and save it to your `+package.json+` with `+--save+`. + [source,sh] ---- @@ -324,12 +324,33 @@ public └── tinymce.min.js ---- -. Using a text editor, open `+./src/App.js+` and replace the contents with: +. Using a text editor, open `+./eslintrc.cjs+` and add `+'src/tinymce'+` to the `+ignorePatterns+` array. ++ +.Diff of `.eslintrc.js` +[source,patch] +---- +diff --git a/.eslintrc.cjs b/.eslintrc.cjs +index 3b3b3b3..4b4b4b4 100644 +--- a/.eslintrc.cjs ++++ b/.eslintrc.cjs +@@ -7,7 +7,7 @@ modules.exports = { + 'plugin:react/jsx-runtime', + 'plugin:react-hooks/recommended', + ], +- ignorePatterns: ['dist', '.eslintrc.cjs'], ++ ignorePatterns: ['dist', '.eslintrc.cjs', 'src/tinymce'], + parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, + settings: { react: { version: '18.2' } }, + plugins: ['react-refresh'], +---- + +. Using a text editor, open `+./src/App.jsx+` and replace the contents with: + [source,jsx] ---- -import React, { useRef } from 'react'; +import { useRef } from 'react'; import { Editor } from '@tinymce/tinymce-react'; +import './App.css'; export default function App() { const editorRef = useRef(null); @@ -341,8 +362,9 @@ export default function App() { return ( <> editorRef.current = editor} + tinymceScriptSrc='/tinymce/tinymce.min.js' + licenseKey='your-license-key' + onInit={(_evt, editor) => editorRef.current = editor} initialValue='

    This is the initial content of the editor.

    ' init={{ height: 500, @@ -364,22 +386,15 @@ export default function App() { ); } ---- +. Update the `+licenseKey+` option in the editor element and include your xref:license-key.adoc[License Key]. endif::[] ifeval::["{productUse}" == "bundle"] -. Eject the create-react-app so it is possible to modify the Webpack configuration. -+ -[source,sh] ----- -npm run eject ----- -+ -Press 'y' when prompted. -. Install the `+tinymce-react+`, `+raw-loader+` and `+script-loader+` packages and save them to your `+package.json+` with `+--save+`. +. Install the `+@tinymce/tinymce-react+` and `+script-loader+` packages and save them to your `+package.json+` with `+--save+`. + [source,sh] ---- -npm install --save @tinymce/tinymce-react raw-loader script-loader +npm install --save @tinymce/tinymce-react script-loader ---- . Unzip the content of the `+tinymce/js+` folder from the link:{download-enterprise}[{productname} zip] into the `+src+` folder. Afterwards the directory listing should be similar to below: @@ -408,91 +423,33 @@ src └── tinymce.min.js ---- -. Using a text editor, open `+./config/paths.js+`, after the line with `+appSrc+` add the line: -+ -[source,js] ----- - appTinymce: resolveApp('src/tinymce'), ----- -+ -.Diff of `./config/paths.js` -[source,patch] ----- -diff --git a/config/paths.js b/config/paths.js -index f0a6cd9..a0d2f50 100644 ---- a/config/paths.js -+++ b/config/paths.js -@@ -60,6 +60,7 @@ module.exports = { - appIndexJs: resolveModule(resolveApp, 'src/index'), - appPackageJson: resolveApp('package.json'), - appSrc: resolveApp('src'), -+ appTinymce: resolveApp('src/tinymce'), - appTsConfig: resolveApp('tsconfig.json'), - appJsConfig: resolveApp('jsconfig.json'), - yarnLockFile: resolveApp('yarn.lock'), ----- - -. Using a text editor, open `+./config/webpack.config.js+` and make the following edits: -+ -** Find the `ModuleScopePlugin` and add `require.resolve('script-loader'),` to its array of exceptions. -** Find the rule for processing javascript in the `src` directory and add the new rule above it: -+ -[source,js] ----- -{ - test: /\.(js)$/, - include: paths.appTinymce, - loader: require.resolve('script-loader'), -}, ----- -** Find the `ESLintPlugin` and add `exclude: ["tinymce"],` to its options. - +. Using a text editor, open `+./eslintrc.cjs+` and add `+'src/tinymce'+` to the `+ignorePatterns+` array. + -.Diff of `./config/webpack.config.js` +.Diff of `.eslintrc.js` [source,patch] ---- -diff --git a/config/webpack.config.js b/config/webpack.config.js -index 6b4a4cd..e0d1952 100644 ---- a/config/webpack.config.js -+++ b/config/webpack.config.js -@@ -331,6 +331,7 @@ module.exports = function (webpackEnv) { - babelRuntimeEntry, - babelRuntimeEntryHelpers, - babelRuntimeRegenerator, -+ require.resolve('script-loader'), - ]), - ], - }, -@@ -399,6 +400,11 @@ module.exports = function (webpackEnv) { - and: [/\.(ts|tsx|js|jsx|md|mdx)$/], - }, - }, -+ { -+ test: /\.(js)$/, -+ include: paths.appTinymce, -+ loader: require.resolve('script-loader'), -+ }, - // Process application JS with Babel. - // The preset includes JSX, Flow, TypeScript, and some ESnext features. - { -@@ -724,6 +730,7 @@ module.exports = function (webpackEnv) { - new ESLintPlugin({ - // Plugin options - extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'], -+ exclude: ["tinymce"], - formatter: require.resolve('react-dev-utils/eslintFormatter'), - eslintPath: require.resolve('eslint'), - failOnError: !(isEnvDevelopment && emitErrorsAsWarnings), ----- - -. Using a text editor, create `+./src/BundledEditor.js+` and set the contents to: +diff --git a/.eslintrc.cjs b/.eslintrc.cjs +index 3b3b3b3..4b4b4b4 100644 +--- a/.eslintrc.cjs ++++ b/.eslintrc.cjs +@@ -7,7 +7,7 @@ modules.exports = { + 'plugin:react/jsx-runtime', + 'plugin:react-hooks/recommended', + ], +- ignorePatterns: ['dist', '.eslintrc.cjs'], ++ ignorePatterns: ['dist', '.eslintrc.cjs', 'src/tinymce'], + parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, + settings: { react: { version: '18.2' } }, + plugins: ['react-refresh'], +---- + +. Using a text editor, create `+./src/BundledEditor.jsx+` and set the contents to: + [source,jsx] ---- import { Editor } from '@tinymce/tinymce-react'; // TinyMCE so the global var exists -// eslint-disable-next-line no-unused-vars import './tinymce/tinymce.min.js'; // DOM model import './tinymce/models/dom/model.min.js' @@ -501,71 +458,65 @@ import './tinymce/themes/silver/theme.min.js'; // Toolbar icons import './tinymce/icons/default/icons.min.js'; // Editor styles -import './tinymce/skins/ui/oxide/skin.min.css'; +import './tinymce/skins/ui/oxide/skin.min.js'; -// importing the plugin js. +// importing the plugin index.js file. // if you use a plugin that is not listed here the editor will fail to load -import './tinymce/plugins/advlist/plugin.min.js'; -import './tinymce/plugins/anchor/plugin.min.js'; -import './tinymce/plugins/autolink/plugin.min.js'; -import './tinymce/plugins/autoresize/plugin.min.js'; -import './tinymce/plugins/autosave/plugin.min.js'; -import './tinymce/plugins/charmap/plugin.min.js'; -import './tinymce/plugins/code/plugin.min.js'; -import './tinymce/plugins/codesample/plugin.min.js'; -import './tinymce/plugins/directionality/plugin.min.js'; -import './tinymce/plugins/emoticons/plugin.min.js'; -import './tinymce/plugins/fullscreen/plugin.min.js'; -import './tinymce/plugins/help/plugin.min.js'; -import './tinymce/plugins/image/plugin.min.js'; -import './tinymce/plugins/importcss/plugin.min.js'; -import './tinymce/plugins/insertdatetime/plugin.min.js'; -import './tinymce/plugins/link/plugin.min.js'; -import './tinymce/plugins/lists/plugin.min.js'; -import './tinymce/plugins/media/plugin.min.js'; -import './tinymce/plugins/nonbreaking/plugin.min.js'; -import './tinymce/plugins/pagebreak/plugin.min.js'; -import './tinymce/plugins/preview/plugin.min.js'; -import './tinymce/plugins/quickbars/plugin.min.js'; -import './tinymce/plugins/save/plugin.min.js'; -import './tinymce/plugins/searchreplace/plugin.min.js'; -import './tinymce/plugins/table/plugin.min.js'; -import './tinymce/plugins/visualblocks/plugin.min.js'; -import './tinymce/plugins/visualchars/plugin.min.js'; -import './tinymce/plugins/wordcount/plugin.min.js'; +import './tinymce/plugins/advlist'; +import './tinymce/plugins/anchor'; +import './tinymce/plugins/autolink'; +import './tinymce/plugins/autoresize'; +import './tinymce/plugins/autosave'; +import './tinymce/plugins/charmap'; +import './tinymce/plugins/code'; +import './tinymce/plugins/codesample'; +import './tinymce/plugins/directionality'; +import './tinymce/plugins/emoticons'; +import './tinymce/plugins/fullscreen'; +import './tinymce/plugins/help'; +import './tinymce/plugins/image'; +import './tinymce/plugins/importcss'; +import './tinymce/plugins/insertdatetime'; +import './tinymce/plugins/link'; +import './tinymce/plugins/lists'; +import './tinymce/plugins/media'; +import './tinymce/plugins/nonbreaking'; +import './tinymce/plugins/pagebreak'; +import './tinymce/plugins/preview'; +import './tinymce/plugins/quickbars'; +import './tinymce/plugins/save'; +import './tinymce/plugins/searchreplace'; +import './tinymce/plugins/table'; +import './tinymce/plugins/visualblocks'; +import './tinymce/plugins/visualchars'; +import './tinymce/plugins/wordcount'; // importing plugin resources import './tinymce/plugins/emoticons/js/emojis.js'; // Content styles, including inline UI like fake cursors -/* eslint import/no-webpack-loader-syntax: off */ -import contentCss from '!!raw-loader!./tinymce/skins/content/default/content.min.css'; -import contentUiCss from '!!raw-loader!./tinymce/skins/ui/oxide/content.min.css'; +import './tinymce/skins/content/default/content.js'; +import './tinymce/skins/ui/oxide/content.js'; export default function BundledEditor(props) { - const {init, ...rest} = props; - // note that skin and content_css is disabled to avoid the normal - // loading process and is instead loaded as a string via content_style return ( ); } ---- -. Using a text editor, open `+./src/App.js+` and replace the contents with: +. Update the `+licenseKey+` option in the editor element and include your xref:license-key.adoc[License Key]. + +. Using a text editor, open `+./src/App.jsx+` and replace the contents with: + [source,jsx] ---- -import React, { useRef } from 'react'; +import { useRef } from 'react'; import BundledEditor from './BundledEditor' +import './App.css'; export default function App() { const editorRef = useRef(null); @@ -577,7 +528,7 @@ export default function App() { return ( <> editorRef.current = editor} + onInit={(_evt, editor) => editorRef.current = editor} initialValue='

    This is the initial content of the editor.

    ' init={{ height: 500, @@ -607,14 +558,14 @@ endif::[] + [source,sh] ---- -npm run start +npm run dev ---- * To stop the development server, select on the command line or command prompt and press _Ctrl+C_. == Deploying the application to a HTTP server -The application will require further configuration before it can be deployed to a production environment. For information on configuring the application for deployment, see: https://create-react-app.dev/docs/deployment[Create React App - Deployment]. +The application will require further configuration before it can be deployed to a production environment. For information on configuring the application for deployment, see: https://vitejs.dev/guide/build[Building for Production] or https://vitejs.dev/guide/static-deploy.html[Deploying a Static Site]. To deploy the application to a local HTTP Server: @@ -624,7 +575,13 @@ To deploy the application to a local HTTP Server: ---- npm run build ---- -. Copy the contents of the `+tinymce-react-demo/build+` directory to the root directory of the web server. +. You can optionally preview the production build by running: ++ +[source,sh] +---- +npm run preview +---- +. Copy the contents of the `+tinymce-react-demo/dist+` directory to the root directory of the web server. The application has now been deployed on the web server. @@ -639,4 +596,4 @@ endif::[] * For information on customizing: ** {productname} integration, see: xref:react-ref.adoc[]. ** {productname}, see: xref:basic-setup.adoc[]. -** The React application, see: https://create-react-app.dev/docs/getting-started[Create React App] or https://reactjs.org/docs/getting-started.html[the React documentation]. +** The React application, see: https://vitejs.dev/guide/#getting-started[Getting Started with Vite] or https://reactjs.org/docs/getting-started.html[the React documentation]. diff --git a/modules/ROOT/partials/integrations/react-tech-ref.adoc b/modules/ROOT/partials/integrations/react-tech-ref.adoc index ede5ba2302..a83c3a3546 100644 --- a/modules/ROOT/partials/integrations/react-tech-ref.adoc +++ b/modules/ROOT/partials/integrations/react-tech-ref.adoc @@ -22,6 +22,7 @@ ** xref:toolbar[`+toolbar+`] ** xref:tinymcescriptsrc[`+tinymceScriptSrc+`] ** xref:value[`+value+`] +** xref:tabIndex[`+tabIndex+`] * xref:using-the-tinymce-react-component-as-a-uncontrolled-component[Using the TinyMCE React component as a uncontrolled component] * xref:using-the-tinymce-react-component-as-a-controlled-component[Using the TinyMCE React component as a controlled component] * xref:event-binding[Event binding] @@ -154,6 +155,8 @@ xref:event-binding[`+onInit+`]:: An event handler for notifying when the editor xref:value[`+value+`]:: Sets and enforces the value of the editor. Only used for a controlled component. +xref:tabIndex[`+value+`]:: Sets the tabindex of the target element that the editor wraps. + [[available-props]] == Available props @@ -597,6 +600,22 @@ For detailed information on using the `+value+` prop, see: xref:using-the-tinymc *Type:* `+String+` +[[tabIndex]] +=== `+tabIndex+` + +Use the `+tabIndex+` prop to set the https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex[tabindex] on the target element that the editor wraps. + +*Type:* `+Number+` + +==== Example: using `+tabIndex+` + +[source,jsx] +---- + +---- + [[using-the-tinymce-react-component-as-a-uncontrolled-component]] == Using the {productname} React component as a uncontrolled component diff --git a/modules/ROOT/partials/integrations/svelte-quick-start.adoc b/modules/ROOT/partials/integrations/svelte-quick-start.adoc index 8bb82caf85..057ef53980 100644 --- a/modules/ROOT/partials/integrations/svelte-quick-start.adoc +++ b/modules/ROOT/partials/integrations/svelte-quick-start.adoc @@ -1,4 +1,4 @@ -The https://github.com/tinymce/tinymce-svelte[Official {productname} Svelte component] integrates {productname} into https://svelte.dev/[Svelte applications]. This procedure creates a basic Svelte application using the https://github.com/sveltejs/template[`+sveltejs/template+` project] adds a {productname} editor based using the {productname} Svelte integration. +The https://github.com/tinymce/tinymce-svelte[Official {productname} Svelte component] integrates {productname} into https://svelte.dev/[Svelte applications]. This procedure creates a basic Svelte application containing a {productname} editor. For examples of the {productname} integration, visit https://tinymce.github.io/tinymce-svelte/[the tinymce-svelte storybook]. @@ -8,21 +8,26 @@ This procedure requires https://nodejs.org/[Node.js (and npm)]. == Procedure -. Create a Svelte application using the https://github.com/sveltejs/template[Svelte template project], for example: +. Use the https://github.com/vitejs/vite[Vite] package to create a new Svelte project named `+tinymce-svelte-demo+`, such as: + [source,sh] ---- -npx degit sveltejs/template my-tiny-app -cd my-tiny-app +npm create vite@5 tinymce-svelte-demo -- --template svelte +---- +. Change to the newly created directory. ++ +[source,sh] +---- +cd tinymce-svelte-demo ---- ifeval::["{productSource}" == "package-manager"] . Install the `+tinymce+` and the `+tinymce-svelte+` editor component, such as: + -[source,sh] +[source,sh,subs="attributes+"] ---- -npm install tinymce @tinymce/tinymce-svelte +npm install tinymce@^{productmajorversion} @tinymce/tinymce-svelte ---- endif::[] @@ -38,23 +43,33 @@ npm install @tinymce/tinymce-svelte endif::[] ifeval::["{productSource}" == "cloud"] -. Open `+src/App.svelte+` and add: -* An `+import+` statement for the {productname} component. -* The `++` as a placeholder for the editor. +. Open `+src/App.svelte+` and replace the contents with: + -For example: -+ -_File:_ `+src/App.svelte+` -+ -[source,html] +[source,html,subs="+macros"] ---- -

    Hello Tiny

    ---- @@ -62,50 +77,59 @@ import Editor from '@tinymce/tinymce-svelte'; endif::[] ifeval::["{productSource}" == "package-manager"] -. Install the `+rollup-plugin-copy+` development dependency, such as: +. Install the `+vite-plugin-static-copy+` development dependency, such as: + [source,sh] ---- -npm install rollup-plugin-copy -D +npm install -D vite-plugin-static-copy ---- -. Open `+rollup.config.js+` and configure the rollup copy plugin `+rollup-plugin-copy+` to copy {productname} to the `+public/+` directory, such as: +. Open `+vite.config.js+` and configure the `+vite-plugin-static-copy+` plugin to copy {productname} to the `+public/+` directory, such as: + [source,js] ---- -/* Existing import statements */ -import copy from 'rollup-plugin-copy' +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import { viteStaticCopy } from 'vite-plugin-static-copy' -/* Skip to the export statement, `plugins` item and add `copy`*/ -export default { - /* Existing key: values... */ +// https://vitejs.dev/config/ +export default defineConfig({ plugins: [ - copy({ + viteStaticCopy({ targets: [ - { src: 'node_modules/tinymce/*', dest: 'public/tinymce' } + { src: 'node_modules/tinymce/*', dest: 'tinymce' } ] }), - /* More existing configuration... */ - ] -} + svelte() + ], +}) ---- -. Open `+src/App.svelte+` and add: -* An `+import+` statement for the {productname} component. -* The `++` as a placeholder for the editor. -* The xref:svelte-ref.adoc#scriptsrc[`+scriptSrc+`] property for the `+Editor+` placeholder. -+ -For example: -+ -_File:_ `+src/App.svelte+` +. Open `+src/App.svelte+` and replace the contents with: + [source,html] ---- -

    Hello Tiny

    ---- @@ -113,24 +137,33 @@ import Editor from '@tinymce/tinymce-svelte'; endif::[] ifeval::["{productSource}" == "zip"] -. Open `+src/App.svelte+` and add: -* An `+import+` statement for the {productname} component. -* The `++` as a placeholder for the editor. -* The xref:svelte-ref.adoc#scriptsrc[`+scriptSrc+`] property for the `+Editor+` placeholder. -+ -For example: -+ -_File:_ `+src/App.svelte+` +. Open `+src/App.svelte+` and replace the contents with: + [source,html] ---- -

    Hello Tiny

    ---- @@ -145,7 +178,6 @@ endif::[] npm run dev ---- + -This will start a local development server, accessible at http://localhost:8080. * To stop the development server, select on the command line or command prompt and press _Ctrl+C_. == Next Steps diff --git a/modules/ROOT/partials/integrations/svelte-tech-ref.adoc b/modules/ROOT/partials/integrations/svelte-tech-ref.adoc index 90aadb9d79..cd0b263586 100644 --- a/modules/ROOT/partials/integrations/svelte-tech-ref.adoc +++ b/modules/ROOT/partials/integrations/svelte-tech-ref.adoc @@ -1,6 +1,14 @@ Covered in this section: * xref:configuring-the-tinymce-svelte-integration[Configuring the TinyMCE Svelte integration] +** xref:apikey[apiKey] +** xref:licensekey[licenseKey] +** xref:channel[channel] +** xref:id[id] +** xref:inline[inline] +** xref:disabled[disabled] +** xref:scriptsrc[scriptsrc] +** xref:conf[conf] * xref:component-binding[Component binding] * xref:event-binding[Event binding] @@ -43,6 +51,28 @@ The `+tinymce-svelte+` `+Editor+` component accepts the following properties: /> ---- +[[licenseKey]] +=== `+licenseKey+` + +{cloudname} License key. + +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+` + +[source,jsx] +---- + +---- + [[channel]] === `+channel+` @@ -229,6 +259,10 @@ The following events are available: * `+change+` * `+clearundos+` * `+click+` +* `+CommentChange+` +* `+CompositionEnd+` +* `+CompositionStart+` +* `+CompositionUpdate+` * `+contextmenu+` * `+copy+` * `+cut+` @@ -248,6 +282,7 @@ The following events are available: * `+getcontent+` * `+hide+` * `+init+` +* `+input+` * `+keydown+` * `+keypress+` * `+keyup+` @@ -279,4 +314,4 @@ The following events are available: * `+show+` * `+submit+` * `+undo+` -* `+visualaid+` +* `+visualaid+` \ No newline at end of file diff --git a/modules/ROOT/partials/integrations/swing-quick-start.adoc b/modules/ROOT/partials/integrations/swing-quick-start.adoc index 5ed83008e2..c8d8eb895a 100644 --- a/modules/ROOT/partials/integrations/swing-quick-start.adoc +++ b/modules/ROOT/partials/integrations/swing-quick-start.adoc @@ -4,7 +4,7 @@ Users can easily configure the {productname} editor in Swing through the *{produ To start using {productname} for Swing as your new rich text editor, the first step is to obtain a copy of the *Integration*. -Contact link:{supporturl}[{supportname}] to discuss how to get started with our latest release. +link:{contactpage}[{contactsales}] to discuss how to get started with our latest release. == Get started with our TinyMCE in Swing integration diff --git a/modules/ROOT/partials/integrations/vue-tech-ref.adoc b/modules/ROOT/partials/integrations/vue-tech-ref.adoc index 354b9c98a2..d2ea3334aa 100644 --- a/modules/ROOT/partials/integrations/vue-tech-ref.adoc +++ b/modules/ROOT/partials/integrations/vue-tech-ref.adoc @@ -4,6 +4,7 @@ * xref:using-the-tinymce-vuejs-integration[Using the TinyMCE Vue.js integration] * xref:configuring-the-editor[Configuring the editor] ** xref:api-key[`+api-key+`] +** xref:license-key[`+licenseKey+`] ** xref:cloud-channel[`+cloud-channel+`] ** xref:disabled[`+disabled+`] ** xref:id[`+id+`] @@ -124,6 +125,28 @@ include::partial$misc/get-an-api-key.adoc[] /> ---- +[[license-key]] +=== `+licenseKey+` + +{cloudname} License key. + +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+` + +[source,html] +---- + +---- + [[cloud-channel]] === `+cloud-channel+` @@ -412,6 +435,10 @@ The following events are available: * `+clearUndos+` * `+click+` * `+contextMenu+` +* `+commentChange+` +* `+compositionEnd+` +* `+compositionStart+` +* `+compositionUpdate+` * `+copy+` * `+cut+` * `+dblclick+` @@ -430,6 +457,7 @@ The following events are available: * `+getContent+` * `+hide+` * `+init+` +* `+input+` * `+keyDown+` * `+keyPress+` * `+keyUp+` @@ -460,4 +488,4 @@ The following events are available: * `+show+` * `+submit+` * `+undo+` -* `+visualAid+` +* `+visualAid+` \ No newline at end of file diff --git a/modules/ROOT/partials/menu-item-ids/math-menu-items.adoc b/modules/ROOT/partials/menu-item-ids/math-menu-items.adoc new file mode 100644 index 0000000000..4c82bb6de0 --- /dev/null +++ b/modules/ROOT/partials/menu-item-ids/math-menu-items.adoc @@ -0,0 +1,5 @@ +[cols="1,1,2",options="header"] +|=== +|Menu item identifier |xref:menus-configuration-options.adoc#example-the-tinymce-default-menu-items[Default Menu Location] |Description +|`+math+` |Insert |Opens the math modal dialog. +|=== \ No newline at end of file diff --git a/modules/ROOT/partials/menu-item-ids/uploadcare-menu-items.adoc b/modules/ROOT/partials/menu-item-ids/uploadcare-menu-items.adoc new file mode 100644 index 0000000000..27b724ae32 --- /dev/null +++ b/modules/ROOT/partials/menu-item-ids/uploadcare-menu-items.adoc @@ -0,0 +1,5 @@ +[cols="1,3",options="header"] +|=== +|Identifier |Description +| `+uploadcare+` | Inserts an image placeholder element. This placeholder supports image uploads via drag-and-drop, file selection, or by providing a URL. +|=== \ No newline at end of file diff --git a/modules/ROOT/partials/misc/admon-accessibility-rule-i3-can-also-be-applied.adoc b/modules/ROOT/partials/misc/admon-accessibility-rule-i3-can-also-be-applied.adoc index 39650322f0..24afe58283 100644 --- a/modules/ROOT/partials/misc/admon-accessibility-rule-i3-can-also-be-applied.adoc +++ b/modules/ROOT/partials/misc/admon-accessibility-rule-i3-can-also-be-applied.adoc @@ -1 +1,4 @@ -NOTE: In {productname} 6.3 and later, rule xref:I3[I3] can also be applied. If applied, 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. +[NOTE] +==== +In {productname} 6.3 and later, rule xref:I3[I3] can also be applied. If applied, 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. +==== \ No newline at end of file diff --git a/modules/ROOT/partials/misc/admon-ai-proxy.adoc b/modules/ROOT/partials/misc/admon-ai-proxy.adoc new file mode 100644 index 0000000000..3f538a66dc --- /dev/null +++ b/modules/ROOT/partials/misc/admon-ai-proxy.adoc @@ -0,0 +1 @@ +IMPORTANT: The following examples are intended to show how to use the authentication credentials with the API within the client side integration. This is **not recommended** for production purposes. It is recommended to only access the API with a xref:ai-proxy.adoc[proxy server] or by implementing a server-side integration to prevent unauthorized access to the API. \ No newline at end of file diff --git a/modules/ROOT/partials/misc/admon-export-pdf-paid-addon-pricing.adoc b/modules/ROOT/partials/misc/admon-export-pdf-paid-addon-pricing.adoc index 3096351f6e..2511223aee 100644 --- a/modules/ROOT/partials/misc/admon-export-pdf-paid-addon-pricing.adoc +++ b/modules/ROOT/partials/misc/admon-export-pdf-paid-addon-pricing.adoc @@ -1 +1 @@ -NOTE: This plugin is only available as a link:{exportpdfpricingurl}/[paid add-on] to link:{pricingpage}/[a TinyMCE subscription]. \ No newline at end of file +NOTE: This plugin is only available as a link:{exportpdfpricingurl}/[paid add-on] to link:{pricingpage}[a TinyMCE subscription]. \ No newline at end of file diff --git a/modules/ROOT/partials/misc/admon-export-word-paid-addon-pricing.adoc b/modules/ROOT/partials/misc/admon-export-word-paid-addon-pricing.adoc index da83aab5ff..87c65c7fe2 100644 --- a/modules/ROOT/partials/misc/admon-export-word-paid-addon-pricing.adoc +++ b/modules/ROOT/partials/misc/admon-export-word-paid-addon-pricing.adoc @@ -1 +1 @@ -NOTE: This plugin is only available as a link:{exportwordpricingurl}/[paid add-on] to link:{pricingpage}/[a TinyMCE subscription]. \ No newline at end of file +NOTE: This plugin is only available as a link:{exportwordpricingurl}/[paid add-on] to link:{pricingpage}[a TinyMCE subscription]. \ No newline at end of file diff --git a/modules/ROOT/partials/misc/admon-import-word-paid-addon-pricing.adoc b/modules/ROOT/partials/misc/admon-import-word-paid-addon-pricing.adoc index 0965eef071..cc5e31f4fa 100644 --- a/modules/ROOT/partials/misc/admon-import-word-paid-addon-pricing.adoc +++ b/modules/ROOT/partials/misc/admon-import-word-paid-addon-pricing.adoc @@ -1 +1 @@ -NOTE: This plugin is only available as a link:{importwordpricingurl}/[paid add-on] to link:{pricingpage}/[a TinyMCE subscription]. \ No newline at end of file +NOTE: This plugin is only available as a link:{importwordpricingurl}/[paid add-on] to link:{pricingpage}[a TinyMCE subscription]. \ No newline at end of file diff --git a/modules/ROOT/partials/misc/admon-requires-7.1v.adoc b/modules/ROOT/partials/misc/admon-requires-7.1v.adoc new file mode 100644 index 0000000000..c23475fcae --- /dev/null +++ b/modules/ROOT/partials/misc/admon-requires-7.1v.adoc @@ -0,0 +1 @@ +NOTE: This feature is only available for {productname} 7.1 and later. diff --git a/modules/ROOT/partials/misc/admon-requires-7.3v.adoc b/modules/ROOT/partials/misc/admon-requires-7.3v.adoc new file mode 100644 index 0000000000..6708f6f266 --- /dev/null +++ b/modules/ROOT/partials/misc/admon-requires-7.3v.adoc @@ -0,0 +1 @@ +NOTE: This feature is only available for {productname} 7.3 and later. diff --git a/modules/ROOT/partials/misc/admon-requires-7.4v.adoc b/modules/ROOT/partials/misc/admon-requires-7.4v.adoc new file mode 100644 index 0000000000..1dc73fba51 --- /dev/null +++ b/modules/ROOT/partials/misc/admon-requires-7.4v.adoc @@ -0,0 +1 @@ +NOTE: This feature is only available for {productname} 7.4 and later. diff --git a/modules/ROOT/partials/misc/admon-requires-7.6v.adoc b/modules/ROOT/partials/misc/admon-requires-7.6v.adoc new file mode 100644 index 0000000000..4983434a45 --- /dev/null +++ b/modules/ROOT/partials/misc/admon-requires-7.6v.adoc @@ -0,0 +1 @@ +NOTE: This feature is only available for {productname} 7.6.0 and later. diff --git a/modules/ROOT/partials/misc/admon-script-tag-placement.adoc b/modules/ROOT/partials/misc/admon-script-tag-placement.adoc new file mode 100644 index 0000000000..312001c8fa --- /dev/null +++ b/modules/ROOT/partials/misc/admon-script-tag-placement.adoc @@ -0,0 +1,2 @@ +[IMPORTANT] +The cloud plugin script tag must be positioned between the {productname} script tag and the `tinymce.init()` call. For applications that bundle {productname}, delay the `tinymce.init()` call until after the cloud plugin script tag has loaded. This ensures that the cloud plugins are available when the editor is initialized. \ No newline at end of file diff --git a/modules/ROOT/partials/misc/annotation-supported-content.adoc b/modules/ROOT/partials/misc/annotation-supported-content.adoc index 8d334f1382..64ccaa244b 100644 --- a/modules/ROOT/partials/misc/annotation-supported-content.adoc +++ b/modules/ROOT/partials/misc/annotation-supported-content.adoc @@ -1,13 +1,16 @@ [[supported-content]] -= Supported content += Supported Content * Text * Blocks -+ -include::partial$misc/admon-requires-6.1v.adoc[] -+ -** Tables of contents created using the xref:tableofcontents.adoc[Table of Contents] plugin. -** Images and images with captions created using the xref:image.adoc[Image] plugin. -** Code samples created using the xref:codesample.adoc[Code Sample] plugin. -** Media created using the xref:media.adoc[Media] plugin and xref:introduction-to-mediaembed.adoc[Enhanced Media Embed] plugin. -** Embedded pages created using the xref:pageembed.adoc[Page Embed] plugin. + +[NOTE] +==== +Comments supports the following features in {productname} 6.1 and later: + +* Tables of contents created with the xref:tableofcontents.adoc[Table of Contents] plugin. +* Images and images with captions created with the xref:image.adoc[Image] plugin. +* Code samples created with the xref:codesample.adoc[Code Sample] plugin. +* Media created with the xref:media.adoc[Media] plugin and the xref:introduction-to-mediaembed.adoc[Enhanced Media Embed] plugin. +* Embedded pages created with the xref:pageembed.adoc[Page Embed] plugin. +==== \ No newline at end of file diff --git a/modules/ROOT/partials/misc/premium-plugin-list.adoc b/modules/ROOT/partials/misc/premium-plugin-list.adoc index 6a30743c91..f93f16cf84 100644 --- a/modules/ROOT/partials/misc/premium-plugin-list.adoc +++ b/modules/ROOT/partials/misc/premium-plugin-list.adoc @@ -13,7 +13,9 @@ * xref:importword.adoc[Import from Word] * xref:inline-css.adoc[Inline CSS] * xref:editimage.adoc[Image Editing] +* xref:uploadcare.adoc[Image Optimizer Powered by Uploadcare] * xref:linkchecker.adoc[Link Checker] +* xref:math.adoc[Math] * xref:markdown.adoc[Markdown] * xref:mentions.adoc[Mentions] * xref:mergetags.adoc[Merge Tags] diff --git a/modules/ROOT/partials/misc/spellchecker-languages.adoc b/modules/ROOT/partials/misc/spellchecker-languages.adoc index c1378726ee..e6bc1bb04a 100644 --- a/modules/ROOT/partials/misc/spellchecker-languages.adoc +++ b/modules/ROOT/partials/misc/spellchecker-languages.adoc @@ -11,22 +11,22 @@ The following languages are supported for the Spell Checker plugin. All of the l |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_US-medical |{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 |{tick} |{tick} +|Dutch |nl, nl_NL |{tick} |{tick} |Finnish |fi |{tick} |{cross} |French |fr |{tick} |{tick} -|German |de |{tick} |{tick} +|German |de, de_DE |{tick} |{tick} |Hungarian |hu |{cross} |{tick} -|Italian |it |{tick} |{tick} +|Italian |it, it_IT |{tick} |{tick} |Maori (New Zealand) |mi_NZ |{cross} |{tick} -|Norwegian Bokmål |nb |{tick} |{tick} +|Norwegian Bokmål |nb, nb_NO |{tick} |{tick} |Norwegian Nynorsk |nn |{cross} |{tick} |Polish |pl |{cross} |{tick} -|Portuguese (Brazil) |pt |{tick} |{tick} +|Portuguese (Brazil) |pt, pt_BR |{tick} |{tick} |Portuguese (Portugal) |pt_PT |{tick} |{tick} |Spanish |es |{tick} |{tick} -|Swedish |sv |{tick} |{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/supported-versions.adoc b/modules/ROOT/partials/misc/supported-versions.adoc index ff00f7fb9d..f8bb653f21 100644 --- a/modules/ROOT/partials/misc/supported-versions.adoc +++ b/modules/ROOT/partials/misc/supported-versions.adoc @@ -5,19 +5,36 @@ Supported versions of {productname}: [cols="^,^,^",options="header"] |=== -|Version |Release Date |End of Support +|Version |Release Date |End of Premium Support +|7.6 |2025-12-04 |2027-06-04 +|7.5 |2025-11-06 |2027-05-06 +|7.4 |2024-10-09 |2026-04-09 +|7.3 |2024-08-07 |2026-02-07 +|7.2 |2024-06-19 |2025-12-19 +|7.1 |2024-05-08 |2025-11-08 |7.0 |2024-03-20 |2025-09-20 |6.8 |2023-12-06 |2025-06-06 |6.7 |2023-09-13 |2025-03-13 |6.6 |2023-07-19 |2025-01-19 |6.5 |2023-06-21 |2024-12-21 |6.4 |2023-03-29 |2024-09-29 -|6.3 |2022-12-08 |2024-06-08 +|6.3 |2023-12-08 |2024-06-08 |6.2 |2022-09-26 |2024-03-26 |6.1 |2022-07-13 |2024-01-13 |6.0 |2022-04-07 |2023-10-07 |=== +The date listed under "End of Premium Support" indicates the last day you may receive technical assistance for using and integrating the editor. + +Bug fixes and new features are always released in the latest version of {productname} (currently {productname} 7). + +=== Security updates: + +* Security updates are released in the latest minor version of each major version of {productname} that is still under active premium or LTS support ({productname} 7, {productname} 6, {productname} 5 LTS). +* Security updates for the free open source edition of {productname} are issued only for around six months after the new major version is available. Security support for the free open source version of {productname} 6 ended on October 31, 2024. +* For customers with a commercial license, security support for {productname} 6 ends on June 6, 2025. +* {productname} 5 (both open source and commercial versions) is no longer receiving security updates. However, it is possible to extend security support for {productname} 5 by purchasing a dedicated LTS (Long Term Support) agreement. If you are interested in purchasing a {productname} 5 LTS license, please link:https://www.tiny.cloud/contact/[contact us]. + To view our Software License Agreements, visit: * link:{legalpages}/cloud-use-subscription-agreement/[The {cloudname} Services Subscription Agreement]. diff --git a/modules/ROOT/partials/module-loading/admon-bundling-plugin-langs.adoc b/modules/ROOT/partials/module-loading/admon-bundling-plugin-langs.adoc index 367803cf55..486ad423bf 100644 --- a/modules/ROOT/partials/module-loading/admon-bundling-plugin-langs.adoc +++ b/modules/ROOT/partials/module-loading/admon-bundling-plugin-langs.adoc @@ -1 +1,26 @@ -NOTE: The plugin language files (such as `+./plugins/plugin/langs/sv_SE.js+`) are required where the editor user interface is localized using the xref:ui-localization.adoc#language[language option]. Please refer to xref:bundling-plugins.adoc#plugin-language-files[plugin-language-files] \ No newline at end of file +[NOTE] +==== +Plugin language files (such as `+./plugins//langs/sv_SE.js+`) are required where the editor user interface is localized using the xref:ui-localization.adoc#language[language option]. + +The below plugins require these xref:bundling-plugins.adoc#plugin-language-files[plugin-language-files] + +* AI Assistant (+ai+) +* Accessibility Checker (+a11ychecker+) +* Enhanced Code (+advcode+) +* Enhanced Tables (+advtable+) +* Templates (+advtemplate+) +* Spelling Autocorrect (+autocorrect+) +* Image Editing (+editimage+) +* Export to PDF (+exportpdf+) +* Export to Word (+exportword+) +* Footnotes (+footnotes+) +* Import from Word (+importword+) +* Merge Tags (+mergetags+) +* Page Embedding (+pageembed+) +* PowerPaste (+powerpaste+) +* Revision History (+revisionhistory+) +* Table of Contents (+tableofcontents+) +* Comments (+tinycomments+) +* Spell Checker (+tinymcespellchecker+) +* Typography (+typography+) +==== \ No newline at end of file diff --git a/modules/ROOT/partials/module-loading/bundling-browserify-cjs-zip_editor.adoc b/modules/ROOT/partials/module-loading/bundling-browserify-cjs-zip_editor.adoc index 1e0fac64b6..43e92ea0e4 100644 --- a/modules/ROOT/partials/module-loading/bundling-browserify-cjs-zip_editor.adoc +++ b/modules/ROOT/partials/module-loading/bundling-browserify-cjs-zip_editor.adoc @@ -22,13 +22,13 @@ require('../tinymce/js/tinymce/models/dom/model.js'); require('../tinymce/js/tinymce/skins/ui/oxide/skin.css'); /* Import plugins - include the relevant plugin in the 'plugins' option. */ -require('../tinymce/js/tinymce/plugins/advlist/plugin.js'); -require('../tinymce/js/tinymce/plugins/code/plugin.js'); -require('../tinymce/js/tinymce/plugins/emoticons/plugin.js'); +require('../tinymce/js/tinymce/plugins/advlist'); +require('../tinymce/js/tinymce/plugins/code'); +require('../tinymce/js/tinymce/plugins/emoticons'); require('../tinymce/js/tinymce/plugins/emoticons/js/emojis'); -require('../tinymce/js/tinymce/plugins/link/plugin.js'); -require('../tinymce/js/tinymce/plugins/lists/plugin.js'); -require('../tinymce/js/tinymce/plugins/table/plugin.js'); +require('../tinymce/js/tinymce/plugins/link'); +require('../tinymce/js/tinymce/plugins/lists'); +require('../tinymce/js/tinymce/plugins/table'); /* content UI CSS is required */ const contentUiSkinCss = fs.readFileSync('tinymce/js/tinymce/skins/ui/oxide/content.css', { encoding: 'UTF-8' }); diff --git a/modules/ROOT/partials/module-loading/bundling-plugin-files.adoc b/modules/ROOT/partials/module-loading/bundling-plugin-files.adoc index 9b651ab29f..b8f8884df5 100644 --- a/modules/ROOT/partials/module-loading/bundling-plugin-files.adoc +++ b/modules/ROOT/partials/module-loading/bundling-plugin-files.adoc @@ -1,339 +1,30 @@ == Contents -include::partial$module-loading/bundling-plugins-that-cant-bundle.adoc[] - -* xref:premium-plugins[Premium plugins] -** xref:accessibility-checker[Accessibility Checker (a11ychecker)] -** xref:case-change[Case Change (casechange)] -** xref:checklist[Checklist (checklist)] -** xref:comments[Comments (tinycomments)] -** xref:advanced-code[Enhanced Code Editor (advcode)] -** xref:advanced-code[Advanced Code (advcode)] -** xref:advanced-tables[Enhanced Tables (advtable)] -** xref:case-change[Case Change (casechange)] -** xref:checklist[Checklist (checklist)] -** xref:comments[Comments (tinycomments)] -** xref:enhanced-media-embed[Enhanced Media Embed (mediaembed)] -** xref:exportword[Export to Word (exportword)] -** xref:footnotes[Footnotes (footnotes)] -** xref:format-painter[Format Painter (formatpainter)] -** xref:link-checker[Link Checker (linkchecker)] -** xref:markdown[Markdown (markdown)] -** xref:mentions[Mentions (mentions)] -** xref:mergetags[Merge Tags] -** xref:page-embed[Page Embed (pageembed)] -** xref:permanent-pen[Permanent Pen (permanentpen)] -** xref:powerpaste[PowerPaste (powerpaste)] -** xref:spell-checker[Spell Checker (tinymcespellchecker)] -** xref:autocorrect[Spelling Autocorrect] -** xref:table-of-contents[Table of Contents (tableofcontents)] -* xref:community-plugins[Community plugins] -** xref:advanced-list[List Styles (advlist)] -** xref:anchor[Anchor (anchor)] -** xref:autolink[Autolink (autolink)] -** xref:autoresize[Autoresize (autoresize)] -** xref:autosave[Autosave (autosave)] -** xref:character-map[Character Map (charmap)] -** xref:code[Code (code)] -** xref:codesamplecodesample[Code Sample (codesample)] -** xref:directionality[Directionality (directionality)] -** xref:emoticons[Emoticons (emoticons)] -** xref:full-screen[Full Screen (fullscreen)] -** xref:help[Help (help)] -** xref:image[Image (image)] -** xref:image-editing[Image Editing (editimage)] -** xref:import-css[Import CSS (importcss)] -** xref:insert-datetime[Insert Date/Time (insertdatetime)] -** xref:link[Link (link)] -** xref:lists[Lists (lists)] -** xref:media[Media (media)] -** xref:nonbreaking-space[Nonbreaking Space (nonbreaking)] -** xref:page-break[Page Break (pagebreak)] -** xref:preview[Preview (preview)] -** xref:quick-toolbar[Quick Toolbar (quickbars)] -** xref:save[Save (save)] -** xref:search-and-replace[Search and Replace (searchreplace)] -** xref:table[Table (table)] -** xref:visual-blocks[Visual Blocks (visualblocks)] -** xref:visual-characters[Visual Characters (visualchars)] -** xref:word-count[Word Count (wordcount)] [[premium-plugins]] -== Premium plugins - -[[accessibility-checker]] -=== Accessibility Checker (`+a11ychecker+`) - -include::partial$module-loading/admon-bundling-plugin-langs.adoc[] - -include::partial$plugin-files/plugin-file-list-a11ychecker.adoc[] - - -[[advanced-tables]] -=== Enhanced Tables (`+advtable+`) - -include::partial$module-loading/admon-bundling-plugin-langs.adoc[] - -include::partial$plugin-files/plugin-file-list-advtable.adoc[] - -[[case-change]] -=== Case Change (`+casechange+`) - -include::partial$plugin-files/plugin-file-list-casechange.adoc[] - -[[checklist]] -=== Checklist (`+checklist+`) - -include::partial$plugin-files/plugin-file-list-checklist.adoc[] - -[[comments]] -=== Comments (`+tinycomments+`) - -include::partial$module-loading/admon-bundling-plugin-langs.adoc[] - -include::partial$plugin-files/plugin-file-list-tinycomments.adoc[] - -[[enhanced-code-editor]] -=== Enhanced Code Editor (`+advcode+`) - -include::partial$plugin-files/plugin-file-list-advcode.adoc[] - -[[enhanced-media-embed]] -=== Enhanced Media Embed (`+mediaembed+`) - -include::partial$plugin-files/plugin-file-list-mediaembed.adoc[] - -[[export-word]] -=== ExportWord (`+exportword+`) - -include::partial$module-loading/admon-bundling-plugin-langs.adoc[] - -include::partial$plugin-files/plugin-file-list-exportword.adoc[] - -[[footnotes]] -=== Footnotes (`+footnotes+`) - -include::partial$module-loading/admon-bundling-plugin-langs.adoc[] - -include::partial$plugin-files/plugin-file-list-footnotes.adoc[] - -[[format-painter]] -=== Format Painter (`+formatpainter+`) - -include::partial$plugin-files/plugin-file-list-formatpainter.adoc[] - -[[image-editing]] -=== Image Editing (`+editimage+`) - -include::partial$module-loading/admon-bundling-plugin-langs.adoc[] - -include::partial$plugin-files/plugin-file-list-editimage.adoc[] - -[[link-checker]] -=== Link Checker (`+linkchecker+`) - -include::partial$plugin-files/plugin-file-list-linkchecker.adoc[] - -[[markdown]] -=== Markdown (`+markdown+`) - -include::partial$plugin-files/plugin-file-list-markdown.adoc[] - -[[mentions]] -=== Mentions (`+mentions+`) - -include::partial$plugin-files/plugin-file-list-mentions.adoc[] - -[[mergetags]] -=== Merge Tags (`+mergetags+`) - -include::partial$module-loading/admon-bundling-plugin-langs.adoc[] - -include::partial$plugin-files/plugin-file-list-mergetags.adoc[] - -[[page-embed]] -=== Page Embed (`+pageembed+`) - -include::partial$plugin-files/plugin-file-list-pageembed.adoc[] - -[[permanent-pen]] -=== Permanent Pen (`+permanentpen+`) - -include::partial$plugin-files/plugin-file-list-permanentpen.adoc[] - -[[powerpaste]] -=== PowerPaste (`+powerpaste+`) - -include::partial$module-loading/admon-bundling-plugin-langs.adoc[] - -include::partial$plugin-files/plugin-file-list-powerpaste.adoc[] - -[[spell-checker]] -=== Spell Checker (`+tinymcespellchecker+`) - -include::partial$module-loading/admon-bundling-plugin-langs.adoc[] +=== Premium plugins -include::partial$plugin-files/plugin-file-list-tinymcespellchecker.adoc[] +[NOTE] +Currently `.zip` style bundling is only available for premium plugins. -[[autocorrect]] -=== Spelling Autocorrect (`+autocorrect+`) +include::partial$plugin-files/plugin-file-bundling-message.adoc[] include::partial$module-loading/admon-bundling-plugin-langs.adoc[] -include::partial$plugin-files/plugin-file-list-autocorrect.adoc[] - -[[table-of-contents]] -=== Table of Contents (`+tableofcontents+`) - -include::partial$module-loading/admon-bundling-plugin-langs.adoc[] - -include::partial$plugin-files/plugin-file-list-tableofcontents.adoc[] - [[community-plugins]] -== Community plugins - -[[list-styles]] -=== List Styles (`+advlist+`) - -include::partial$plugin-files/plugin-file-list-advlist.adoc[] - -[[anchor]] -=== Anchor (`+anchor+`) - -include::partial$plugin-files/plugin-file-list-anchor.adoc[] - -[[autolink]] -=== Autolink (`+autolink+`) - -include::partial$plugin-files/plugin-file-list-autolink.adoc[] - -[[autoresize]] -=== Autoresize (`+autoresize+`) - -include::partial$plugin-files/plugin-file-list-autoresize.adoc[] - -[[autosave]] -=== Autosave (`+autosave+`) - -include::partial$plugin-files/plugin-file-list-autosave.adoc[] +=== Community plugins -[[character-map]] -=== Character Map (`+charmap+`) +include::partial$plugin-files/plugin-file-bundling-message.adoc[] -include::partial$plugin-files/plugin-file-list-charmap.adoc[] - -[[code]] -=== Code (`+code+`) - -include::partial$plugin-files/plugin-file-list-code.adoc[] - -[[codesamplecodesample]] -=== Code Sample (`+codesample+`) - -include::partial$plugin-files/plugin-file-list-codesample.adoc[] - -[[directionality]] -=== Directionality (`+directionality+`) - -include::partial$plugin-files/plugin-file-list-directionality.adoc[] +include::partial$plugin-files/plugin-file-bundling-also-requires.adoc[] [[emoticons]] -=== Emoticons (`+emoticons+`) +==== Emoticons (`+emoticons+`) include::partial$plugin-files/plugin-file-list-emoticons.adoc[] -[[full-screen]] -=== Full Screen (`+fullscreen+`) - -include::partial$plugin-files/plugin-file-list-fullscreen.adoc[] - -[[help]] -=== Help (`+help+`) - -include::partial$plugin-files/plugin-file-list-help.adoc[] - -[[image]] -=== Image (`+image+`) - -include::partial$plugin-files/plugin-file-list-image.adoc[] - -[[import-css]] -=== Import CSS (`+importcss+`) - -include::partial$plugin-files/plugin-file-list-importcss.adoc[] - -[[insert-datetime]] -=== Insert Date/Time (`+insertdatetime+`) - -include::partial$plugin-files/plugin-file-list-insertdatetime.adoc[] - -[[link]] -=== Link (`+link+`) - -include::partial$plugin-files/plugin-file-list-link.adoc[] - -[[lists]] -=== Lists (`+lists+`) - -include::partial$plugin-files/plugin-file-list-lists.adoc[] - -[[media]] -=== Media (`+media+`) - -include::partial$plugin-files/plugin-file-list-media.adoc[] - -[[nonbreaking-space]] -=== Nonbreaking Space (`+nonbreaking+`) - -include::partial$plugin-files/plugin-file-list-nonbreaking.adoc[] - -[[page-break]] -=== Page Break (`+pagebreak+`) - -include::partial$plugin-files/plugin-file-list-pagebreak.adoc[] - -[[preview]] -=== Preview (`+preview+`) - -include::partial$plugin-files/plugin-file-list-preview.adoc[] - -[[quick-toolbar]] -=== Quick Toolbar (`+quickbars+`) - -include::partial$plugin-files/plugin-file-list-quickbars.adoc[] - -[[save]] -=== Save (`+save+`) - -include::partial$plugin-files/plugin-file-list-save.adoc[] - -[[search-and-replace]] -=== Search and Replace (`+searchreplace+`) - -include::partial$plugin-files/plugin-file-list-searchreplace.adoc[] - -[[table]] -=== Table (`+table+`) - -include::partial$plugin-files/plugin-file-list-table.adoc[] - -[[visual-blocks]] -=== Visual Blocks (`+visualblocks+`) - -include::partial$plugin-files/plugin-file-list-visualblocks.adoc[] - -[[visual-characters]] -=== Visual Characters (`+visualchars+`) - -include::partial$plugin-files/plugin-file-list-visualchars.adoc[] - -[[word-count]] -=== Word Count (`+wordcount+`) - -include::partial$plugin-files/plugin-file-list-wordcount.adoc[] - [[plugin-language-files]] -== Plugin language files +=== Plugin language files include::partial$module-loading/bundling-plugin-language-files.adoc[] \ No newline at end of file diff --git a/modules/ROOT/partials/module-loading/bundling-plugin-language-files.adoc b/modules/ROOT/partials/module-loading/bundling-plugin-language-files.adoc index 602ebcafe1..d58dac3256 100644 --- a/modules/ROOT/partials/module-loading/bundling-plugin-language-files.adoc +++ b/modules/ROOT/partials/module-loading/bundling-plugin-language-files.adoc @@ -1,43 +1,43 @@ -IMPORTANT: Replace `` with the specific plugin name when adding the plugin language files to your config. +IMPORTANT: Replace `++` placeholder with the specific `plugincode` when adding the plugin language files to your config. [source, js] ---- -./plugins//langs/ar.js -./plugins//langs/bg_BG.js -./plugins//langs/ca.js -./plugins//langs/cs.js -./plugins//langs/da.js -./plugins//langs/de.js -./plugins//langs/el.js -./plugins//langs/es.js -./plugins//langs/eu.js -./plugins//langs/fa.js -./plugins//langs/fi.js -./plugins//langs/fr_FR.js -./plugins//langs/he_IL.js -./plugins//langs/hi.js -./plugins//langs/hr.js -./plugins//langs/hu_HU.js -./plugins//langs/id.js -./plugins//langs/it.js -./plugins//langs/ja.js -./plugins//langs/kk.js -./plugins//langs/ko_KR.js -./plugins//langs/ms.js -./plugins//langs/nb_NO.js -./plugins//langs/nl.js -./plugins//langs/pl.js -./plugins//langs/pt_BR.js -./plugins//langs/pt_PT.js -./plugins//langs/ro.js -./plugins//langs/ru.js -./plugins//langs/sk.js -./plugins//langs/sl_SI.js -./plugins//langs/sv_SE.js -./plugins//langs/th_TH.js -./plugins//langs/tr.js -./plugins//langs/uk.js -./plugins//langs/vi.js -./plugins//langs/zh_CN.js -./plugins//langs/zh_TW.js +./plugins//langs/ar.js +./plugins//langs/bg_BG.js +./plugins//langs/ca.js +./plugins//langs/cs.js +./plugins//langs/da.js +./plugins//langs/de.js +./plugins//langs/el.js +./plugins//langs/es.js +./plugins//langs/eu.js +./plugins//langs/fa.js +./plugins//langs/fi.js +./plugins//langs/fr_FR.js +./plugins//langs/he_IL.js +./plugins//langs/hi.js +./plugins//langs/hr.js +./plugins//langs/hu_HU.js +./plugins//langs/id.js +./plugins//langs/it.js +./plugins//langs/ja.js +./plugins//langs/kk.js +./plugins//langs/ko_KR.js +./plugins//langs/ms.js +./plugins//langs/nb_NO.js +./plugins//langs/nl.js +./plugins//langs/pl.js +./plugins//langs/pt_BR.js +./plugins//langs/pt_PT.js +./plugins//langs/ro.js +./plugins//langs/ru.js +./plugins//langs/sk.js +./plugins//langs/sl_SI.js +./plugins//langs/sv_SE.js +./plugins//langs/th_TH.js +./plugins//langs/tr.js +./plugins//langs/uk.js +./plugins//langs/vi.js +./plugins//langs/zh_CN.js +./plugins//langs/zh_TW.js ---- \ No newline at end of file diff --git a/modules/ROOT/partials/module-loading/bundling-plugins-that-cant-bundle.adoc b/modules/ROOT/partials/module-loading/bundling-plugins-that-cant-bundle.adoc deleted file mode 100644 index 5423d522c6..0000000000 --- a/modules/ROOT/partials/module-loading/bundling-plugins-that-cant-bundle.adoc +++ /dev/null @@ -1,12 +0,0 @@ -[IMPORTANT] -==== -The following premium plugins *can not* be bundled if the {productname} version is earlier than **6.8.0**. However, if the {productname} version is equivalent to **v6.8.0** or **later**, the following premium plugins can be bundled: - -* Accessibility Checker (`+a11ychecker+`) -* Comments (`+tinycomments+`) -* Enhanced Code Editor (`+advcode+`) -* Enhanced Media Embed (`+mediaembed+`) -* Link Checker (`+linkchecker+`) -* Mentions (`+mentions+`) -* Page Embed (`+pageembed+`) -==== diff --git a/modules/ROOT/partials/module-loading/bundling-rollup-es6-npm_editor.adoc b/modules/ROOT/partials/module-loading/bundling-rollup-es6-npm_editor.adoc index 66a0fd0280..ce7dbbdfbd 100644 --- a/modules/ROOT/partials/module-loading/bundling-rollup-es6-npm_editor.adoc +++ b/modules/ROOT/partials/module-loading/bundling-rollup-es6-npm_editor.adoc @@ -28,11 +28,9 @@ import 'tinymce/plugins/link'; import 'tinymce/plugins/lists'; import 'tinymce/plugins/table'; -/* Import premium plugins */ +/* Import premium plugins by replacing */ /* NOTE: Download separately and add these to /src/plugins */ -/* import './plugins/checklist/plugin'; */ -/* import './plugins/powerpaste/plugin'; */ -/* import './plugins/powerpaste/js/wordimport'; */ +/* import './plugins/'; */ /* content UI CSS is required */ import contentUiSkinCss from 'tinymce/skins/ui/oxide/content.css'; @@ -51,4 +49,4 @@ export function render () { content_style: contentUiSkinCss.toString() + '\n' + contentCss.toString(), }); }; ----- +---- \ No newline at end of file diff --git a/modules/ROOT/partials/module-loading/bundling-rollup-es6-zip_editor.adoc b/modules/ROOT/partials/module-loading/bundling-rollup-es6-zip_editor.adoc index 9e26aa0024..f04de11c0a 100644 --- a/modules/ROOT/partials/module-loading/bundling-rollup-es6-zip_editor.adoc +++ b/modules/ROOT/partials/module-loading/bundling-rollup-es6-zip_editor.adoc @@ -20,19 +20,17 @@ import '../tinymce/js/tinymce/models/dom/model'; import '../tinymce/js/tinymce/skins/ui/oxide/skin.css'; /* Import plugins */ -import '../tinymce/js/tinymce/plugins/advlist/plugin'; -import '../tinymce/js/tinymce/plugins/code/plugin'; -import '../tinymce/js/tinymce/plugins/emoticons/plugin'; +import '../tinymce/js/tinymce/plugins/advlist'; +import '../tinymce/js/tinymce/plugins/code'; +import '../tinymce/js/tinymce/plugins/emoticons'; import '../tinymce/js/tinymce/plugins/emoticons/js/emojis'; -import '../tinymce/js/tinymce/plugins/link/plugin'; -import '../tinymce/js/tinymce/plugins/lists/plugin'; -import '../tinymce/js/tinymce/plugins/table/plugin'; +import '../tinymce/js/tinymce/plugins/link'; +import '../tinymce/js/tinymce/plugins/lists'; +import '../tinymce/js/tinymce/plugins/table'; /* Import premium plugins */ /* NOTE: Download separately and add these to /src/plugins */ -/* import './plugins/checklist/plugin'; */ -/* import './plugins/powerpaste/plugin'; */ -/* import './plugins/powerpaste/js/wordimport'; */ +/* import './plugins/'; */ /* content UI CSS is required */ import contentUiSkinCss from '../tinymce/js/tinymce/skins/ui/oxide/content.css'; @@ -51,4 +49,4 @@ export function render () { content_style: contentUiSkinCss.toString() + '\n' + contentCss.toString(), }); }; ----- +---- \ No newline at end of file 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 176d1caed3..a26d8d2c51 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 @@ -32,9 +32,7 @@ import 'tinymce/plugins/table'; /* Import premium plugins */ /* NOTE: Download separately and add these to /src/plugins */ -/* import './plugins/checklist/plugin.js'; */ -/* import './plugins/powerpaste/plugin.js'; */ -/* import './plugins/powerpaste/js/wordimport.js'; */ +/* import './plugins/'; */ /* content UI CSS is required */ import contentUiSkinCss from 'tinymce/skins/ui/oxide/content.js'; diff --git a/modules/ROOT/partials/module-loading/bundling-webpack-cjs-zip_editor.adoc b/modules/ROOT/partials/module-loading/bundling-webpack-cjs-zip_editor.adoc index 5c8747bd2f..3440348359 100644 --- a/modules/ROOT/partials/module-loading/bundling-webpack-cjs-zip_editor.adoc +++ b/modules/ROOT/partials/module-loading/bundling-webpack-cjs-zip_editor.adoc @@ -20,13 +20,13 @@ require('../tinymce/js/tinymce/models/dom/model.js'); require('../tinymce/js/tinymce/skins/ui/oxide/skin.css'); /* Import plugins - include the relevant plugin in the 'plugins' option. */ -require('../tinymce/js/tinymce/plugins/advlist/plugin.js'); -require('../tinymce/js/tinymce/plugins/code/plugin.js'); -require('../tinymce/js/tinymce/plugins/emoticons/plugin.js'); +require('../tinymce/js/tinymce/plugins/advlist'); +require('../tinymce/js/tinymce/plugins/code'); +require('../tinymce/js/tinymce/plugins/emoticons'); require('../tinymce/js/tinymce/plugins/emoticons/js/emojis'); -require('../tinymce/js/tinymce/plugins/link/plugin.js'); -require('../tinymce/js/tinymce/plugins/lists/plugin.js'); -require('../tinymce/js/tinymce/plugins/table/plugin.js'); +require('../tinymce/js/tinymce/plugins/link'); +require('../tinymce/js/tinymce/plugins/lists'); +require('../tinymce/js/tinymce/plugins/table'); /* content UI CSS is required */ const contentUiSkinCss = require('../tinymce/js/tinymce/skins/ui/oxide/content.css'); diff --git a/modules/ROOT/partials/module-loading/bundling-webpack-es6-npm_editor.adoc b/modules/ROOT/partials/module-loading/bundling-webpack-es6-npm_editor.adoc index 66a0fd0280..0191d2a446 100644 --- a/modules/ROOT/partials/module-loading/bundling-webpack-es6-npm_editor.adoc +++ b/modules/ROOT/partials/module-loading/bundling-webpack-es6-npm_editor.adoc @@ -30,9 +30,7 @@ import 'tinymce/plugins/table'; /* Import premium plugins */ /* NOTE: Download separately and add these to /src/plugins */ -/* import './plugins/checklist/plugin'; */ -/* import './plugins/powerpaste/plugin'; */ -/* import './plugins/powerpaste/js/wordimport'; */ +/* import './plugins/'; */ /* content UI CSS is required */ import contentUiSkinCss from 'tinymce/skins/ui/oxide/content.css'; diff --git a/modules/ROOT/partials/module-loading/bundling-webpack-es6-zip_editor.adoc b/modules/ROOT/partials/module-loading/bundling-webpack-es6-zip_editor.adoc index 9e26aa0024..f04de11c0a 100644 --- a/modules/ROOT/partials/module-loading/bundling-webpack-es6-zip_editor.adoc +++ b/modules/ROOT/partials/module-loading/bundling-webpack-es6-zip_editor.adoc @@ -20,19 +20,17 @@ import '../tinymce/js/tinymce/models/dom/model'; import '../tinymce/js/tinymce/skins/ui/oxide/skin.css'; /* Import plugins */ -import '../tinymce/js/tinymce/plugins/advlist/plugin'; -import '../tinymce/js/tinymce/plugins/code/plugin'; -import '../tinymce/js/tinymce/plugins/emoticons/plugin'; +import '../tinymce/js/tinymce/plugins/advlist'; +import '../tinymce/js/tinymce/plugins/code'; +import '../tinymce/js/tinymce/plugins/emoticons'; import '../tinymce/js/tinymce/plugins/emoticons/js/emojis'; -import '../tinymce/js/tinymce/plugins/link/plugin'; -import '../tinymce/js/tinymce/plugins/lists/plugin'; -import '../tinymce/js/tinymce/plugins/table/plugin'; +import '../tinymce/js/tinymce/plugins/link'; +import '../tinymce/js/tinymce/plugins/lists'; +import '../tinymce/js/tinymce/plugins/table'; /* Import premium plugins */ /* NOTE: Download separately and add these to /src/plugins */ -/* import './plugins/checklist/plugin'; */ -/* import './plugins/powerpaste/plugin'; */ -/* import './plugins/powerpaste/js/wordimport'; */ +/* import './plugins/'; */ /* content UI CSS is required */ import contentUiSkinCss from '../tinymce/js/tinymce/skins/ui/oxide/content.css'; @@ -51,4 +49,4 @@ export function render () { content_style: contentUiSkinCss.toString() + '\n' + contentCss.toString(), }); }; ----- +---- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-apis/accordion-apis.adoc b/modules/ROOT/partials/plugin-apis/accordion-apis.adoc deleted file mode 100644 index 0adbbef325..0000000000 --- a/modules/ROOT/partials/plugin-apis/accordion-apis.adoc +++ /dev/null @@ -1,24 +0,0 @@ -[cols="1,1,4",options="header"] -|=== -|Name |Arguments |Description -| | | -| | | -| | | -| | | -|=== - - -.Examples -[source,js] ----- -// what this example does -tinymce.activeEditor.plugins.accordion.(); - -// what this example does -tinymce.activeEditor.plugins.accordion.(); - -// what this example does -tinymce.activeEditor.plugins.accordion.(); -// what this example does -tinymce.activeEditor.plugins.accordion.(); ----- diff --git a/modules/ROOT/partials/plugin-apis/comments-apis.adoc b/modules/ROOT/partials/plugin-apis/comments-apis.adoc new file mode 100644 index 0000000000..211e696f9f --- /dev/null +++ b/modules/ROOT/partials/plugin-apis/comments-apis.adoc @@ -0,0 +1,188 @@ +== APIs + +The {pluginname} plugin provides the xref:comments-commands-events-apis#getEventLog[`+getEventLog()+`] API, as well as an annotator named xref:comments-commands-events-apis#tinycomments-annotator[`+'tinycomments'+`] created using the xref:annotations.adoc[`+editor.annotator+` API]. + +[[getEventLog]] +=== getEventLog() + +include::partial$misc/admon-requires-6.1v.adoc[] + +The `getEventLog` returns a log that contains information and timestamps of all changes to comments, including when: + +* A new comment is added. + +[source,js] +---- +{ + "type": "create", + "timestamp": "2024-10-01T03:07:53.771Z", + "conversationUid": "annotation-r1nn5xdo5ye", + "conversationContext": "Welcome", + "conversationContent": "new comment", + "conversationAuthor": { + "author": "DEMO USER", + "authorName": "DEMO USER" + } +}, +---- + +* A comment is edited. + +[source,js] +---- +{ + "type": "edit-comment", + "timestamp": "2024-10-01T03:08:06.551Z", + "conversationUid": "annotation-r1nn5xdo5ye", + "commentUid": "annotation-r1nn5xdo5ye", + "conversationContext": "Welcome", + "conversationContent": "new comment", + "conversationCreatedAt": "2024-10-01T03:07:53.771Z", + "commentContent": "new comment (Edit comment)", + "commentAuthor": { + "author": "DEMO USER", + "authorName": "DEMO USER" + }, + "conversationAuthor": { + "author": "DEMO USER", + "authorName": "DEMO USER" + } +}, +---- + +* A reply to a comment is added. + +[source,js] +---- +{ + "type": "reply", + "timestamp": "2024-10-01T03:07:53.771Z", + "conversationUid": "annotation-r1nn5xdo5ye", + "commentUid": "annotation-uh00rb41kma", + "conversationContext": "Welcome", + "conversationContent": "new comment (Edit comment)", + "conversationCreatedAt": "2024-10-01T03:07:53.771Z", + "commentContent": "reply to existing comment", + "commentAuthor": { + "author": "DEMO USER", + "authorName": "DEMO USER" + }, + "conversationAuthor": { + "author": "DEMO USER", + "authorName": "DEMO USER" + } +}, +---- + +* A comment is resolved. + +[source,js] +---- +{ + "type": "resolve", + "timestamp": "2024-10-01T03:08:25.783Z", + "conversationUid": "annotation-r1nn5xdo5ye", + "conversationContext": "Welcome", + "conversationContent": "new comment (Edit comment)", + "conversationAuthor": { + "author": "DEMO USER", + "authorName": "DEMO USER" + } +}, +---- + +* A comment is deleted. + +[source,js] +---- +{ + "type": "delete-comment", + "timestamp": "2024-10-01T03:08:23.292Z", + "conversationUid": "annotation-r1nn5xdo5ye", + "commentUid": "annotation-uh00rb41kma", + "conversationContext": "Welcome", + "conversationContent": "new comment (Edit comment)", + "commentContent": "reply to existing comment", + "commentAuthor": { + "author": "DEMO USER", + "authorName": "DEMO USER" + }, + "conversationAuthor": { + "author": "DEMO USER", + "authorName": "DEMO USER" + } +}, +---- + +The event log can be retrieved either in full or with the `after` option, which restricts the returned list to Comment events after a time-stamp date in the link:https://en.wikipedia.org/wiki/ISO_8601[ISO-8601] format, both shown in the following: + +==== With the Mentions plugin + +When the xref:mentions.adoc[Mentions] plugin is enabled, each of the above events will include the `mentionedUids` property, which contains an array of UIDs mentioned in the comment. The `mentionedUids` property is only included when the xref:mentions.adoc[Mentions] plugin is enabled. + +It is recommended to use this API to retrieve which users have been mentioned in comments. + +[NOTE] +==== +The `mentionedUids` array captures strings following the `@` symbol without verifying if they correspond to valid user IDs. It is the integrator's responsibility to validate these strings against the database to ensure they represent valid users. + +For guidance on retrieving and verifying the `mentionedUids` array, refer to the xref:#example-using-geteventlog[getEventLog example]. + +==== + +[[example-using-geteventlog]] +==== Example: using `+getEventLog()+` + +[source,js] +---- +// Sample user database +const userDb = { + "johnsmith": { + "id": "johnsmith", + "name": "John Smith", + "fullName": "John Smith", + "description": "Company Founder", + "image": "https://i.pravatar.cc/150?img=11" + }, + "jennynichols": { + "id": "jennynichols", + "name": "Jenny Nichols", + "fullName": "Jenny Nichols", + "description": "Marketing Director", + "image": "https://i.pravatar.cc/150?img=10" + } +}; + +const comments = tinymce.activeEditor.plugins.tinycomments; + +console.log(comments.getEventLog()); +console.log(comments.getEventLog( + { after: '2022-02-22T12:34:56Z' } // ISO-8601 standard: YYYY-MM-DDThh:mm:ssZ +)); + +const eventLog = comments.getEventLog(); +const events = eventLog.events; + +// Ensure that the mentioned users are valid users in the database +const validatedEvents = JSON.parse(JSON.stringify(events)); +validatedEvents.forEach((event) => { + // Filter out invalid users - change this to your own validation logic + event.mentionedUids = event.mentionedUids ? event.mentionedUids.filter((uid) => userDb[uid]) : undefined; +}); + +const mentionedUsers = validatedEvents.flatMap(({ mentionedUids }) => mentionedUids || []); +console.log(mentionedUsers); + +let whoMentionedWho = {}; +validatedEvents.forEach((event) => { + if ((event.type === "create" || event.type === "reply") && event.mentionedUids !== undefined) { + console.log(event); + if (whoMentionedWho[event.conversationAuthor.author] === undefined) { + whoMentionedWho[event.conversationAuthor.author] = [...event.mentionedUids]; + } else { + whoMentionedWho[event.conversationAuthor.author].push(...event.mentionedUids); + } + } +}); +console.log(whoMentionedWho); +---- diff --git a/modules/ROOT/partials/plugin-apis/revisionhistory-apis.adoc b/modules/ROOT/partials/plugin-apis/revisionhistory-apis.adoc new file mode 100644 index 0000000000..17dd3a5c2b --- /dev/null +++ b/modules/ROOT/partials/plugin-apis/revisionhistory-apis.adoc @@ -0,0 +1,29 @@ +[source,ts] +---- +interface PluginAPI { + diff: (originalHTML: string, changedHTML: string) => string +} +---- + +[[diff]] +=== `diff` + +Returns a HTML string with annotations indicating the changes in `originalHTML` relative to `changedHTML`. The styling of annotations can be customized via xref:revisionhistory_diff_classes[`+revisionhistory_diff_classes+`] option. + +include::partial$misc/admon-requires-7.1v.adoc[] + +.Example +[source,js] +---- +const input1 = `

    The banner is red

    `; +const input2 = `

    The flag is red

    `; +tinymce.activeEditor.plugins.revisionhistory.diff(input1, input2); +/* +Expected output: +

    The + bannerflag + is +red +

    +*/ +---- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-bundling-also-requires.adoc b/modules/ROOT/partials/plugin-files/plugin-file-bundling-also-requires.adoc new file mode 100644 index 0000000000..ee9dd98e20 --- /dev/null +++ b/modules/ROOT/partials/plugin-files/plugin-file-bundling-also-requires.adoc @@ -0,0 +1,2 @@ +[TIP] +The below plugin also requires additional files to be included along side the xref:bundling-plugins.adoc#base-folder[base folder]. \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-bundling-message.adoc b/modules/ROOT/partials/plugin-files/plugin-file-bundling-message.adoc new file mode 100644 index 0000000000..6ed4c19012 --- /dev/null +++ b/modules/ROOT/partials/plugin-files/plugin-file-bundling-message.adoc @@ -0,0 +1 @@ +When bundling, replace the `+plugincode+` with the specific plugins in your {productname} configuration. \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-index.js.adoc b/modules/ROOT/partials/plugin-files/plugin-file-index.js.adoc new file mode 100644 index 0000000000..d6e51914c7 --- /dev/null +++ b/modules/ROOT/partials/plugin-files/plugin-file-index.js.adoc @@ -0,0 +1,9 @@ +[[base-folder]] +== Required base folder + +The below base folder is required for each plugin when bundling {productname}. + +[source, js] +---- +./plugins/ +---- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-a11ychecker.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-a11ychecker.adoc deleted file mode 100644 index 96654c8258..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-a11ychecker.adoc +++ /dev/null @@ -1,12 +0,0 @@ -.Base js file. -[source, js] ----- -./plugins/a11ychecker/plugin.js ----- - -.css or bundled css -[source, js] ----- -./plugins/a11ychecker/css/annotations.css // or -./plugins/a11ychecker/css/annotations.js // bundling requires v6.8.0 or later. ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-advcode.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-advcode.adoc deleted file mode 100644 index 9e7c646d1a..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-advcode.adoc +++ /dev/null @@ -1,19 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/advcode/plugin.js ----- - -.css or bundled css -[source, js] ----- -./plugins/advcode/codemirror.min.css //or -./plugins/advcode/codemirror_css.js // bundling requires v6.8.0 or later. ----- - -.other js files -[source, js] ----- -./plugins/advcode/codemirror.min.js -./plugins/advcode/customeditor.js ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-advlist.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-advlist.adoc deleted file mode 100644 index 1b3bb7d9cc..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-advlist.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/advlist/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-advtable.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-advtable.adoc deleted file mode 100644 index 318c0748f1..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-advtable.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/advtable/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-anchor.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-anchor.adoc deleted file mode 100644 index 46ead7f860..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-anchor.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/anchor/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-autocorrect.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-autocorrect.adoc deleted file mode 100644 index 3761112a86..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-autocorrect.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/autocorrect/plugin.js ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-autolink.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-autolink.adoc deleted file mode 100644 index 5302b7ab94..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-autolink.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/autolink/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-autoresize.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-autoresize.adoc deleted file mode 100644 index a123e339d9..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-autoresize.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/autoresize/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-autosave.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-autosave.adoc deleted file mode 100644 index f58d66cc5a..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-autosave.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/autosave/plugin.js ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-casechange.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-casechange.adoc deleted file mode 100644 index c37e517350..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-casechange.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/casechange/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-charmap.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-charmap.adoc deleted file mode 100644 index 0febba14b9..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-charmap.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/charmap/plugin.js ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-checklist.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-checklist.adoc deleted file mode 100644 index a1f3cff071..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-checklist.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/checklist/plugin.js ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-code.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-code.adoc deleted file mode 100644 index 7bef9a5371..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-code.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/code/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-codesample.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-codesample.adoc deleted file mode 100644 index c631f9992c..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-codesample.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/codesample/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-directionality.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-directionality.adoc deleted file mode 100644 index 237cf87c11..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-directionality.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/directionality/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-editimage.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-editimage.adoc deleted file mode 100644 index cd6f1de99d..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-editimage.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/editimage/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-emoticons.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-emoticons.adoc index 71f0922db5..c835128770 100644 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-emoticons.adoc +++ b/modules/ROOT/partials/plugin-files/plugin-file-list-emoticons.adoc @@ -1,7 +1,9 @@ -.Base js file +.Requires other js files [source, js] ---- -./plugins/emoticons/plugin.js ./plugins/emoticons/js/emojiimages.js ./plugins/emoticons/js/emojis.js ---- + +[NOTE] +Only one of the above `.js` files are required, depending on which one is chosen through the `emoticons_database` setting. \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-exportpdf.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-exportpdf.adoc deleted file mode 100644 index 00513e455e..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-exportpdf.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/exportpdf/plugin.js ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-exportword.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-exportword.adoc deleted file mode 100644 index cf939ad20b..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-exportword.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/exportword/plugin.js ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-footnotes.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-footnotes.adoc deleted file mode 100644 index f142867931..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-footnotes.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/footnotes/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-formatpainter.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-formatpainter.adoc deleted file mode 100644 index 8cd2b84be2..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-formatpainter.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/formatpainter/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-fullscreen.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-fullscreen.adoc deleted file mode 100644 index 8c06cc566b..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-fullscreen.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/fullscreen/plugin.js ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-help.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-help.adoc deleted file mode 100644 index 513eee5909..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-help.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/help/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-image.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-image.adoc deleted file mode 100644 index a9c2602394..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-image.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/image/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-importcss.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-importcss.adoc deleted file mode 100644 index ff9ffc5554..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-importcss.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/importcss/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-importword.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-importword.adoc deleted file mode 100644 index 2456f79fc2..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-importword.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/importword/plugin.js ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-insertdatetime.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-insertdatetime.adoc deleted file mode 100644 index e3075e73cb..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-insertdatetime.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/insertdatetime/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-link.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-link.adoc deleted file mode 100644 index 14eacc69af..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-link.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/link/plugin.js ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-linkchecker.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-linkchecker.adoc deleted file mode 100644 index 8dce71103c..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-linkchecker.adoc +++ /dev/null @@ -1,12 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/linkchecker/plugin.js ----- - -.css or bundled css -[source, js] ----- -./plugins/linkchecker/content.min.css //or -./plugins/linkchecker/content_css.js // bundling requires v6.8.0 or later. ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-lists.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-lists.adoc deleted file mode 100644 index e3cd76456b..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-lists.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/lists/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-markdown.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-markdown.adoc deleted file mode 100644 index 5bbb27b707..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-markdown.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/markdown/plugin.js ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-media.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-media.adoc deleted file mode 100644 index aac8d116e5..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-media.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/media/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-mediaembed.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-mediaembed.adoc deleted file mode 100644 index f1364d71a1..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-mediaembed.adoc +++ /dev/null @@ -1,12 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/mediaembed/plugin.js ----- - -.css or bundled css -[source, js] ----- -./plugins/mediaembed/content.min.css //or -./plugins/mediaembed/content_css.js // bundling requires v6.8.0 or later. ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-mentions.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-mentions.adoc deleted file mode 100644 index 0d76a3595a..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-mentions.adoc +++ /dev/null @@ -1,12 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/mentions/plugin.js ----- - -.css or bundled css -[source, js] ----- -./plugins/mentions/css/mentions.css //or -./plugins/mentions/css/mentions.js // bundling requires v6.8.0 or later. ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-mergetags.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-mergetags.adoc deleted file mode 100644 index 85cc860a09..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-mergetags.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/mergetags/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-nonbreaking.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-nonbreaking.adoc deleted file mode 100644 index bda47311c0..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-nonbreaking.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/nonbreaking/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-pagebreak.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-pagebreak.adoc deleted file mode 100644 index e796db7f97..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-pagebreak.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/pagebreak/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-pageembed.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-pageembed.adoc deleted file mode 100644 index 635a839e6d..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-pageembed.adoc +++ /dev/null @@ -1,12 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/pageembed/plugin.js ----- - -.css or bundled css -[source, js] ----- -./plugins/pageembed/css/empa30.css //or -./plugins/pageembed/css/empa30.js // bundling requires v6.8.0 or later. ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-permanentpen.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-permanentpen.adoc deleted file mode 100644 index 716902cd5c..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-permanentpen.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/permanentpen/plugin.js ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-powerpaste.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-powerpaste.adoc deleted file mode 100644 index 35ef74418f..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-powerpaste.adoc +++ /dev/null @@ -1,11 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/powerpaste/plugin.js ----- - -.other js files -[source, js] ----- -./plugins/powerpaste/js/wordimport.js ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-preview.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-preview.adoc deleted file mode 100644 index ca2a54702d..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-preview.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/preview/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-quickbars.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-quickbars.adoc deleted file mode 100644 index 123c58c438..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-quickbars.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/quickbars/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-save.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-save.adoc deleted file mode 100644 index 0623d5b80f..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-save.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/save/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-searchreplace.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-searchreplace.adoc deleted file mode 100644 index 6c89e4a13f..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-searchreplace.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/searchreplace/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-table.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-table.adoc deleted file mode 100644 index a2fa6e49d7..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-table.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/table/plugin.js ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-tableofcontents.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-tableofcontents.adoc deleted file mode 100644 index 9599110120..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-tableofcontents.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/tableofcontents/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-tinycomments.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-tinycomments.adoc deleted file mode 100644 index dcd3744dd9..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-tinycomments.adoc +++ /dev/null @@ -1,18 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/tinycomments/plugin.js ----- - -.css or bundled css -[source, js] ----- -./plugins/tinycomments/css/tinycomments.css //or -./plugins/tinycomments/css/tinycomments.js // bundling requires v6.8.0 or later. ----- - -.other js files -[source, js] ----- -./plugins/tinycomments/js/tinycomments-sidebar.js ----- \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-tinymcespellchecker.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-tinymcespellchecker.adoc deleted file mode 100644 index f078bb8250..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-tinymcespellchecker.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/tinymcespellchecker/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-visualblocks.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-visualblocks.adoc deleted file mode 100644 index c90153f2aa..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-visualblocks.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/visualblocks/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-visualchars.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-visualchars.adoc deleted file mode 100644 index a7fe145542..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-visualchars.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/visualchars/plugin.js ----- diff --git a/modules/ROOT/partials/plugin-files/plugin-file-list-wordcount.adoc b/modules/ROOT/partials/plugin-files/plugin-file-list-wordcount.adoc deleted file mode 100644 index cc01decc10..0000000000 --- a/modules/ROOT/partials/plugin-files/plugin-file-list-wordcount.adoc +++ /dev/null @@ -1,5 +0,0 @@ -.Base js file -[source, js] ----- -./plugins/wordcount/plugin.js ----- diff --git a/modules/ROOT/partials/plugins/comments-highlighting-css.adoc b/modules/ROOT/partials/plugins/comments-highlighting-css.adoc index 54304ffc6d..6de7d6ea97 100644 --- a/modules/ROOT/partials/plugins/comments-highlighting-css.adoc +++ b/modules/ROOT/partials/plugins/comments-highlighting-css.adoc @@ -2,8 +2,8 @@ The highlight styles are now a part of the overall content skin and are changed through customizing the skin. -{productname} open source project https://github.com/tinymce/oxide/blob/master/src/less/theme/content/comments/comments.less[oxide] (default skin), defines the variables used for changing the annotation colours. +{productname} open source project https://github.com/tinymce/oxide/blob/master/src/less/theme/content/comments/comments.less[oxide] (default skin), defines the variables used for changing the annotation colors. Refer to the xref:creating-a-skin.adoc[documentation] for building a skin using this repo. -For more information on configuring {productname} formats, refer to the xref:content-formatting.adoc#formats[formats] section. +For more information on configuring {productname} formats, refer to the xref:content-formatting.adoc#formats[formats] section. \ No newline at end of file diff --git a/modules/ROOT/partials/plugins/comments-open-sidebar.adoc b/modules/ROOT/partials/plugins/comments-open-sidebar.adoc index 45df1ac28d..f5f73286e4 100644 --- a/modules/ROOT/partials/plugins/comments-open-sidebar.adoc +++ b/modules/ROOT/partials/plugins/comments-open-sidebar.adoc @@ -1,9 +1,8 @@ -== Show the comments sidebar when TinyMCE loads +== Show the {pluginname} sidebar when TinyMCE loads -The xref:customsidebar.adoc#sidebar_show[`sidebar_show`] option can be used to show the comments sidebar when the editor is loaded. - -For example: +The xref:customsidebar.adoc#sidebar_show[`sidebar_show`] option can be used to show the {pluginname} sidebar when the editor is loaded. +.For example: ifeval::["{commentsMode}" == "callback"] [source,js] ---- @@ -18,6 +17,7 @@ tinymce.init({ tinycomments_delete_all, tinycomments_delete_comment, tinycomments_lookup, + tinycomments_fetch, sidebar_show: 'showcomments' }); ---- @@ -35,4 +35,4 @@ tinymce.init({ sidebar_show: 'showcomments' }); ---- -endif::[] +endif::[] \ No newline at end of file diff --git a/modules/ROOT/partials/plugins/spellchecker-content_langs.adoc b/modules/ROOT/partials/plugins/spellchecker-content_langs.adoc index c5c713ff82..f7d077b457 100644 --- a/modules/ROOT/partials/plugins/spellchecker-content_langs.adoc +++ b/modules/ROOT/partials/plugins/spellchecker-content_langs.adoc @@ -18,19 +18,33 @@ For example: [source,js] ---- tinymce.init({ - selector: 'textarea', // change this according to your HTML + selector: 'textarea', toolbar: 'language', plugins: 'tinymcespellchecker', content_langs: [ - { title: 'English (US)', code: 'en_US' }, - { title: 'English (US Medical)', code: 'en_US', customCode: 'en_US-medical' }, - { title: 'English (UK)', code: 'en_UK' }, - { title: 'English (UK Medical)', code: 'en_UK', customCode: 'en_UK-medical' }, - { title: 'Spanish', code: 'es' }, + { 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: 'Finnish', code: 'fi' }, { title: 'French', code: 'fr' }, - { title: 'German', code: 'de' }, - { title: 'Portuguese', code: 'pt' }, - { title: 'Chinese', code: 'zh' } - ] + { 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: 'Norwegian Nynorsk', code: 'nn' }, + { title: 'Polish', code: 'pl' }, + { 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' } + ], }); ----- +---- \ No newline at end of file diff --git a/modules/ROOT/partials/private-public-key-pairs-for-tiny-cloud-services.adoc b/modules/ROOT/partials/private-public-key-pairs-for-tiny-cloud-services.adoc new file mode 100644 index 0000000000..62b3b6f9e3 --- /dev/null +++ b/modules/ROOT/partials/private-public-key-pairs-for-tiny-cloud-services.adoc @@ -0,0 +1,10 @@ +The {pluginname} Server requires a _public_ key generated from the same _private_ key that will be used on your JSON Web Token (JWT) provider endpoint. The public key(s) stored on the {pluginname} Server are used to ensure that content is sent by authorized users. + +There are two methods for generating and adding a public key to your API key: + +== Generate a key pair using the {accountpage} JWT Keys page + +The link:{accountjwturl}[{accountpage} - JWT Keys] page provides a private/public key generator, providing a quick and secure way of generating the required keys. This generator will store a copy of the _public_ key, and provide a downloadable file for both the public and private keys. {companyname} does **not store** the _private_ key and the key pair **cannot** be retrieved later. + +[[generate-a-key-pair-locally]] +== Generate a key pair locally \ No newline at end of file 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 ffa4d749db..4038fe8c91 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 @@ -5,18 +5,18 @@ Previously, before HTML content was passed to {productname} 5.x, it was parsed u The `SaxParser` API was developed in the then-absence of alternatives. -When this API’s validate setting was enabled — `validate: true` — `SaxParser` removed elements and attributes that did not fit the declared schema. +When this API's validate setting was enabled — `validate: true` — `SaxParser` removed elements and attributes that did not fit the declared schema. And, over its lifetime, `SaxParser` was extended. For example, as of {productname} 5.9, the `SaxParser` API marked attributes with certain names or IDs as unsafe, because some names or IDs can cause the host browser to overwrite existing properties or functions. -For {productname} 6.0, however, this basic parser was removed and replaced with two significantly more thorough alternatives: +Since {productname} 6.0, this basic parser was removed and replaced with two significantly more thorough alternatives: . the https://developer.mozilla.org/en-US/docs/Web/API/DOMParser[native browser API], `DOMParser()`; and . the Free and Open Source _https://github.com/cure53/DOMPurify[XSS sanitizer for HTML, MathML and SVG]_, DOMPurify. -NOTE: {productname} uses DOMPurify 2.x, which was current at the time version 6 was developed. +NOTE: {productname} uses DOMPurify 3.x, which was current at the time {productname} {productmajorversion} was developed. -Before HTML (or XML) content is passed to {productname} 6.x, the `DOMParser` API parses the HTML (or XML) string into a https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model[DOM object]. As part of this process, `DOMParser` attempts to correct malformed HTML. +Before HTML (or XML) content is passed to {productname} {productmajorversion}, the `DOMParser` API parses the HTML (or XML) string into a https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model[DOM object]. As part of this process, `DOMParser` attempts to correct malformed HTML. For example, the following string: diff --git a/modules/ROOT/partials/toolbar-button-ids/comments-toolbar-buttons.adoc b/modules/ROOT/partials/toolbar-button-ids/comments-toolbar-buttons.adoc index cf7fb6bf1d..8bf3baa53a 100644 --- a/modules/ROOT/partials/toolbar-button-ids/comments-toolbar-buttons.adoc +++ b/modules/ROOT/partials/toolbar-button-ids/comments-toolbar-buttons.adoc @@ -2,5 +2,5 @@ |=== |Toolbar button identifier |Description |`+addcomment+` |Adds a comment at the cursor location or to the selected content. -|`+showcomments+` |Shows/hides comments present in the editor. +|`+showcomments+` |Shows/hides the {pluginname} sidebar UI and comments present in the editor. |=== diff --git a/modules/ROOT/partials/toolbar-button-ids/math-toolbar-buttons.adoc b/modules/ROOT/partials/toolbar-button-ids/math-toolbar-buttons.adoc new file mode 100644 index 0000000000..640532f480 --- /dev/null +++ b/modules/ROOT/partials/toolbar-button-ids/math-toolbar-buttons.adoc @@ -0,0 +1,5 @@ +[cols="1,3",options="header"] +|=== +|Toolbar button identifier |Description +|`+math+` |Opens the math modal dialog. +|=== \ No newline at end of file diff --git a/modules/ROOT/partials/toolbar-button-ids/uploadcare-toolbar-buttons.adoc b/modules/ROOT/partials/toolbar-button-ids/uploadcare-toolbar-buttons.adoc new file mode 100644 index 0000000000..27b724ae32 --- /dev/null +++ b/modules/ROOT/partials/toolbar-button-ids/uploadcare-toolbar-buttons.adoc @@ -0,0 +1,5 @@ +[cols="1,3",options="header"] +|=== +|Identifier |Description +| `+uploadcare+` | Inserts an image placeholder element. This placeholder supports image uploads via drag-and-drop, file selection, or by providing a URL. +|=== \ No newline at end of file diff --git a/package.json b/package.json index a69a23fec9..9a24a18b76 100644 --- a/package.json +++ b/package.json @@ -11,10 +11,13 @@ "build": "./-scripts/api-reference.sh", "build-local-ref": "./-scripts/api-reference-local.sh", "clean": "rm -rf ./build", - "nodemon-dev": "nodemon --exec yarn antora ./antora-playbook.yml", - "server": "http-server build/site/ --port 4000", - "serve": "npm-run-all -p nodemon-dev server", - "start": "yarn clean && yarn serve" + "nodemon": "nodemon --exec yarn antora ./antora-playbook.yml", + "nodemon-dev": "nodemon --exec yarn antora ./antora-playbook-local.yml", + "server": "http-server build/site/ --port 4000 -a localhost", + "serve": "npm-run-all -p nodemon server", + "serve-dev": "npm-run-all -p nodemon-dev server", + "start": "yarn clean && yarn serve", + "start-dev": "yarn clean && yarn serve-dev" }, "author": "Tiny Technologies Inc", "license": "CC-BY-NC-SA-3.0",