From ced42300f7e7b9464f1441002ac204518734cae5 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Wed, 19 Mar 2025 10:21:58 +1000 Subject: [PATCH 01/68] Initial setup --- modules/ROOT/nav.adoc | 1 + modules/ROOT/pages/trackchanges.adoc | 67 +++++++++++++++++++ .../partials/commands/trackchanges-cmds.adoc | 33 +++++++++ .../configuration/defaultmenuitems.adoc | 2 +- .../configuration/trackchanges-options.adoc | 57 ++++++++++++++++ .../partials/events/trackchanges-events.adoc | 17 +++++ .../partials/index-pages/premium-plugins.adoc | 5 ++ .../trackchanges-menu-items.adoc | 6 ++ .../partials/misc/admon-requires-8.0v.adoc | 1 + .../plugin-apis/trackchanges-apis.adoc | 23 +++++++ .../trackchanges-toolbar-buttons.adoc | 6 ++ 11 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 modules/ROOT/pages/trackchanges.adoc create mode 100644 modules/ROOT/partials/commands/trackchanges-cmds.adoc create mode 100644 modules/ROOT/partials/configuration/trackchanges-options.adoc create mode 100644 modules/ROOT/partials/events/trackchanges-events.adoc create mode 100644 modules/ROOT/partials/menu-item-ids/trackchanges-menu-items.adoc create mode 100644 modules/ROOT/partials/misc/admon-requires-8.0v.adoc create mode 100644 modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc create mode 100644 modules/ROOT/partials/toolbar-button-ids/trackchanges-toolbar-buttons.adoc diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc index d6035355f5..507e0c1b74 100644 --- a/modules/ROOT/nav.adoc +++ b/modules/ROOT/nav.adoc @@ -377,6 +377,7 @@ ***** xref:tinydrive-pick.adoc[The Pick API] ***** xref:tinydrive-type-interfaces.adoc[TypeScript interfaces] **** xref:tinydrive-changelog.adoc[Changelog] +*** xref:trackchanges.adoc[Track Changes] ** Open source plugins *** xref:accordion.adoc[Accordion] *** xref:anchor.adoc[Anchor] diff --git a/modules/ROOT/pages/trackchanges.adoc b/modules/ROOT/pages/trackchanges.adoc new file mode 100644 index 0000000000..9a686415a2 --- /dev/null +++ b/modules/ROOT/pages/trackchanges.adoc @@ -0,0 +1,67 @@ += Track Changes Plugin +:navtitle: Track Changes +:description: A view that allows users to review document changes made by multiple authors +:description_short: A view of tracked changes made by multiple authors +:keywords: plugin, Track Changes, changes, diff +:pluginname: Track Changes +:plugincode: trackchanges +:plugincategory: premium + +include::partial$misc/admon-revisionhistory-paid-addon-pricing.adoc[] + +include::partial$misc/admon-requires-8.0v.adoc[] + +The Track Changes plugin allows users to easily review and manage changes made to a document by multiple authors. + +== Interactive example + +== How it works + +== Basic setup + +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; + +For example: + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'trackchanges', + toolbar: 'trackchanges', + // track changes options +}); +---- + +== Data structure + +== Options + +The following configuration options affect the behavior of the {pluginname} plugin. + +include::partial$configuration/trackchanges-options.adoc[] + +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[] + +== Events + +The {pluginname} plugin provides the following events. + +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/partials/commands/trackchanges-cmds.adoc b/modules/ROOT/partials/commands/trackchanges-cmds.adoc new file mode 100644 index 0000000000..9d61f6860b --- /dev/null +++ b/modules/ROOT/partials/commands/trackchanges-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/modules/ROOT/partials/configuration/defaultmenuitems.adoc b/modules/ROOT/partials/configuration/defaultmenuitems.adoc index dd2c811ce9..e891f9803b 100644 --- a/modules/ROOT/partials/configuration/defaultmenuitems.adoc +++ b/modules/ROOT/partials/configuration/defaultmenuitems.adoc @@ -5,7 +5,7 @@ tinymce.init({ menu: { 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' }, + view: { title: 'View', items: 'code revisionhistory trackchanges | visualaid visualchars visualblocks | spellchecker | preview fullscreen | showcomments' }, 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' }, diff --git a/modules/ROOT/partials/configuration/trackchanges-options.adoc b/modules/ROOT/partials/configuration/trackchanges-options.adoc new file mode 100644 index 0000000000..391b450c3b --- /dev/null +++ b/modules/ROOT/partials/configuration/trackchanges-options.adoc @@ -0,0 +1,57 @@ +[[]] +== `` + +//// +What does the option do? +Why use it? +When use it? +What values can it use? +What do these values do? +Are there risks? + - Explain without using ‘risk’ or similar words. + - Use NOTE or IMPORTANT admonitions if helpful. + - For longer or more complicated scenarios, use the limitations section below. +//// + +*Type:* `+String+`, `+Boolean+`, `+Number+`, `+Function+`, `+Object+`, `+Array+`, or `+Regexp+` + +// Remove the *Possible values* line if there is no discrete set of possible values. +*Possible values:* `'string1'`, `'string2'`, `false` + +*Default value:* `false`, `1`, `'string1'` + +=== Example: using `` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : '' +}); +---- + +// Add a working and tested configuration (edit as required) +// or remove if not applicable. +=== Example: disabling the + +To disable , set `` to `false`. + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : 'false' +}); +---- + +// Remove if not applicable. +=== Limitation of the `` option + +The `` option has the following limitations. + +//// +Known limitations. +Complicated scenarios. +Anything that warrants a CAUTION or WARNING admonition. +//// \ No newline at end of file diff --git a/modules/ROOT/partials/events/trackchanges-events.adoc b/modules/ROOT/partials/events/trackchanges-events.adoc new file mode 100644 index 0000000000..79e6124bd0 --- /dev/null +++ b/modules/ROOT/partials/events/trackchanges-events.adoc @@ -0,0 +1,17 @@ +The following events are provided by the xref:{plugincode}.adoc[{pluginname} plugin]. + +[cols="1,1,2",options="header"] +|=== +|Name |Data |Description +|EventOne |`+{ : }+` |Fired when event one description. +|EventTwo |`+{ : , : }+` |Fired when event two description. +|EventThree |N/A |Fired when event three description. +// 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[] +|EventFour |`+{ : }+` |Fired when the event seven description. +|EventEn |`+{ : , : }+` |Fired when event en description. +|=== \ No newline at end of file diff --git a/modules/ROOT/partials/index-pages/premium-plugins.adoc b/modules/ROOT/partials/index-pages/premium-plugins.adoc index 3d76fe8cc5..f2770bfe03 100644 --- a/modules/ROOT/partials/index-pages/premium-plugins.adoc +++ b/modules/ROOT/partials/index-pages/premium-plugins.adoc @@ -201,7 +201,12 @@ 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| +[.lead] +xref:trackchanges.adoc[Track Changes] + +Review document changes by multiple users. |=== diff --git a/modules/ROOT/partials/menu-item-ids/trackchanges-menu-items.adoc b/modules/ROOT/partials/menu-item-ids/trackchanges-menu-items.adoc new file mode 100644 index 0000000000..edde0cbb96 --- /dev/null +++ b/modules/ROOT/partials/menu-item-ids/trackchanges-menu-items.adoc @@ -0,0 +1,6 @@ +[cols="1,1,2",options="header"] +|=== +|Menu item identifier |xref:menus-configuration-options.adoc#example-the-tinymce-default-menu-items[Default Menu Location] |Description + +|`trackchanges` |View |Opens the Track Changes view. +|=== \ No newline at end of file diff --git a/modules/ROOT/partials/misc/admon-requires-8.0v.adoc b/modules/ROOT/partials/misc/admon-requires-8.0v.adoc new file mode 100644 index 0000000000..9160a25fc7 --- /dev/null +++ b/modules/ROOT/partials/misc/admon-requires-8.0v.adoc @@ -0,0 +1 @@ +NOTE: This feature is only available for {productname} 8.0 and later. diff --git a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc b/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc new file mode 100644 index 0000000000..da3b8a1a17 --- /dev/null +++ b/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc @@ -0,0 +1,23 @@ +[cols="1,1,4",options="header"] +|=== +|Name |Arguments |Description + +| | | +// 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 +[source,js] +---- +// what this example does +tinymce.activeEditor.plugins..(); + +// what this example does +tinymce.activeEditor.plugins..(); +---- diff --git a/modules/ROOT/partials/toolbar-button-ids/trackchanges-toolbar-buttons.adoc b/modules/ROOT/partials/toolbar-button-ids/trackchanges-toolbar-buttons.adoc new file mode 100644 index 0000000000..4def3fff9f --- /dev/null +++ b/modules/ROOT/partials/toolbar-button-ids/trackchanges-toolbar-buttons.adoc @@ -0,0 +1,6 @@ +[cols="1,3",options="header"] +|=== +|Toolbar button identifier |Description + +|`+trackchanges+` |Open the Track Changes view. +|=== \ No newline at end of file From 56f01d927c8cf5631e03b1e2544d1eb0a64389f2 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Wed, 19 Mar 2025 10:37:59 +1000 Subject: [PATCH 02/68] add live demo template --- .../live-demos/trackchanges/example.js | 30 +++++++++++++++++++ .../live-demos/trackchanges/index.html | 15 ++++++++++ .../examples/live-demos/trackchanges/index.js | 16 ++++++++++ modules/ROOT/pages/trackchanges.adoc | 4 +++ 4 files changed, 65 insertions(+) create mode 100644 modules/ROOT/examples/live-demos/trackchanges/example.js create mode 100644 modules/ROOT/examples/live-demos/trackchanges/index.html create mode 100644 modules/ROOT/examples/live-demos/trackchanges/index.js diff --git a/modules/ROOT/examples/live-demos/trackchanges/example.js b/modules/ROOT/examples/live-demos/trackchanges/example.js new file mode 100644 index 0000000000..6b8e2b18e0 --- /dev/null +++ b/modules/ROOT/examples/live-demos/trackchanges/example.js @@ -0,0 +1,30 @@ +/* + +This file is not normally required. + +Sometimes, however, a plugin, or a particular feature of a plugin, +requires a back-end service. + +In these cases, creating a working demo requires setting up an +emulated version of this service. + +And `example.js` is part of this emulation. + +`index.js` still runs the live demo. + +But `example.js` is what is displayed in the *js* tab of the +live-demo interface on the built docs site. + +So `example.js` has to be a working equivalent to `index.js` *if* +`index.js` was wired up in a standard way, to its required back-end +service. + +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 ‘includes-an-emulated-back-end’ examples +will almost certainly include significant initial input from the +plugin’s developer. + +*/ diff --git a/modules/ROOT/examples/live-demos/trackchanges/index.html b/modules/ROOT/examples/live-demos/trackchanges/index.html new file mode 100644 index 0000000000..ebe4fa70ca --- /dev/null +++ b/modules/ROOT/examples/live-demos/trackchanges/index.html @@ -0,0 +1,15 @@ + diff --git a/modules/ROOT/examples/live-demos/trackchanges/index.js b/modules/ROOT/examples/live-demos/trackchanges/index.js new file mode 100644 index 0000000000..045103dc9d --- /dev/null +++ b/modules/ROOT/examples/live-demos/trackchanges/index.js @@ -0,0 +1,16 @@ +tinymce.init({ + selector: 'textarea#', +// below is a basic 6.x working configuration. +// Do not assume it is suitable for demonstrating the plugin to be documented. + height: 500, + plugins: [ + 'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'preview', + 'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen', + 'insertdatetime', 'media', 'table', 'help', 'wordcount' + ], + toolbar: 'undo redo | blocks | ' + + 'bold italic backcolor | alignleft aligncenter ' + + 'alignright alignjustify | bullist numlist outdent indent | ' + + 'removeformat | help', + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }' +}); diff --git a/modules/ROOT/pages/trackchanges.adoc b/modules/ROOT/pages/trackchanges.adoc index 9a686415a2..a0892c5956 100644 --- a/modules/ROOT/pages/trackchanges.adoc +++ b/modules/ROOT/pages/trackchanges.adoc @@ -15,6 +15,10 @@ The Track Changes plugin allows users to easily review and manage changes made t == Interactive example +liveDemo::{plugincode}[] + +include::partial$misc/admon-iframe-only.adoc[] + == How it works == Basic setup From facd9702e29d1e7dad453156366c16211a7f76c8 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Fri, 21 Mar 2025 16:46:49 +1000 Subject: [PATCH 03/68] Update API sections --- modules/ROOT/pages/trackchanges.adoc | 37 ++- .../partials/commands/trackchanges-cmds.adoc | 25 +- .../configuration/trackchanges-options.adoc | 282 +++++++++++++++++- .../partials/events/trackchanges-events.adoc | 10 +- .../plugin-apis/trackchanges-apis.adoc | 22 +- 5 files changed, 326 insertions(+), 50 deletions(-) diff --git a/modules/ROOT/pages/trackchanges.adoc b/modules/ROOT/pages/trackchanges.adoc index a0892c5956..758c637e97 100644 --- a/modules/ROOT/pages/trackchanges.adoc +++ b/modules/ROOT/pages/trackchanges.adoc @@ -42,11 +42,44 @@ tinymce.init({ == Data structure +=== TrackedDocument + +`TrackedDocument` is an `+Object+` that contains the following fields: + +[cols="1,1,1,3",options="header"] +|=== +| Field | Type | Required? | Description +| `+version+` | `+Number+` | required | +| `+maxId+` | `+Number+` | required | +| `+contents+` | xref:#trackednode[TrackedNode] `+Object+` `+Array+` | required | +|=== + +=== TrackedNode + +`TrackedNode` is an `+Object+` that contains the following fields: + +[cols="1,1,1,3",options="header"] +|=== +| Field | Type | Required? | Description +| `+type+` | `+String+` | required | +| `+attrs+` | `` | optional | +| `+oldAttrs+` | `` | optional | +| `+text+` | `+String+` | required | +| `+_opData+` | xref:#trackedData[TrackedData] `+Object+` `+Array+` | optional | +| `+format+` | xref:#textformat[TextFormat] `+Object+` | optional | +| `+oldFormat+` | xref:#textformat[TextFormat] `+Object+` | optional | +| `+children+` | xref:#trackednode[TrackedNode] `+Object+` `+Array+` | optional | +|=== + +=== TrackedData + +=== TextFormat + == Options The following configuration options affect the behavior of the {pluginname} plugin. -include::partial$configuration/trackchanges-options.adoc[] +include::partial$configuration/trackchanges-options.adoc[leveloffset=+1] include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] @@ -66,6 +99,6 @@ include::partial$events/{plugincode}-events.adoc[] == APIs -The {pluginname} plugin provide the following APIs. +The {pluginname} plugin provides the following APIs. include::partial$plugin-apis/{plugincode}-apis.adoc[] \ No newline at end of file diff --git a/modules/ROOT/partials/commands/trackchanges-cmds.adoc b/modules/ROOT/partials/commands/trackchanges-cmds.adoc index 9d61f6860b..9dcee19963 100644 --- a/modules/ROOT/partials/commands/trackchanges-cmds.adoc +++ b/modules/ROOT/partials/commands/trackchanges-cmds.adoc @@ -2,32 +2,11 @@ |=== |Command |Description -| | -// Boilerplate for commands that require further documentation -| |Description two. For details, see xref:using-[Using `++`]. +|trackchanges |Toggle the Track Changes view |=== .Examples [source,js] ---- -tinymce.activeEditor.execCommand(''); -tinymce.activeEditor.execCommand('', , { : '', : '' }); +tinymce.activeEditor.execCommand('trackchanges'); ---- - -// 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/modules/ROOT/partials/configuration/trackchanges-options.adoc b/modules/ROOT/partials/configuration/trackchanges-options.adoc index 391b450c3b..496ec1f158 100644 --- a/modules/ROOT/partials/configuration/trackchanges-options.adoc +++ b/modules/ROOT/partials/configuration/trackchanges-options.adoc @@ -1,5 +1,5 @@ -[[]] -== `` +[[trackchanges_model]] +== `trackchanges_model` //// What does the option do? @@ -13,12 +13,282 @@ Are there risks? - For longer or more complicated scenarios, use the limitations section below. //// -*Type:* `+String+`, `+Boolean+`, `+Number+`, `+Function+`, `+Object+`, `+Array+`, or `+Regexp+` +*Type:* xref:#trackeddocument[TrackedDocument] `+Object+` -// Remove the *Possible values* line if there is no discrete set of possible values. -*Possible values:* `'string1'`, `'string2'`, `false` +=== Example: using `trackchanges_model` -*Default value:* `false`, `1`, `'string1'` +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : '' +}); +---- + +// Add a working and tested configuration (edit as required) +// or remove if not applicable. +=== Example: disabling the + +To disable , set `` to `false`. + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : 'false' +}); +---- + +// Remove if not applicable. +=== Limitation of the `` option + +The `` option has the following limitations. + +//// +Known limitations. +Complicated scenarios. +Anything that warrants a CAUTION or WARNING admonition. +//// + +[[trackchanges_uid]] +== `trackchanges_uid` + +*Type:* `+String+` + + +//// +What does the option do? +Why use it? +When use it? +What values can it use? +What do these values do? +Are there risks? + - Explain without using ‘risk’ or similar words. + - Use NOTE or IMPORTANT admonitions if helpful. + - For longer or more complicated scenarios, use the limitations section below. +//// + +=== Example: using `` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : '' +}); +---- + +// Add a working and tested configuration (edit as required) +// or remove if not applicable. +=== Example: disabling the + +To disable , set `` to `false`. + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : 'false' +}); +---- + +// Remove if not applicable. +=== Limitation of the `` option + +The `` option has the following limitations. + +//// +Known limitations. +Complicated scenarios. +Anything that warrants a CAUTION or WARNING admonition. +//// + +[[trackchanges_role]] +== `trackchanges_role` + +*Type:* `+String+` + +*Possible values:* `'admin'`, `'reviewer'`, `'contributor'`, `'viewer'`, `'none'`, + +*Default value:* `'admin'` + + +//// +What does the option do? +Why use it? +When use it? +What values can it use? +What do these values do? +Are there risks? + - Explain without using ‘risk’ or similar words. + - Use NOTE or IMPORTANT admonitions if helpful. + - For longer or more complicated scenarios, use the limitations section below. +//// + +=== Example: using `` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : '' +}); +---- + +// Add a working and tested configuration (edit as required) +// or remove if not applicable. +=== Example: disabling the + +To disable , set `` to `false`. + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : 'false' +}); +---- + +// Remove if not applicable. +=== Limitation of the `` option + +The `` option has the following limitations. + +//// +Known limitations. +Complicated scenarios. +Anything that warrants a CAUTION or WARNING admonition. +//// + +[[trackchanges_user_lookup]] +== `trackchanges_user_lookup` + +*Type:* `+Function+` + + +//// +What does the option do? +Why use it? +When use it? +What values can it use? +What do these values do? +Are there risks? + - Explain without using ‘risk’ or similar words. + - Use NOTE or IMPORTANT admonitions if helpful. + - For longer or more complicated scenarios, use the limitations section below. +//// + +=== Example: using `` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : '' +}); +---- + +// Add a working and tested configuration (edit as required) +// or remove if not applicable. +=== Example: disabling the + +To disable , set `` to `false`. + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : 'false' +}); +---- + +// Remove if not applicable. +=== Limitation of the `` option + +The `` option has the following limitations. + +//// +Known limitations. +Complicated scenarios. +Anything that warrants a CAUTION or WARNING admonition. +//// + +[[trackchanges_css_url]] +== `trackchanges_css_url` + +*Type:* `+String+` + +*Default value:* `'${pluginUrl}/css/trackchanges.css'` + + +//// +What does the option do? +Why use it? +When use it? +What values can it use? +What do these values do? +Are there risks? + - Explain without using ‘risk’ or similar words. + - Use NOTE or IMPORTANT admonitions if helpful. + - For longer or more complicated scenarios, use the limitations section below. +//// + +=== Example: using `` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : '' +}); +---- + +// Add a working and tested configuration (edit as required) +// or remove if not applicable. +=== Example: disabling the + +To disable , set `` to `false`. + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : 'false' +}); +---- + +// Remove if not applicable. +=== Limitation of the `` option + +The `` option has the following limitations. + +//// +Known limitations. +Complicated scenarios. +Anything that warrants a CAUTION or WARNING admonition. +//// + +[[trackchanges_diff_classes]] +== `trackchanges_diff_classes` + +*Type:* `+Object+` + +//// +What does the option do? +Why use it? +When use it? +What values can it use? +What do these values do? +Are there risks? + - Explain without using ‘risk’ or similar words. + - Use NOTE or IMPORTANT admonitions if helpful. + - For longer or more complicated scenarios, use the limitations section below. +//// === Example: using `` diff --git a/modules/ROOT/partials/events/trackchanges-events.adoc b/modules/ROOT/partials/events/trackchanges-events.adoc index 79e6124bd0..a3fedfbff0 100644 --- a/modules/ROOT/partials/events/trackchanges-events.adoc +++ b/modules/ROOT/partials/events/trackchanges-events.adoc @@ -3,15 +3,11 @@ The following events are provided by the xref:{plugincode}.adoc[{pluginname} plu [cols="1,1,2",options="header"] |=== |Name |Data |Description -|EventOne |`+{ : }+` |Fired when event one description. -|EventTwo |`+{ : , : }+` |Fired when event two description. -|EventThree |N/A |Fired when event three description. +|TrackChangesBeginReview |N/A |Fired when the Track Changes view opens. +|TrackChangesReviewComplete |N/A |Fired when a review in the Track Changes view is completed. +|TrackChangesReviewCancelled |N/A |Fired when a review in the Track Changes view is cancelled. // 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[] -|EventFour |`+{ : }+` |Fired when the event seven description. -|EventEn |`+{ : , : }+` |Fired when event en description. |=== \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc b/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc index da3b8a1a17..b2952a18a9 100644 --- a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc +++ b/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc @@ -2,22 +2,20 @@ |=== |Name |Arguments |Description -| | | -// 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[] -| | | +|getModel |N/A |Return a xref:#trackeddocument[TrackedDocument] `+Object+` of the document. +|resetModel |N/A |Reset the document to its original state. +|hasChanges |N/A |Return a boolean value indicating whether the document contains changes to be reviewed. |=== .Examples [source,js] ---- -// what this example does -tinymce.activeEditor.plugins..(); +// Get the current model of the document +tinymce.activeEditor.plugins.trackchanges.getModel(); -// what this example does -tinymce.activeEditor.plugins..(); +// Reset the document model to its original state +tinymce.activeEditor.plugins.trackchanges.resetModel(); + +// Check if document contains changes to be reviewed +tinymce.activeEditor.plugins.trackchanges.hasChanges(); ---- From 0e1756f64e20fc5788983ed14e2761b30300ca6d Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Mon, 24 Mar 2025 17:41:21 +1000 Subject: [PATCH 04/68] Add description of plugin and examples for API options --- modules/ROOT/pages/trackchanges.adoc | 80 +++-- .../configuration/trackchanges-options.adoc | 311 +++--------------- .../plugin-apis/trackchanges-apis.adoc | 20 +- 3 files changed, 109 insertions(+), 302 deletions(-) diff --git a/modules/ROOT/pages/trackchanges.adoc b/modules/ROOT/pages/trackchanges.adoc index 758c637e97..e50758aa0e 100644 --- a/modules/ROOT/pages/trackchanges.adoc +++ b/modules/ROOT/pages/trackchanges.adoc @@ -21,12 +21,43 @@ include::partial$misc/admon-iframe-only.adoc[] == How it works +The Track Changes plugin monitors edits made to a document by comparing its current state to the original version. Each change is attributed to its respective author and can be approved or rejected before being applied to the document. + +[NOTE] +Since the comparison is made against the original version of the document, if there are unresolved changes by multiple authors affecting the same part, the most recent change will be used for comparison. The `hasChanges` API can be used to implement a safeguard that prevents further edits on a document with unresolved changes. + +The plugin includes a dedicated view for reviewing current changes, accessible via the `{plugincode} toolbar button or the menu option under the `View` menu. The key components are: + +. **Read-only Diff View**: ++ +Highlights the current changes made to the document, using the following color codes: ++ +* Green: New content. +* Blue: Modified content. Modifications to HTML content implies attributes or formatting (e.g. bold, italic, etc.). +* Red: Removed content. + +. **Sidebar**: ++ +Contains a header with the following buttons: ++ +* Show Changes: A toggle button which hides/unhides the change annotations. +* Complete: Ends the review applies the resolved changes. +* Cancel: Ends the review without any further action. + ++ +The sidebar also displays all tracked changes that need to be resolved. Each change can be handled in the following ways: +* Accept: Applies the change to the document. +* Reject: Removes the change from the document. +* Revert: Undoes a previously accepted or rejected change. + == Basic setup 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; +* add `{plugincode}_model` to the editor configuration. +* add `{plugincode}_uid` to the editor configuration. For example: @@ -36,45 +67,22 @@ tinymce.init({ selector: 'textarea', // change this value according to your HTML plugins: 'trackchanges', toolbar: 'trackchanges', - // track changes options + trackchanges_model: { + version: 1, + maxId: 0, + contents: [ + { + type: 'p', + children: [ + { text: 'Hello, World!' } + ] + } + ] + } + trackchanges_uid: 'unique-identifier' // replace this with a unique string to identify the user }); ---- -== Data structure - -=== TrackedDocument - -`TrackedDocument` is an `+Object+` that contains the following fields: - -[cols="1,1,1,3",options="header"] -|=== -| Field | Type | Required? | Description -| `+version+` | `+Number+` | required | -| `+maxId+` | `+Number+` | required | -| `+contents+` | xref:#trackednode[TrackedNode] `+Object+` `+Array+` | required | -|=== - -=== TrackedNode - -`TrackedNode` is an `+Object+` that contains the following fields: - -[cols="1,1,1,3",options="header"] -|=== -| Field | Type | Required? | Description -| `+type+` | `+String+` | required | -| `+attrs+` | `` | optional | -| `+oldAttrs+` | `` | optional | -| `+text+` | `+String+` | required | -| `+_opData+` | xref:#trackedData[TrackedData] `+Object+` `+Array+` | optional | -| `+format+` | xref:#textformat[TextFormat] `+Object+` | optional | -| `+oldFormat+` | xref:#textformat[TextFormat] `+Object+` | optional | -| `+children+` | xref:#trackednode[TrackedNode] `+Object+` `+Array+` | optional | -|=== - -=== TrackedData - -=== TextFormat - == Options The following configuration options affect the behavior of the {pluginname} plugin. diff --git a/modules/ROOT/partials/configuration/trackchanges-options.adoc b/modules/ROOT/partials/configuration/trackchanges-options.adoc index 496ec1f158..1af4b9d22b 100644 --- a/modules/ROOT/partials/configuration/trackchanges-options.adoc +++ b/modules/ROOT/partials/configuration/trackchanges-options.adoc @@ -1,19 +1,9 @@ [[trackchanges_model]] == `trackchanges_model` -//// -What does the option do? -Why use it? -When use it? -What values can it use? -What do these values do? -Are there risks? - - Explain without using ‘risk’ or similar words. - - Use NOTE or IMPORTANT admonitions if helpful. - - For longer or more complicated scenarios, use the limitations section below. -//// +The `trackchanges_model` option sets the initial model of the document to be begin tracking changes. It takes as input an object representing the document. If no value is set, the plugin will generate the model by default. -*Type:* xref:#trackeddocument[TrackedDocument] `+Object+` +//*Type:* xref:#trackeddocument[TrackedDocument] `+Object+` === Example: using `trackchanges_model` @@ -22,306 +12,99 @@ Are there risks? ---- tinymce.init({ selector: 'textarea', // Change this value according to your HTML - : '' + plugins: 'trackchanges', + toolbar: 'trackchanges', + trackchanges_model: { + version: 1, + maxId: 0, + contents: [ + { + type: 'p', + children: [ + { text: 'Hello, World!' } + ] + } + ] + } }); ---- -// Add a working and tested configuration (edit as required) -// or remove if not applicable. -=== Example: disabling the - -To disable , set `` to `false`. - -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : 'false' -}); ----- - -// Remove if not applicable. -=== Limitation of the `` option - -The `` option has the following limitations. - -//// -Known limitations. -Complicated scenarios. -Anything that warrants a CAUTION or WARNING admonition. -//// - [[trackchanges_uid]] == `trackchanges_uid` -*Type:* `+String+` - - -//// -What does the option do? -Why use it? -When use it? -What values can it use? -What do these values do? -Are there risks? - - Explain without using ‘risk’ or similar words. - - Use NOTE or IMPORTANT admonitions if helpful. - - For longer or more complicated scenarios, use the limitations section below. -//// - -=== Example: using `` - -// Add a working and tested configuration. -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : '' -}); ----- - -// Add a working and tested configuration (edit as required) -// or remove if not applicable. -=== Example: disabling the - -To disable , set `` to `false`. - -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : 'false' -}); ----- - -// Remove if not applicable. -=== Limitation of the `` option - -The `` option has the following limitations. - -//// -Known limitations. -Complicated scenarios. -Anything that warrants a CAUTION or WARNING admonition. -//// - -[[trackchanges_role]] -== `trackchanges_role` +The `trackchanges_uid` is a _required_ option that takes as input a unique string to identify the current user. This is used to attribute changes made by the user. *Type:* `+String+` -*Possible values:* `'admin'`, `'reviewer'`, `'contributor'`, `'viewer'`, `'none'`, - -*Default value:* `'admin'` - - -//// -What does the option do? -Why use it? -When use it? -What values can it use? -What do these values do? -Are there risks? - - Explain without using ‘risk’ or similar words. - - Use NOTE or IMPORTANT admonitions if helpful. - - For longer or more complicated scenarios, use the limitations section below. -//// - -=== Example: using `` - -// Add a working and tested configuration. -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : '' -}); ----- - -// Add a working and tested configuration (edit as required) -// or remove if not applicable. -=== Example: disabling the - -To disable , set `` to `false`. - -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : 'false' -}); ----- - -// Remove if not applicable. -=== Limitation of the `` option - -The `` option has the following limitations. - -//// -Known limitations. -Complicated scenarios. -Anything that warrants a CAUTION or WARNING admonition. -//// - -[[trackchanges_user_lookup]] -== `trackchanges_user_lookup` - -*Type:* `+Function+` - - -//// -What does the option do? -Why use it? -When use it? -What values can it use? -What do these values do? -Are there risks? - - Explain without using ‘risk’ or similar words. - - Use NOTE or IMPORTANT admonitions if helpful. - - For longer or more complicated scenarios, use the limitations section below. -//// - -=== Example: using `` +=== Example: using `trackchanges_uid` // Add a working and tested configuration. [source,js] ---- tinymce.init({ selector: 'textarea', // Change this value according to your HTML - : '' + plugins: 'trackchanges', + toolbar: 'trackchanges', + trackchanges_uid: 'unique-identifier' // replace this with a unique string to identify the user }); ---- -// Add a working and tested configuration (edit as required) -// or remove if not applicable. -=== Example: disabling the - -To disable , set `` to `false`. - -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : 'false' -}); ----- - -// Remove if not applicable. -=== Limitation of the `` option - -The `` option has the following limitations. - -//// -Known limitations. -Complicated scenarios. -Anything that warrants a CAUTION or WARNING admonition. -//// - [[trackchanges_css_url]] == `trackchanges_css_url` +The `trackchanges_css_url` option sets the location where a CSS file containing change annotations in the {pluginname} view should be loaded from. To override the default CSS classes, use this option alongside `trackchanges_diff_classes`. + *Type:* `+String+` *Default value:* `'${pluginUrl}/css/trackchanges.css'` - -//// -What does the option do? -Why use it? -When use it? -What values can it use? -What do these values do? -Are there risks? - - Explain without using ‘risk’ or similar words. - - Use NOTE or IMPORTANT admonitions if helpful. - - For longer or more complicated scenarios, use the limitations section below. -//// - -=== Example: using `` +=== Example: using `trackchanges_css_url` // Add a working and tested configuration. [source,js] ---- tinymce.init({ selector: 'textarea', // Change this value according to your HTML - : '' + trackchanges_css_url: './trackchanges.css' }); ---- -// Add a working and tested configuration (edit as required) -// or remove if not applicable. -=== Example: disabling the - -To disable , set `` to `false`. - -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : 'false' -}); ----- - -// Remove if not applicable. -=== Limitation of the `` option - -The `` option has the following limitations. - -//// -Known limitations. -Complicated scenarios. -Anything that warrants a CAUTION or WARNING admonition. -//// - [[trackchanges_diff_classes]] == `trackchanges_diff_classes` +The `trackchanges_diff_classes` option configures the CSS classes applied to the change annotations in the {pluginname} view. This is useful to set custom styles and must be used in combination with the `trackchanges_css_url` option. + +[NOTE] +The CSS class names must exist in the xref:trackchanges_css_url[`+trackchanges_css_url+`]. + *Type:* `+Object+` -//// -What does the option do? -Why use it? -When use it? -What values can it use? -What do these values do? -Are there risks? - - Explain without using ‘risk’ or similar words. - - Use NOTE or IMPORTANT admonitions if helpful. - - For longer or more complicated scenarios, use the limitations section below. -//// +*Default value:* `addition`, `removal`, `modification` -=== Example: using `` +Below are the default CSS classes: -// Add a working and tested configuration. [source,js] ---- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : '' -}); +{ + addition: 'tox-trackchanges__annotation--added', + removal: 'tox-trackchanges__annotation--removed', + modification: 'tox-trackchanges__annotation--modified' +} ---- -// Add a working and tested configuration (edit as required) -// or remove if not applicable. -=== Example: disabling the - -To disable , set `` to `false`. +=== Example: using `trackchanges_diff_classes` [source,js] ---- tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : 'false' + selector: 'textarea', // change this value according to your HTML + plugins: 'trackchanges', + toolbar: 'trackchanges', + trackchanges_css_url: './trackchanges.css', + trackchanges_diff_classes: { + addition: 'added', + removal: 'removed', + modification: 'modified' + } }); ---- - -// Remove if not applicable. -=== Limitation of the `` option - -The `` option has the following limitations. - -//// -Known limitations. -Complicated scenarios. -Anything that warrants a CAUTION or WARNING admonition. -//// \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc b/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc index b2952a18a9..2ac0f57efe 100644 --- a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc +++ b/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc @@ -2,8 +2,9 @@ |=== |Name |Arguments |Description -|getModel |N/A |Return a xref:#trackeddocument[TrackedDocument] `+Object+` of the document. -|resetModel |N/A |Reset the document to its original state. +|getModel |N/A |Return an object representing the document model used to store tracked changes data. +//|setModel |xref:#trackeddocument[TrackedDocument] `+Object+` | Set the current model of the document. +//|resetModel |N/A |Reset the document to its original state. |hasChanges |N/A |Return a boolean value indicating whether the document contains changes to be reviewed. |=== @@ -13,9 +14,24 @@ // Get the current model of the document tinymce.activeEditor.plugins.trackchanges.getModel(); +// Check if document contains changes to be reviewed +tinymce.activeEditor.plugins.trackchanges.hasChanges(); +---- + +//// +.Examples +[source,js] +---- +// Get the current model of the document +tinymce.activeEditor.plugins.trackchanges.getModel(); + +// Set current model of the document +tinymce.activeEditor.plugins.trackchanges.setModel(model); + // Reset the document model to its original state tinymce.activeEditor.plugins.trackchanges.resetModel(); // Check if document contains changes to be reviewed tinymce.activeEditor.plugins.trackchanges.hasChanges(); ---- +//// \ No newline at end of file From b1acbb3a0d2bc2ad78e2b21f2c9283627b7d9435 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Tue, 25 Mar 2025 10:58:38 +1000 Subject: [PATCH 05/68] Comment out note about stacked changes and minor copy edits --- modules/ROOT/pages/trackchanges.adoc | 17 +++++++++++------ .../partials/plugin-apis/trackchanges-apis.adoc | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/modules/ROOT/pages/trackchanges.adoc b/modules/ROOT/pages/trackchanges.adoc index e50758aa0e..9019d6423a 100644 --- a/modules/ROOT/pages/trackchanges.adoc +++ b/modules/ROOT/pages/trackchanges.adoc @@ -23,10 +23,7 @@ include::partial$misc/admon-iframe-only.adoc[] The Track Changes plugin monitors edits made to a document by comparing its current state to the original version. Each change is attributed to its respective author and can be approved or rejected before being applied to the document. -[NOTE] -Since the comparison is made against the original version of the document, if there are unresolved changes by multiple authors affecting the same part, the most recent change will be used for comparison. The `hasChanges` API can be used to implement a safeguard that prevents further edits on a document with unresolved changes. - -The plugin includes a dedicated view for reviewing current changes, accessible via the `{plugincode} toolbar button or the menu option under the `View` menu. The key components are: +The plugin includes a dedicated view for reviewing current changes, accessible via the `{plugincode}` toolbar button or the menu option under the `View` menu. The key components are: . **Read-only Diff View**: + @@ -41,7 +38,7 @@ Highlights the current changes made to the document, using the following color c Contains a header with the following buttons: + * Show Changes: A toggle button which hides/unhides the change annotations. -* Complete: Ends the review applies the resolved changes. +* Complete: Ends the review and applies the resolved changes. * Cancel: Ends the review without any further action. + @@ -109,4 +106,12 @@ include::partial$events/{plugincode}-events.adoc[] The {pluginname} plugin provides the following APIs. -include::partial$plugin-apis/{plugincode}-apis.adoc[] \ No newline at end of file +include::partial$plugin-apis/{plugincode}-apis.adoc[] + +//// +== Known Limitations + +[NOTE] +Since the comparison is made against the original version of the document, if there are unresolved changes by multiple authors affecting the same part, the most recent change will be used for comparison. The `hasChanges` API can be used to implement a safeguard that prevents further edits on a document with unresolved changes. + +//// \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc b/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc index 2ac0f57efe..339ad43f50 100644 --- a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc +++ b/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc @@ -2,7 +2,7 @@ |=== |Name |Arguments |Description -|getModel |N/A |Return an object representing the document model used to store tracked changes data. +|getModel |N/A |Return an object representing the document model used to store data of the tracked changes. //|setModel |xref:#trackeddocument[TrackedDocument] `+Object+` | Set the current model of the document. //|resetModel |N/A |Reset the document to its original state. |hasChanges |N/A |Return a boolean value indicating whether the document contains changes to be reviewed. From 9ba47ed49d73054c3d16f17b5a1a81defeaf5f84 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Mon, 31 Mar 2025 16:04:20 +1000 Subject: [PATCH 06/68] add live demo --- antora.yml | 2 +- .../live-demos/trackchanges/example.js | 37 ++++----------- .../live-demos/trackchanges/index.html | 33 ++++++++++++- .../examples/live-demos/trackchanges/index.js | 47 ++++++++++++++----- modules/ROOT/pages/trackchanges.adoc | 2 +- 5 files changed, 75 insertions(+), 46 deletions(-) diff --git a/antora.yml b/antora.yml index fbfa6a6e49..adc6b05a06 100644 --- a/antora.yml +++ b/antora.yml @@ -10,7 +10,7 @@ asciidoc: 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 + tinymce_live_demo_url: https://internal-preview.tiny.work/epic/EPIC-134/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 diff --git a/modules/ROOT/examples/live-demos/trackchanges/example.js b/modules/ROOT/examples/live-demos/trackchanges/example.js index 6b8e2b18e0..814574e2a6 100644 --- a/modules/ROOT/examples/live-demos/trackchanges/example.js +++ b/modules/ROOT/examples/live-demos/trackchanges/example.js @@ -1,30 +1,9 @@ -/* -This file is not normally required. - -Sometimes, however, a plugin, or a particular feature of a plugin, -requires a back-end service. - -In these cases, creating a working demo requires setting up an -emulated version of this service. - -And `example.js` is part of this emulation. - -`index.js` still runs the live demo. - -But `example.js` is what is displayed in the *js* tab of the -live-demo interface on the built docs site. - -So `example.js` has to be a working equivalent to `index.js` *if* -`index.js` was wired up in a standard way, to its required back-end -service. - -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 ‘includes-an-emulated-back-end’ examples -will almost certainly include significant initial input from the -plugin’s developer. - -*/ +tinymce.init({ + selector: 'textarea#trackchanges', + height: 500, + plugins: 'trackchanges', + toolbar: 'trackchanges', + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', + trackchanges_uid: 'adamhenderson', + }); \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/trackchanges/index.html b/modules/ROOT/examples/live-demos/trackchanges/index.html index ebe4fa70ca..d2dabf9f53 100644 --- a/modules/ROOT/examples/live-demos/trackchanges/index.html +++ b/modules/ROOT/examples/live-demos/trackchanges/index.html @@ -1,8 +1,12 @@ - diff --git a/modules/ROOT/examples/live-demos/trackchanges/index.js b/modules/ROOT/examples/live-demos/trackchanges/index.js index 045103dc9d..4d888ade46 100644 --- a/modules/ROOT/examples/live-demos/trackchanges/index.js +++ b/modules/ROOT/examples/live-demos/trackchanges/index.js @@ -1,16 +1,37 @@ +/** Fake user database */ +const userinfos = { + adamhenderson: { + uid: 'adamhenderson', + name: 'Adam Henderson', + avatar: `https://randomuser.me/api/portraits/men/1.jpg`, + }, + michaelcook: { + uid: 'michaelcook', + name: 'Michael Cook', + avatar: `https://randomuser.me/api/portraits/men/2.jpg`, + }, + kalebwilson: { + uid: 'kalebwilson', + name: 'Kaleb Wilson', + avatar: `https://randomuser.me/api/portraits/men/3.jpg`, + }, + kyleeinstein: { + uid: 'kyleeinstein', + name: 'Kyle Einstein', + avatar: `https://randomuser.me/api/portraits/men/4.jpg`, + }, +}; + +const trackchanges_user_lookup = (uid) => new Promise((resolve, reject) => + setTimeout(() => userinfos[uid] ? resolve(userinfos[uid]) : reject(), 1000)); + + tinymce.init({ - selector: 'textarea#', -// below is a basic 6.x working configuration. -// Do not assume it is suitable for demonstrating the plugin to be documented. + selector: 'textarea#trackchanges', height: 500, - plugins: [ - 'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'preview', - 'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen', - 'insertdatetime', 'media', 'table', 'help', 'wordcount' - ], - toolbar: 'undo redo | blocks | ' + - 'bold italic backcolor | alignleft aligncenter ' + - 'alignright alignjustify | bullist numlist outdent indent | ' + - 'removeformat | help', - content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }' + plugins: 'trackchanges', + toolbar: 'trackchanges', + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', + trackchanges_uid: 'adamhenderson', + trackchanges_user_lookup, }); diff --git a/modules/ROOT/pages/trackchanges.adoc b/modules/ROOT/pages/trackchanges.adoc index 9019d6423a..d18ce7e0b0 100644 --- a/modules/ROOT/pages/trackchanges.adoc +++ b/modules/ROOT/pages/trackchanges.adoc @@ -75,7 +75,7 @@ tinymce.init({ ] } ] - } + }, trackchanges_uid: 'unique-identifier' // replace this with a unique string to identify the user }); ---- From f252ba0883f7bdae6c7cc8ba27262811fc52b7f9 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Mon, 31 Mar 2025 16:42:11 +1000 Subject: [PATCH 07/68] rename plugin to Suggested Edits --- modules/ROOT/nav.adoc | 2 +- .../pages/{trackchanges.adoc => suggestededits.adoc} | 12 ++++++------ .../ROOT/partials/index-pages/premium-plugins.adoc | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) rename modules/ROOT/pages/{trackchanges.adoc => suggestededits.adoc} (87%) diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc index 507e0c1b74..636d3088c3 100644 --- a/modules/ROOT/nav.adoc +++ b/modules/ROOT/nav.adoc @@ -377,7 +377,7 @@ ***** xref:tinydrive-pick.adoc[The Pick API] ***** xref:tinydrive-type-interfaces.adoc[TypeScript interfaces] **** xref:tinydrive-changelog.adoc[Changelog] -*** xref:trackchanges.adoc[Track Changes] +*** xref:suggestededits.adoc[Suggested Edits] ** Open source plugins *** xref:accordion.adoc[Accordion] *** xref:anchor.adoc[Anchor] diff --git a/modules/ROOT/pages/trackchanges.adoc b/modules/ROOT/pages/suggestededits.adoc similarity index 87% rename from modules/ROOT/pages/trackchanges.adoc rename to modules/ROOT/pages/suggestededits.adoc index d18ce7e0b0..34534d0b4d 100644 --- a/modules/ROOT/pages/trackchanges.adoc +++ b/modules/ROOT/pages/suggestededits.adoc @@ -1,9 +1,9 @@ -= Track Changes Plugin -:navtitle: Track Changes += Suggested Edits Plugin +:navtitle: Suggested Edits :description: A view that allows users to review document changes made by multiple authors :description_short: A view of tracked changes made by multiple authors -:keywords: plugin, Track Changes, changes, diff -:pluginname: Track Changes +:keywords: plugin, Suggested Edits, changes, diff +:pluginname: Suggested Edits :plugincode: trackchanges :plugincategory: premium @@ -11,7 +11,7 @@ include::partial$misc/admon-revisionhistory-paid-addon-pricing.adoc[] include::partial$misc/admon-requires-8.0v.adoc[] -The Track Changes plugin allows users to easily review and manage changes made to a document by multiple authors. +The Suggested Edits plugin allows users to easily review and manage changes made to a document by multiple authors. == Interactive example @@ -21,7 +21,7 @@ include::partial$misc/admon-iframe-only.adoc[] == How it works -The Track Changes plugin monitors edits made to a document by comparing its current state to the original version. Each change is attributed to its respective author and can be approved or rejected before being applied to the document. +The Suggested Edits plugin monitors edits made to a document by comparing its current state to the original version. Each change is attributed to its respective author and can be approved or rejected before being applied to the document. The plugin includes a dedicated view for reviewing current changes, accessible via the `{plugincode}` toolbar button or the menu option under the `View` menu. The key components are: diff --git a/modules/ROOT/partials/index-pages/premium-plugins.adoc b/modules/ROOT/partials/index-pages/premium-plugins.adoc index f2770bfe03..3e9cc5fff2 100644 --- a/modules/ROOT/partials/index-pages/premium-plugins.adoc +++ b/modules/ROOT/partials/index-pages/premium-plugins.adoc @@ -204,7 +204,7 @@ Cloud-based file and image management for {productname}. a| [.lead] -xref:trackchanges.adoc[Track Changes] +xref:suggestededits.adoc[Suggested Edits] Review document changes by multiple users. From 8fa5056e416740ba9c0449b9c1afbdde75ea3aee Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Tue, 1 Apr 2025 15:17:32 +1000 Subject: [PATCH 08/68] replace all instanes of plugin name and code --- .../example.js | 0 .../index.html | 24 ++-- .../{trackchanges => suggestededits}/index.js | 0 modules/ROOT/nav.adoc | 2 +- modules/ROOT/pages/7.0-release-notes.adoc | 2 +- modules/ROOT/pages/suggestededits.adoc | 12 +- ...ges-cmds.adoc => suggestededits-cmds.adoc} | 4 +- .../configuration/defaultmenuitems.adoc | 2 +- .../configuration/suggestededits-options.adoc | 110 ++++++++++++++++++ .../configuration/trackchanges-options.adoc | 110 ------------------ ...events.adoc => suggestededits-events.adoc} | 6 +- ...ms.adoc => suggestededits-menu-items.adoc} | 2 +- ...ges-apis.adoc => suggestededits-apis.adoc} | 12 +- ...oc => suggestededits-toolbar-buttons.adoc} | 2 +- 14 files changed, 144 insertions(+), 144 deletions(-) rename modules/ROOT/examples/live-demos/{trackchanges => suggestededits}/example.js (100%) rename modules/ROOT/examples/live-demos/{trackchanges => suggestededits}/index.html (84%) rename modules/ROOT/examples/live-demos/{trackchanges => suggestededits}/index.js (100%) rename modules/ROOT/partials/commands/{trackchanges-cmds.adoc => suggestededits-cmds.adoc} (50%) create mode 100644 modules/ROOT/partials/configuration/suggestededits-options.adoc delete mode 100644 modules/ROOT/partials/configuration/trackchanges-options.adoc rename modules/ROOT/partials/events/{trackchanges-events.adoc => suggestededits-events.adoc} (57%) rename modules/ROOT/partials/menu-item-ids/{trackchanges-menu-items.adoc => suggestededits-menu-items.adoc} (75%) rename modules/ROOT/partials/plugin-apis/{trackchanges-apis.adoc => suggestededits-apis.adoc} (70%) rename modules/ROOT/partials/toolbar-button-ids/{trackchanges-toolbar-buttons.adoc => suggestededits-toolbar-buttons.adoc} (59%) diff --git a/modules/ROOT/examples/live-demos/trackchanges/example.js b/modules/ROOT/examples/live-demos/suggestededits/example.js similarity index 100% rename from modules/ROOT/examples/live-demos/trackchanges/example.js rename to modules/ROOT/examples/live-demos/suggestededits/example.js diff --git a/modules/ROOT/examples/live-demos/trackchanges/index.html b/modules/ROOT/examples/live-demos/suggestededits/index.html similarity index 84% rename from modules/ROOT/examples/live-demos/trackchanges/index.html rename to modules/ROOT/examples/live-demos/suggestededits/index.html index d2dabf9f53..7f32961fc0 100644 --- a/modules/ROOT/examples/live-demos/trackchanges/index.html +++ b/modules/ROOT/examples/live-demos/suggestededits/index.html @@ -1,22 +1,12 @@ diff --git a/modules/ROOT/examples/live-demos/trackchanges/index.js b/modules/ROOT/examples/live-demos/suggestededits/index.js similarity index 100% rename from modules/ROOT/examples/live-demos/trackchanges/index.js rename to modules/ROOT/examples/live-demos/suggestededits/index.js diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc index 636d3088c3..eb50325379 100644 --- a/modules/ROOT/nav.adoc +++ b/modules/ROOT/nav.adoc @@ -351,6 +351,7 @@ **** xref:introduction-to-tiny-spellchecker.adoc[Spell Checker] **** xref:custom-dictionaries-for-tiny-spellchecker.adoc[Adding custom dictionaries] *** xref:autocorrect.adoc[Spelling Autocorrect] +*** xref:suggestededits.adoc[Suggested Edits] *** xref:tableofcontents.adoc[Table of Contents] *** xref:advanced-templates.adoc[Templates] *** Tiny Drive @@ -377,7 +378,6 @@ ***** xref:tinydrive-pick.adoc[The Pick API] ***** xref:tinydrive-type-interfaces.adoc[TypeScript interfaces] **** xref:tinydrive-changelog.adoc[Changelog] -*** xref:suggestededits.adoc[Suggested Edits] ** Open source plugins *** xref:accordion.adoc[Accordion] *** xref:anchor.adoc[Anchor] diff --git a/modules/ROOT/pages/7.0-release-notes.adoc b/modules/ROOT/pages/7.0-release-notes.adoc index 99f52461d6..fa559046db 100644 --- a/modules/ROOT/pages/7.0-release-notes.adoc +++ b/modules/ROOT/pages/7.0-release-notes.adoc @@ -49,7 +49,7 @@ The following new Premium plugins was released alongside {productname} 7.0. [[premium-plugin-revision-history]] === Revision History -The new Premium plugin, **Revision History**, allows you to track changes made to content in the {productname} editor and restore previous versions of the content. +The new Premium plugin, **Revision History**, allows you to Suggested Edits made to content in the {productname} editor and restore previous versions of the content. For information on the **Revision History** plugin, see xref:revisionhistory.adoc[Revision History]. diff --git a/modules/ROOT/pages/suggestededits.adoc b/modules/ROOT/pages/suggestededits.adoc index 34534d0b4d..fc5277efd1 100644 --- a/modules/ROOT/pages/suggestededits.adoc +++ b/modules/ROOT/pages/suggestededits.adoc @@ -4,7 +4,7 @@ :description_short: A view of tracked changes made by multiple authors :keywords: plugin, Suggested Edits, changes, diff :pluginname: Suggested Edits -:plugincode: trackchanges +:plugincode: suggestededits :plugincategory: premium include::partial$misc/admon-revisionhistory-paid-addon-pricing.adoc[] @@ -62,9 +62,9 @@ For example: ---- tinymce.init({ selector: 'textarea', // change this value according to your HTML - plugins: 'trackchanges', - toolbar: 'trackchanges', - trackchanges_model: { + plugins: 'suggestededits', + toolbar: 'suggestededits', + suggestededits_model: { version: 1, maxId: 0, contents: [ @@ -76,7 +76,7 @@ tinymce.init({ } ] }, - trackchanges_uid: 'unique-identifier' // replace this with a unique string to identify the user + suggestededits_uid: 'unique-identifier' // replace this with a unique string to identify the user }); ---- @@ -84,7 +84,7 @@ tinymce.init({ The following configuration options affect the behavior of the {pluginname} plugin. -include::partial$configuration/trackchanges-options.adoc[leveloffset=+1] +include::partial$configuration/suggestededits-options.adoc[leveloffset=+1] include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] diff --git a/modules/ROOT/partials/commands/trackchanges-cmds.adoc b/modules/ROOT/partials/commands/suggestededits-cmds.adoc similarity index 50% rename from modules/ROOT/partials/commands/trackchanges-cmds.adoc rename to modules/ROOT/partials/commands/suggestededits-cmds.adoc index 9dcee19963..c7873a96c3 100644 --- a/modules/ROOT/partials/commands/trackchanges-cmds.adoc +++ b/modules/ROOT/partials/commands/suggestededits-cmds.adoc @@ -2,11 +2,11 @@ |=== |Command |Description -|trackchanges |Toggle the Track Changes view +|suggestededits |Toggle the Suggested Edits view |=== .Examples [source,js] ---- -tinymce.activeEditor.execCommand('trackchanges'); +tinymce.activeEditor.execCommand('suggestededits'); ---- diff --git a/modules/ROOT/partials/configuration/defaultmenuitems.adoc b/modules/ROOT/partials/configuration/defaultmenuitems.adoc index e891f9803b..abd816b32a 100644 --- a/modules/ROOT/partials/configuration/defaultmenuitems.adoc +++ b/modules/ROOT/partials/configuration/defaultmenuitems.adoc @@ -5,7 +5,7 @@ tinymce.init({ menu: { 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 trackchanges | visualaid visualchars visualblocks | spellchecker | preview fullscreen | showcomments' }, + view: { title: 'View', items: 'code revisionhistory suggestededits | visualaid visualchars visualblocks | spellchecker | preview fullscreen | showcomments' }, 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' }, diff --git a/modules/ROOT/partials/configuration/suggestededits-options.adoc b/modules/ROOT/partials/configuration/suggestededits-options.adoc new file mode 100644 index 0000000000..96322925a2 --- /dev/null +++ b/modules/ROOT/partials/configuration/suggestededits-options.adoc @@ -0,0 +1,110 @@ +[[suggestededits_model]] +== `suggestededits_model` + +The `suggestededits_model` option sets the initial model of the document to begin tracking changes. It takes as input an object representing the document. If no value is set, the plugin will generate the model by default. + +//*Type:* xref:#trackeddocument[TrackedDocument] `+Object+` + +=== Example: using `suggestededits_model` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + suggestededits_model: { + version: 1, + maxId: 0, + contents: [ + { + type: 'p', + children: [ + { text: 'Hello, World!' } + ] + } + ] + } +}); +---- + +[[suggestededits_uid]] +== `suggestededits_uid` + +The `suggestededits_uid` is a _required_ option that takes as input a unique string to identify the current user. This is used to attribute changes made by the user. + +*Type:* `+String+` + +=== Example: using `suggestededits_uid` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + suggestededits_uid: 'unique-identifier' // replace this with a unique string to identify the user +}); +---- + +[[suggestededits_css_url]] +== `suggestededits_css_url` + +The `suggestededits_css_url` option sets the location where a CSS file containing change annotations in the {pluginname} view should be loaded from. To override the default CSS classes, use this option alongside `suggestededits_diff_classes`. + +*Type:* `+String+` + +*Default value:* `'${pluginUrl}/css/suggestededits.css'` + +=== Example: using `suggestededits_css_url` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + suggestededits_css_url: './suggestededits.css' +}); +---- + +[[suggestededits_diff_classes]] +== `suggestededits_diff_classes` + +The `suggestededits_diff_classes` option configures the CSS classes applied to the change annotations in the {pluginname} view. This is useful to set custom styles and must be used in combination with the `suggestededits_css_url` option. + +[NOTE] +The CSS class names must exist in the xref:suggestededits_css_url[`+suggestededits_css_url+`]. + +*Type:* `+Object+` + +*Default value:* `addition`, `removal`, `modification` + +Below are the default CSS classes: + +[source,js] +---- +{ + addition: 'tox-suggestededits__annotation--added', + removal: 'tox-suggestededits__annotation--removed', + modification: 'tox-suggestededits__annotation--modified' +} +---- + +=== Example: using `suggestededits_diff_classes` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + suggestededits_css_url: './suggestededits.css', + suggestededits_diff_classes: { + addition: 'added', + removal: 'removed', + modification: 'modified' + } +}); +---- diff --git a/modules/ROOT/partials/configuration/trackchanges-options.adoc b/modules/ROOT/partials/configuration/trackchanges-options.adoc deleted file mode 100644 index 1af4b9d22b..0000000000 --- a/modules/ROOT/partials/configuration/trackchanges-options.adoc +++ /dev/null @@ -1,110 +0,0 @@ -[[trackchanges_model]] -== `trackchanges_model` - -The `trackchanges_model` option sets the initial model of the document to be begin tracking changes. It takes as input an object representing the document. If no value is set, the plugin will generate the model by default. - -//*Type:* xref:#trackeddocument[TrackedDocument] `+Object+` - -=== Example: using `trackchanges_model` - -// Add a working and tested configuration. -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - plugins: 'trackchanges', - toolbar: 'trackchanges', - trackchanges_model: { - version: 1, - maxId: 0, - contents: [ - { - type: 'p', - children: [ - { text: 'Hello, World!' } - ] - } - ] - } -}); ----- - -[[trackchanges_uid]] -== `trackchanges_uid` - -The `trackchanges_uid` is a _required_ option that takes as input a unique string to identify the current user. This is used to attribute changes made by the user. - -*Type:* `+String+` - -=== Example: using `trackchanges_uid` - -// Add a working and tested configuration. -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - plugins: 'trackchanges', - toolbar: 'trackchanges', - trackchanges_uid: 'unique-identifier' // replace this with a unique string to identify the user -}); ----- - -[[trackchanges_css_url]] -== `trackchanges_css_url` - -The `trackchanges_css_url` option sets the location where a CSS file containing change annotations in the {pluginname} view should be loaded from. To override the default CSS classes, use this option alongside `trackchanges_diff_classes`. - -*Type:* `+String+` - -*Default value:* `'${pluginUrl}/css/trackchanges.css'` - -=== Example: using `trackchanges_css_url` - -// Add a working and tested configuration. -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - trackchanges_css_url: './trackchanges.css' -}); ----- - -[[trackchanges_diff_classes]] -== `trackchanges_diff_classes` - -The `trackchanges_diff_classes` option configures the CSS classes applied to the change annotations in the {pluginname} view. This is useful to set custom styles and must be used in combination with the `trackchanges_css_url` option. - -[NOTE] -The CSS class names must exist in the xref:trackchanges_css_url[`+trackchanges_css_url+`]. - -*Type:* `+Object+` - -*Default value:* `addition`, `removal`, `modification` - -Below are the default CSS classes: - -[source,js] ----- -{ - addition: 'tox-trackchanges__annotation--added', - removal: 'tox-trackchanges__annotation--removed', - modification: 'tox-trackchanges__annotation--modified' -} ----- - -=== Example: using `trackchanges_diff_classes` - -[source,js] ----- -tinymce.init({ - selector: 'textarea', // change this value according to your HTML - plugins: 'trackchanges', - toolbar: 'trackchanges', - trackchanges_css_url: './trackchanges.css', - trackchanges_diff_classes: { - addition: 'added', - removal: 'removed', - modification: 'modified' - } -}); ----- diff --git a/modules/ROOT/partials/events/trackchanges-events.adoc b/modules/ROOT/partials/events/suggestededits-events.adoc similarity index 57% rename from modules/ROOT/partials/events/trackchanges-events.adoc rename to modules/ROOT/partials/events/suggestededits-events.adoc index a3fedfbff0..9b411215a0 100644 --- a/modules/ROOT/partials/events/trackchanges-events.adoc +++ b/modules/ROOT/partials/events/suggestededits-events.adoc @@ -3,9 +3,9 @@ The following events are provided by the xref:{plugincode}.adoc[{pluginname} plu [cols="1,1,2",options="header"] |=== |Name |Data |Description -|TrackChangesBeginReview |N/A |Fired when the Track Changes view opens. -|TrackChangesReviewComplete |N/A |Fired when a review in the Track Changes view is completed. -|TrackChangesReviewCancelled |N/A |Fired when a review in the Track Changes view is cancelled. +|suggestededitsBeginReview |N/A |Fired when the Suggested Edits view opens. +|suggestededitsReviewComplete |N/A |Fired when a review in the Suggested Edits view is completed. +|suggestededitsReviewCancelled |N/A |Fired when a review in the Suggested Edits view is cancelled. // 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. diff --git a/modules/ROOT/partials/menu-item-ids/trackchanges-menu-items.adoc b/modules/ROOT/partials/menu-item-ids/suggestededits-menu-items.adoc similarity index 75% rename from modules/ROOT/partials/menu-item-ids/trackchanges-menu-items.adoc rename to modules/ROOT/partials/menu-item-ids/suggestededits-menu-items.adoc index edde0cbb96..d45e2420b5 100644 --- a/modules/ROOT/partials/menu-item-ids/trackchanges-menu-items.adoc +++ b/modules/ROOT/partials/menu-item-ids/suggestededits-menu-items.adoc @@ -2,5 +2,5 @@ |=== |Menu item identifier |xref:menus-configuration-options.adoc#example-the-tinymce-default-menu-items[Default Menu Location] |Description -|`trackchanges` |View |Opens the Track Changes view. +|`suggestededits` |View |Opens the Suggested Edits view. |=== \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc b/modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc similarity index 70% rename from modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc rename to modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc index 339ad43f50..725698b6e5 100644 --- a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc +++ b/modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc @@ -12,10 +12,10 @@ [source,js] ---- // Get the current model of the document -tinymce.activeEditor.plugins.trackchanges.getModel(); +tinymce.activeEditor.plugins.suggestededits.getModel(); // Check if document contains changes to be reviewed -tinymce.activeEditor.plugins.trackchanges.hasChanges(); +tinymce.activeEditor.plugins.suggestededits.hasChanges(); ---- //// @@ -23,15 +23,15 @@ tinymce.activeEditor.plugins.trackchanges.hasChanges(); [source,js] ---- // Get the current model of the document -tinymce.activeEditor.plugins.trackchanges.getModel(); +tinymce.activeEditor.plugins.suggestededits.getModel(); // Set current model of the document -tinymce.activeEditor.plugins.trackchanges.setModel(model); +tinymce.activeEditor.plugins.suggestededits.setModel(model); // Reset the document model to its original state -tinymce.activeEditor.plugins.trackchanges.resetModel(); +tinymce.activeEditor.plugins.suggestededits.resetModel(); // Check if document contains changes to be reviewed -tinymce.activeEditor.plugins.trackchanges.hasChanges(); +tinymce.activeEditor.plugins.suggestededits.hasChanges(); ---- //// \ No newline at end of file diff --git a/modules/ROOT/partials/toolbar-button-ids/trackchanges-toolbar-buttons.adoc b/modules/ROOT/partials/toolbar-button-ids/suggestededits-toolbar-buttons.adoc similarity index 59% rename from modules/ROOT/partials/toolbar-button-ids/trackchanges-toolbar-buttons.adoc rename to modules/ROOT/partials/toolbar-button-ids/suggestededits-toolbar-buttons.adoc index 4def3fff9f..45fc5d5f82 100644 --- a/modules/ROOT/partials/toolbar-button-ids/trackchanges-toolbar-buttons.adoc +++ b/modules/ROOT/partials/toolbar-button-ids/suggestededits-toolbar-buttons.adoc @@ -2,5 +2,5 @@ |=== |Toolbar button identifier |Description -|`+trackchanges+` |Open the Track Changes view. +|`+suggestededits+` |Open the Suggested Edits view. |=== \ No newline at end of file From 99870e930468d021314c83ad96cf47788fe08082 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Tue, 15 Apr 2025 09:20:00 +1000 Subject: [PATCH 09/68] Update docs to include Review Permissions V1 --- .../suggestededits-access/index.html | 34 ++++++++ .../live-demos/suggestededits-access/index.js | 10 +++ .../live-demos/suggestededits/index.js | 1 + .../configuration/suggestededits-options.adoc | 79 +++++++++++++++---- 4 files changed, 109 insertions(+), 15 deletions(-) create mode 100644 modules/ROOT/examples/live-demos/suggestededits-access/index.html create mode 100644 modules/ROOT/examples/live-demos/suggestededits-access/index.js diff --git a/modules/ROOT/examples/live-demos/suggestededits-access/index.html b/modules/ROOT/examples/live-demos/suggestededits-access/index.html new file mode 100644 index 0000000000..97445bffd3 --- /dev/null +++ b/modules/ROOT/examples/live-demos/suggestededits-access/index.html @@ -0,0 +1,34 @@ + diff --git a/modules/ROOT/examples/live-demos/suggestededits-access/index.js b/modules/ROOT/examples/live-demos/suggestededits-access/index.js new file mode 100644 index 0000000000..e6b255cb43 --- /dev/null +++ b/modules/ROOT/examples/live-demos/suggestededits-access/index.js @@ -0,0 +1,10 @@ +tinymce.init({ + selector: 'textarea#trackchanges', + height: 500, + plugins: 'trackchanges', + toolbar: 'trackchanges', + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', + trackchanges_uid: 'adamhenderson', + trackchanges_access: 'read', //change this value to set permission to the Suggested Edits view + readonly: false //set to true to restrict a user's editing permission +}); \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/suggestededits/index.js b/modules/ROOT/examples/live-demos/suggestededits/index.js index 4d888ade46..4334e24a28 100644 --- a/modules/ROOT/examples/live-demos/suggestededits/index.js +++ b/modules/ROOT/examples/live-demos/suggestededits/index.js @@ -35,3 +35,4 @@ tinymce.init({ trackchanges_uid: 'adamhenderson', trackchanges_user_lookup, }); + diff --git a/modules/ROOT/partials/configuration/suggestededits-options.adoc b/modules/ROOT/partials/configuration/suggestededits-options.adoc index 96322925a2..a4cb7e6dcc 100644 --- a/modules/ROOT/partials/configuration/suggestededits-options.adoc +++ b/modules/ROOT/partials/configuration/suggestededits-options.adoc @@ -1,11 +1,31 @@ +[[suggestededits_uid]] +== `suggestededits_uid` + +The `{plugincode}_uid` is a _required_ option that takes as input a unique string to identify the current user. This is used to attribute changes made by the user. + +*Type:* `+String+` + +=== Example: using `{plugincode}_uid` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + suggestededits_uid: 'unique-identifier' // replace this with a unique string to identify the user +}); +---- + [[suggestededits_model]] == `suggestededits_model` -The `suggestededits_model` option sets the initial model of the document to begin tracking changes. It takes as input an object representing the document. If no value is set, the plugin will generate the model by default. +The `{plugincode}_model` option sets the initial model of the document to begin tracking changes. It takes as input an object representing the document. If no value is set, the plugin will generate the model by default. //*Type:* xref:#trackeddocument[TrackedDocument] `+Object+` -=== Example: using `suggestededits_model` +=== Example: using `{plugincode}_model` // Add a working and tested configuration. [source,js] @@ -14,6 +34,7 @@ tinymce.init({ selector: 'textarea', // Change this value according to your HTML plugins: 'suggestededits', toolbar: 'suggestededits', + suggestededits_uid: 'unique-identifier', // replace this with a unique string to identify the user suggestededits_model: { version: 1, maxId: 0, @@ -29,36 +50,64 @@ tinymce.init({ }); ---- -[[suggestededits_uid]] -== `suggestededits_uid` +[[suggestededits_access]] +== `suggestededits_access` -The `suggestededits_uid` is a _required_ option that takes as input a unique string to identify the current user. This is used to attribute changes made by the user. +To configure a user's permission to edit the document and review changes, the `{plugincode}_access` option can be set alongside the editor mode. *Type:* `+String+` -=== Example: using `suggestededits_uid` +*Possible Values*: `'full'`, `'suggest'`, `'read'`, `'none'` -// Add a working and tested configuration. -[source,js] +*Default Value*: `'full'` + +The possible values set the access level of the review permissions as follows: + +[cols="20%,80%"] +|=== +|Value | Review Permission + +|`+'full'+` +|Access to the {pluginname} view, with permission to accept, reject, or add suggestions to changes. + +|`+'suggest'+` +|Access to the {pluginname} view, with permission to add suggestions to changes. + +|`+'read'+` +|Readonly access to the {pluginname} view. + +|`+'none'+` +|No access to the {pluginname} view. +|=== + +[NOTE] +The `{plugincode}_access` option can be used in combination with the editor's read-only mode to restrict a user’s editing permission. + +.Example +[source,javascript] ---- tinymce.init({ selector: 'textarea', // Change this value according to your HTML plugins: 'suggestededits', toolbar: 'suggestededits', - suggestededits_uid: 'unique-identifier' // replace this with a unique string to identify the user + suggestededits_uid: 'unique-identifier', // replace this with a unique string to identify the user + suggestededits_access: 'full' //change this value to set permission to the Suggested Edits view + readonly: false //set to true to restrict a user's editing permission }); ---- +liveDemo::suggestededits-access[] + [[suggestededits_css_url]] == `suggestededits_css_url` -The `suggestededits_css_url` option sets the location where a CSS file containing change annotations in the {pluginname} view should be loaded from. To override the default CSS classes, use this option alongside `suggestededits_diff_classes`. +The `{plugincode}_css_url` option sets the location where a CSS file containing change annotations in the {pluginname} view should be loaded from. To override the default CSS classes, use this option alongside `{plugincode}_diff_classes`. *Type:* `+String+` -*Default value:* `'${pluginUrl}/css/suggestededits.css'` +*Default value:* `'${pluginUrl}/css/{plugincode}.css'` -=== Example: using `suggestededits_css_url` +=== Example: using `{plugincode}_css_url` // Add a working and tested configuration. [source,js] @@ -72,10 +121,10 @@ tinymce.init({ [[suggestededits_diff_classes]] == `suggestededits_diff_classes` -The `suggestededits_diff_classes` option configures the CSS classes applied to the change annotations in the {pluginname} view. This is useful to set custom styles and must be used in combination with the `suggestededits_css_url` option. +The `{plugincode}_diff_classes` option configures the CSS classes applied to the change annotations in the {pluginname} view. This is useful to set custom styles and must be used in combination with the `{plugincode}_css_url` option. [NOTE] -The CSS class names must exist in the xref:suggestededits_css_url[`+suggestededits_css_url+`]. +The CSS class names must exist in the xref:{plugincode}_css_url[`+{plugincode}_css_url+`]. *Type:* `+Object+` @@ -92,7 +141,7 @@ Below are the default CSS classes: } ---- -=== Example: using `suggestededits_diff_classes` +=== Example: using `{plugincode}_diff_classes` [source,js] ---- From c4680c9fa2c10eb32e29a88dbeff584a3d9fc3e8 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Tue, 15 Apr 2025 10:02:52 +1000 Subject: [PATCH 10/68] Fix demo for Review Permissions --- .../suggestededits-access/index.html | 2 +- .../live-demos/suggestededits-access/index.js | 32 +++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/modules/ROOT/examples/live-demos/suggestededits-access/index.html b/modules/ROOT/examples/live-demos/suggestededits-access/index.html index 97445bffd3..eb09c543be 100644 --- a/modules/ROOT/examples/live-demos/suggestededits-access/index.html +++ b/modules/ROOT/examples/live-demos/suggestededits-access/index.html @@ -1,4 +1,4 @@ - diff --git a/modules/ROOT/examples/live-demos/suggestededits-suggestions/index.js b/modules/ROOT/examples/live-demos/suggestededits-suggestions/index.js new file mode 100644 index 0000000000..0484a81b82 --- /dev/null +++ b/modules/ROOT/examples/live-demos/suggestededits-suggestions/index.js @@ -0,0 +1,38 @@ +/** Fake user database */ +const userinfos = { + adamhenderson: { + uid: 'adamhenderson', + name: 'Adam Henderson', + avatar: `https://randomuser.me/api/portraits/men/1.jpg`, + }, + michaelcook: { + uid: 'michaelcook', + name: 'Michael Cook', + avatar: `https://randomuser.me/api/portraits/men/2.jpg`, + }, + kalebwilson: { + uid: 'kalebwilson', + name: 'Kaleb Wilson', + avatar: `https://randomuser.me/api/portraits/men/3.jpg`, + }, + kyleeinstein: { + uid: 'kyleeinstein', + name: 'Kyle Einstein', + avatar: `https://randomuser.me/api/portraits/men/4.jpg`, + }, +}; + +const trackchanges_user_lookup = (uid) => new Promise((resolve, reject) => + setTimeout(() => userinfos[uid] ? resolve(userinfos[uid]) : reject(), 1000)); + +tinymce.init({ + selector: 'textarea#trackchanges_suggestions', + height: 500, + plugins: 'trackchanges', + toolbar: 'trackchanges', + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', + trackchanges_uid: 'adamhenderson', + trackchanges_access: 'suggest', //change this value to set permission to the Suggested Edits view + readonly: false, //set to true to restrict a user's editing permission + trackchanges_user_lookup +}); \ No newline at end of file diff --git a/modules/ROOT/pages/suggestededits.adoc b/modules/ROOT/pages/suggestededits.adoc index fc5277efd1..5301618573 100644 --- a/modules/ROOT/pages/suggestededits.adoc +++ b/modules/ROOT/pages/suggestededits.adoc @@ -80,6 +80,14 @@ tinymce.init({ }); ---- +== Suggestions + +The plugin also enables users to provide suggestions or feedback to edits before they are resolved. This feature is only available if xref:{plugincode}_access[`+suggestededits_access+`] is set to `admin` or `suggest`. + +Example: Using Suggestions + +liveDemo::suggestededits-suggestions[] + == Options The following configuration options affect the behavior of the {pluginname} plugin. diff --git a/modules/ROOT/partials/configuration/suggestededits-options.adoc b/modules/ROOT/partials/configuration/suggestededits-options.adoc index a4cb7e6dcc..2e16c037e0 100644 --- a/modules/ROOT/partials/configuration/suggestededits-options.adoc +++ b/modules/ROOT/partials/configuration/suggestededits-options.adoc @@ -124,7 +124,7 @@ tinymce.init({ The `{plugincode}_diff_classes` option configures the CSS classes applied to the change annotations in the {pluginname} view. This is useful to set custom styles and must be used in combination with the `{plugincode}_css_url` option. [NOTE] -The CSS class names must exist in the xref:{plugincode}_css_url[`+{plugincode}_css_url+`]. +The CSS class names must exist in the xref:{plugincode}_css_url[`+suggestededits_css_url+`]. *Type:* `+Object+` From 980adc3769a162c4133f66fb917d3bc0692bf45c Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Fri, 9 May 2025 13:30:18 +1000 Subject: [PATCH 12/68] Revise Suggestions content --- modules/ROOT/pages/suggestededits.adoc | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/modules/ROOT/pages/suggestededits.adoc b/modules/ROOT/pages/suggestededits.adoc index 5301618573..b7479d5c65 100644 --- a/modules/ROOT/pages/suggestededits.adoc +++ b/modules/ROOT/pages/suggestededits.adoc @@ -47,6 +47,8 @@ The sidebar also displays all tracked changes that need to be resolved. Each cha * Reject: Removes the change from the document. * Revert: Undoes a previously accepted or rejected change. +The plugin also enables users to view and provide suggestions to edits. All users with access to the {pluginname} View can view suggestions. To allow users to provide suggestions, xref:{plugincode}_access[`{plugincode}_access`] must be set to either `admin` or `suggest`. + == Basic setup To setup the {pluginname} plugin in the editor: @@ -80,14 +82,6 @@ tinymce.init({ }); ---- -== Suggestions - -The plugin also enables users to provide suggestions or feedback to edits before they are resolved. This feature is only available if xref:{plugincode}_access[`+suggestededits_access+`] is set to `admin` or `suggest`. - -Example: Using Suggestions - -liveDemo::suggestededits-suggestions[] - == Options The following configuration options affect the behavior of the {pluginname} plugin. From 7afd9a17370966dbd7a3e344409f619d0be9809c Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Wed, 19 Mar 2025 10:21:58 +1000 Subject: [PATCH 13/68] Initial setup --- modules/ROOT/nav.adoc | 1 + modules/ROOT/pages/trackchanges.adoc | 67 +++++++++++++++++++ .../partials/commands/trackchanges-cmds.adoc | 33 +++++++++ .../configuration/defaultmenuitems.adoc | 2 +- .../configuration/trackchanges-options.adoc | 57 ++++++++++++++++ .../partials/events/trackchanges-events.adoc | 17 +++++ .../partials/index-pages/premium-plugins.adoc | 5 ++ .../trackchanges-menu-items.adoc | 6 ++ .../partials/misc/admon-requires-8.0v.adoc | 1 + .../plugin-apis/trackchanges-apis.adoc | 23 +++++++ .../trackchanges-toolbar-buttons.adoc | 6 ++ 11 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 modules/ROOT/pages/trackchanges.adoc create mode 100644 modules/ROOT/partials/commands/trackchanges-cmds.adoc create mode 100644 modules/ROOT/partials/configuration/trackchanges-options.adoc create mode 100644 modules/ROOT/partials/events/trackchanges-events.adoc create mode 100644 modules/ROOT/partials/menu-item-ids/trackchanges-menu-items.adoc create mode 100644 modules/ROOT/partials/misc/admon-requires-8.0v.adoc create mode 100644 modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc create mode 100644 modules/ROOT/partials/toolbar-button-ids/trackchanges-toolbar-buttons.adoc diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc index 04ebfa9fe1..274f9be34e 100644 --- a/modules/ROOT/nav.adoc +++ b/modules/ROOT/nav.adoc @@ -371,6 +371,7 @@ ***** xref:tinydrive-pick.adoc[The Pick API] ***** xref:tinydrive-type-interfaces.adoc[TypeScript interfaces] **** xref:tinydrive-changelog.adoc[Changelog] +*** xref:trackchanges.adoc[Track Changes] ** Open source plugins *** xref:accordion.adoc[Accordion] *** xref:anchor.adoc[Anchor] diff --git a/modules/ROOT/pages/trackchanges.adoc b/modules/ROOT/pages/trackchanges.adoc new file mode 100644 index 0000000000..9a686415a2 --- /dev/null +++ b/modules/ROOT/pages/trackchanges.adoc @@ -0,0 +1,67 @@ += Track Changes Plugin +:navtitle: Track Changes +:description: A view that allows users to review document changes made by multiple authors +:description_short: A view of tracked changes made by multiple authors +:keywords: plugin, Track Changes, changes, diff +:pluginname: Track Changes +:plugincode: trackchanges +:plugincategory: premium + +include::partial$misc/admon-revisionhistory-paid-addon-pricing.adoc[] + +include::partial$misc/admon-requires-8.0v.adoc[] + +The Track Changes plugin allows users to easily review and manage changes made to a document by multiple authors. + +== Interactive example + +== How it works + +== Basic setup + +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; + +For example: + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'trackchanges', + toolbar: 'trackchanges', + // track changes options +}); +---- + +== Data structure + +== Options + +The following configuration options affect the behavior of the {pluginname} plugin. + +include::partial$configuration/trackchanges-options.adoc[] + +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[] + +== Events + +The {pluginname} plugin provides the following events. + +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/partials/commands/trackchanges-cmds.adoc b/modules/ROOT/partials/commands/trackchanges-cmds.adoc new file mode 100644 index 0000000000..9d61f6860b --- /dev/null +++ b/modules/ROOT/partials/commands/trackchanges-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/modules/ROOT/partials/configuration/defaultmenuitems.adoc b/modules/ROOT/partials/configuration/defaultmenuitems.adoc index dd2c811ce9..e891f9803b 100644 --- a/modules/ROOT/partials/configuration/defaultmenuitems.adoc +++ b/modules/ROOT/partials/configuration/defaultmenuitems.adoc @@ -5,7 +5,7 @@ tinymce.init({ menu: { 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' }, + view: { title: 'View', items: 'code revisionhistory trackchanges | visualaid visualchars visualblocks | spellchecker | preview fullscreen | showcomments' }, 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' }, diff --git a/modules/ROOT/partials/configuration/trackchanges-options.adoc b/modules/ROOT/partials/configuration/trackchanges-options.adoc new file mode 100644 index 0000000000..391b450c3b --- /dev/null +++ b/modules/ROOT/partials/configuration/trackchanges-options.adoc @@ -0,0 +1,57 @@ +[[]] +== `` + +//// +What does the option do? +Why use it? +When use it? +What values can it use? +What do these values do? +Are there risks? + - Explain without using ‘risk’ or similar words. + - Use NOTE or IMPORTANT admonitions if helpful. + - For longer or more complicated scenarios, use the limitations section below. +//// + +*Type:* `+String+`, `+Boolean+`, `+Number+`, `+Function+`, `+Object+`, `+Array+`, or `+Regexp+` + +// Remove the *Possible values* line if there is no discrete set of possible values. +*Possible values:* `'string1'`, `'string2'`, `false` + +*Default value:* `false`, `1`, `'string1'` + +=== Example: using `` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : '' +}); +---- + +// Add a working and tested configuration (edit as required) +// or remove if not applicable. +=== Example: disabling the + +To disable , set `` to `false`. + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : 'false' +}); +---- + +// Remove if not applicable. +=== Limitation of the `` option + +The `` option has the following limitations. + +//// +Known limitations. +Complicated scenarios. +Anything that warrants a CAUTION or WARNING admonition. +//// \ No newline at end of file diff --git a/modules/ROOT/partials/events/trackchanges-events.adoc b/modules/ROOT/partials/events/trackchanges-events.adoc new file mode 100644 index 0000000000..79e6124bd0 --- /dev/null +++ b/modules/ROOT/partials/events/trackchanges-events.adoc @@ -0,0 +1,17 @@ +The following events are provided by the xref:{plugincode}.adoc[{pluginname} plugin]. + +[cols="1,1,2",options="header"] +|=== +|Name |Data |Description +|EventOne |`+{ : }+` |Fired when event one description. +|EventTwo |`+{ : , : }+` |Fired when event two description. +|EventThree |N/A |Fired when event three description. +// 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[] +|EventFour |`+{ : }+` |Fired when the event seven description. +|EventEn |`+{ : , : }+` |Fired when event en description. +|=== \ No newline at end of file diff --git a/modules/ROOT/partials/index-pages/premium-plugins.adoc b/modules/ROOT/partials/index-pages/premium-plugins.adoc index 3d76fe8cc5..f2770bfe03 100644 --- a/modules/ROOT/partials/index-pages/premium-plugins.adoc +++ b/modules/ROOT/partials/index-pages/premium-plugins.adoc @@ -201,7 +201,12 @@ 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| +[.lead] +xref:trackchanges.adoc[Track Changes] + +Review document changes by multiple users. |=== diff --git a/modules/ROOT/partials/menu-item-ids/trackchanges-menu-items.adoc b/modules/ROOT/partials/menu-item-ids/trackchanges-menu-items.adoc new file mode 100644 index 0000000000..edde0cbb96 --- /dev/null +++ b/modules/ROOT/partials/menu-item-ids/trackchanges-menu-items.adoc @@ -0,0 +1,6 @@ +[cols="1,1,2",options="header"] +|=== +|Menu item identifier |xref:menus-configuration-options.adoc#example-the-tinymce-default-menu-items[Default Menu Location] |Description + +|`trackchanges` |View |Opens the Track Changes view. +|=== \ No newline at end of file diff --git a/modules/ROOT/partials/misc/admon-requires-8.0v.adoc b/modules/ROOT/partials/misc/admon-requires-8.0v.adoc new file mode 100644 index 0000000000..9160a25fc7 --- /dev/null +++ b/modules/ROOT/partials/misc/admon-requires-8.0v.adoc @@ -0,0 +1 @@ +NOTE: This feature is only available for {productname} 8.0 and later. diff --git a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc b/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc new file mode 100644 index 0000000000..da3b8a1a17 --- /dev/null +++ b/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc @@ -0,0 +1,23 @@ +[cols="1,1,4",options="header"] +|=== +|Name |Arguments |Description + +| | | +// 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 +[source,js] +---- +// what this example does +tinymce.activeEditor.plugins..(); + +// what this example does +tinymce.activeEditor.plugins..(); +---- diff --git a/modules/ROOT/partials/toolbar-button-ids/trackchanges-toolbar-buttons.adoc b/modules/ROOT/partials/toolbar-button-ids/trackchanges-toolbar-buttons.adoc new file mode 100644 index 0000000000..4def3fff9f --- /dev/null +++ b/modules/ROOT/partials/toolbar-button-ids/trackchanges-toolbar-buttons.adoc @@ -0,0 +1,6 @@ +[cols="1,3",options="header"] +|=== +|Toolbar button identifier |Description + +|`+trackchanges+` |Open the Track Changes view. +|=== \ No newline at end of file From c9ba93b66aac892ff33fadf11e24878308c58de8 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Wed, 19 Mar 2025 10:37:59 +1000 Subject: [PATCH 14/68] add live demo template --- .../live-demos/trackchanges/example.js | 30 +++++++++++++++++++ .../live-demos/trackchanges/index.html | 15 ++++++++++ .../examples/live-demos/trackchanges/index.js | 16 ++++++++++ modules/ROOT/pages/trackchanges.adoc | 4 +++ 4 files changed, 65 insertions(+) create mode 100644 modules/ROOT/examples/live-demos/trackchanges/example.js create mode 100644 modules/ROOT/examples/live-demos/trackchanges/index.html create mode 100644 modules/ROOT/examples/live-demos/trackchanges/index.js diff --git a/modules/ROOT/examples/live-demos/trackchanges/example.js b/modules/ROOT/examples/live-demos/trackchanges/example.js new file mode 100644 index 0000000000..6b8e2b18e0 --- /dev/null +++ b/modules/ROOT/examples/live-demos/trackchanges/example.js @@ -0,0 +1,30 @@ +/* + +This file is not normally required. + +Sometimes, however, a plugin, or a particular feature of a plugin, +requires a back-end service. + +In these cases, creating a working demo requires setting up an +emulated version of this service. + +And `example.js` is part of this emulation. + +`index.js` still runs the live demo. + +But `example.js` is what is displayed in the *js* tab of the +live-demo interface on the built docs site. + +So `example.js` has to be a working equivalent to `index.js` *if* +`index.js` was wired up in a standard way, to its required back-end +service. + +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 ‘includes-an-emulated-back-end’ examples +will almost certainly include significant initial input from the +plugin’s developer. + +*/ diff --git a/modules/ROOT/examples/live-demos/trackchanges/index.html b/modules/ROOT/examples/live-demos/trackchanges/index.html new file mode 100644 index 0000000000..ebe4fa70ca --- /dev/null +++ b/modules/ROOT/examples/live-demos/trackchanges/index.html @@ -0,0 +1,15 @@ + diff --git a/modules/ROOT/examples/live-demos/trackchanges/index.js b/modules/ROOT/examples/live-demos/trackchanges/index.js new file mode 100644 index 0000000000..045103dc9d --- /dev/null +++ b/modules/ROOT/examples/live-demos/trackchanges/index.js @@ -0,0 +1,16 @@ +tinymce.init({ + selector: 'textarea#', +// below is a basic 6.x working configuration. +// Do not assume it is suitable for demonstrating the plugin to be documented. + height: 500, + plugins: [ + 'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'preview', + 'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen', + 'insertdatetime', 'media', 'table', 'help', 'wordcount' + ], + toolbar: 'undo redo | blocks | ' + + 'bold italic backcolor | alignleft aligncenter ' + + 'alignright alignjustify | bullist numlist outdent indent | ' + + 'removeformat | help', + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }' +}); diff --git a/modules/ROOT/pages/trackchanges.adoc b/modules/ROOT/pages/trackchanges.adoc index 9a686415a2..a0892c5956 100644 --- a/modules/ROOT/pages/trackchanges.adoc +++ b/modules/ROOT/pages/trackchanges.adoc @@ -15,6 +15,10 @@ The Track Changes plugin allows users to easily review and manage changes made t == Interactive example +liveDemo::{plugincode}[] + +include::partial$misc/admon-iframe-only.adoc[] + == How it works == Basic setup From db52e977257bdf1d17bfbf42999a83c4ff6191e9 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Fri, 21 Mar 2025 16:46:49 +1000 Subject: [PATCH 15/68] Update API sections --- modules/ROOT/pages/trackchanges.adoc | 37 ++- .../partials/commands/trackchanges-cmds.adoc | 25 +- .../configuration/trackchanges-options.adoc | 282 +++++++++++++++++- .../partials/events/trackchanges-events.adoc | 10 +- .../plugin-apis/trackchanges-apis.adoc | 22 +- 5 files changed, 326 insertions(+), 50 deletions(-) diff --git a/modules/ROOT/pages/trackchanges.adoc b/modules/ROOT/pages/trackchanges.adoc index a0892c5956..758c637e97 100644 --- a/modules/ROOT/pages/trackchanges.adoc +++ b/modules/ROOT/pages/trackchanges.adoc @@ -42,11 +42,44 @@ tinymce.init({ == Data structure +=== TrackedDocument + +`TrackedDocument` is an `+Object+` that contains the following fields: + +[cols="1,1,1,3",options="header"] +|=== +| Field | Type | Required? | Description +| `+version+` | `+Number+` | required | +| `+maxId+` | `+Number+` | required | +| `+contents+` | xref:#trackednode[TrackedNode] `+Object+` `+Array+` | required | +|=== + +=== TrackedNode + +`TrackedNode` is an `+Object+` that contains the following fields: + +[cols="1,1,1,3",options="header"] +|=== +| Field | Type | Required? | Description +| `+type+` | `+String+` | required | +| `+attrs+` | `` | optional | +| `+oldAttrs+` | `` | optional | +| `+text+` | `+String+` | required | +| `+_opData+` | xref:#trackedData[TrackedData] `+Object+` `+Array+` | optional | +| `+format+` | xref:#textformat[TextFormat] `+Object+` | optional | +| `+oldFormat+` | xref:#textformat[TextFormat] `+Object+` | optional | +| `+children+` | xref:#trackednode[TrackedNode] `+Object+` `+Array+` | optional | +|=== + +=== TrackedData + +=== TextFormat + == Options The following configuration options affect the behavior of the {pluginname} plugin. -include::partial$configuration/trackchanges-options.adoc[] +include::partial$configuration/trackchanges-options.adoc[leveloffset=+1] include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] @@ -66,6 +99,6 @@ include::partial$events/{plugincode}-events.adoc[] == APIs -The {pluginname} plugin provide the following APIs. +The {pluginname} plugin provides the following APIs. include::partial$plugin-apis/{plugincode}-apis.adoc[] \ No newline at end of file diff --git a/modules/ROOT/partials/commands/trackchanges-cmds.adoc b/modules/ROOT/partials/commands/trackchanges-cmds.adoc index 9d61f6860b..9dcee19963 100644 --- a/modules/ROOT/partials/commands/trackchanges-cmds.adoc +++ b/modules/ROOT/partials/commands/trackchanges-cmds.adoc @@ -2,32 +2,11 @@ |=== |Command |Description -| | -// Boilerplate for commands that require further documentation -| |Description two. For details, see xref:using-[Using `++`]. +|trackchanges |Toggle the Track Changes view |=== .Examples [source,js] ---- -tinymce.activeEditor.execCommand(''); -tinymce.activeEditor.execCommand('', , { : '', : '' }); +tinymce.activeEditor.execCommand('trackchanges'); ---- - -// 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/modules/ROOT/partials/configuration/trackchanges-options.adoc b/modules/ROOT/partials/configuration/trackchanges-options.adoc index 391b450c3b..496ec1f158 100644 --- a/modules/ROOT/partials/configuration/trackchanges-options.adoc +++ b/modules/ROOT/partials/configuration/trackchanges-options.adoc @@ -1,5 +1,5 @@ -[[]] -== `` +[[trackchanges_model]] +== `trackchanges_model` //// What does the option do? @@ -13,12 +13,282 @@ Are there risks? - For longer or more complicated scenarios, use the limitations section below. //// -*Type:* `+String+`, `+Boolean+`, `+Number+`, `+Function+`, `+Object+`, `+Array+`, or `+Regexp+` +*Type:* xref:#trackeddocument[TrackedDocument] `+Object+` -// Remove the *Possible values* line if there is no discrete set of possible values. -*Possible values:* `'string1'`, `'string2'`, `false` +=== Example: using `trackchanges_model` -*Default value:* `false`, `1`, `'string1'` +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : '' +}); +---- + +// Add a working and tested configuration (edit as required) +// or remove if not applicable. +=== Example: disabling the + +To disable , set `` to `false`. + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : 'false' +}); +---- + +// Remove if not applicable. +=== Limitation of the `` option + +The `` option has the following limitations. + +//// +Known limitations. +Complicated scenarios. +Anything that warrants a CAUTION or WARNING admonition. +//// + +[[trackchanges_uid]] +== `trackchanges_uid` + +*Type:* `+String+` + + +//// +What does the option do? +Why use it? +When use it? +What values can it use? +What do these values do? +Are there risks? + - Explain without using ‘risk’ or similar words. + - Use NOTE or IMPORTANT admonitions if helpful. + - For longer or more complicated scenarios, use the limitations section below. +//// + +=== Example: using `` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : '' +}); +---- + +// Add a working and tested configuration (edit as required) +// or remove if not applicable. +=== Example: disabling the + +To disable , set `` to `false`. + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : 'false' +}); +---- + +// Remove if not applicable. +=== Limitation of the `` option + +The `` option has the following limitations. + +//// +Known limitations. +Complicated scenarios. +Anything that warrants a CAUTION or WARNING admonition. +//// + +[[trackchanges_role]] +== `trackchanges_role` + +*Type:* `+String+` + +*Possible values:* `'admin'`, `'reviewer'`, `'contributor'`, `'viewer'`, `'none'`, + +*Default value:* `'admin'` + + +//// +What does the option do? +Why use it? +When use it? +What values can it use? +What do these values do? +Are there risks? + - Explain without using ‘risk’ or similar words. + - Use NOTE or IMPORTANT admonitions if helpful. + - For longer or more complicated scenarios, use the limitations section below. +//// + +=== Example: using `` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : '' +}); +---- + +// Add a working and tested configuration (edit as required) +// or remove if not applicable. +=== Example: disabling the + +To disable , set `` to `false`. + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : 'false' +}); +---- + +// Remove if not applicable. +=== Limitation of the `` option + +The `` option has the following limitations. + +//// +Known limitations. +Complicated scenarios. +Anything that warrants a CAUTION or WARNING admonition. +//// + +[[trackchanges_user_lookup]] +== `trackchanges_user_lookup` + +*Type:* `+Function+` + + +//// +What does the option do? +Why use it? +When use it? +What values can it use? +What do these values do? +Are there risks? + - Explain without using ‘risk’ or similar words. + - Use NOTE or IMPORTANT admonitions if helpful. + - For longer or more complicated scenarios, use the limitations section below. +//// + +=== Example: using `` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : '' +}); +---- + +// Add a working and tested configuration (edit as required) +// or remove if not applicable. +=== Example: disabling the + +To disable , set `` to `false`. + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : 'false' +}); +---- + +// Remove if not applicable. +=== Limitation of the `` option + +The `` option has the following limitations. + +//// +Known limitations. +Complicated scenarios. +Anything that warrants a CAUTION or WARNING admonition. +//// + +[[trackchanges_css_url]] +== `trackchanges_css_url` + +*Type:* `+String+` + +*Default value:* `'${pluginUrl}/css/trackchanges.css'` + + +//// +What does the option do? +Why use it? +When use it? +What values can it use? +What do these values do? +Are there risks? + - Explain without using ‘risk’ or similar words. + - Use NOTE or IMPORTANT admonitions if helpful. + - For longer or more complicated scenarios, use the limitations section below. +//// + +=== Example: using `` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : '' +}); +---- + +// Add a working and tested configuration (edit as required) +// or remove if not applicable. +=== Example: disabling the + +To disable , set `` to `false`. + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + : 'false' +}); +---- + +// Remove if not applicable. +=== Limitation of the `` option + +The `` option has the following limitations. + +//// +Known limitations. +Complicated scenarios. +Anything that warrants a CAUTION or WARNING admonition. +//// + +[[trackchanges_diff_classes]] +== `trackchanges_diff_classes` + +*Type:* `+Object+` + +//// +What does the option do? +Why use it? +When use it? +What values can it use? +What do these values do? +Are there risks? + - Explain without using ‘risk’ or similar words. + - Use NOTE or IMPORTANT admonitions if helpful. + - For longer or more complicated scenarios, use the limitations section below. +//// === Example: using `` diff --git a/modules/ROOT/partials/events/trackchanges-events.adoc b/modules/ROOT/partials/events/trackchanges-events.adoc index 79e6124bd0..a3fedfbff0 100644 --- a/modules/ROOT/partials/events/trackchanges-events.adoc +++ b/modules/ROOT/partials/events/trackchanges-events.adoc @@ -3,15 +3,11 @@ The following events are provided by the xref:{plugincode}.adoc[{pluginname} plu [cols="1,1,2",options="header"] |=== |Name |Data |Description -|EventOne |`+{ : }+` |Fired when event one description. -|EventTwo |`+{ : , : }+` |Fired when event two description. -|EventThree |N/A |Fired when event three description. +|TrackChangesBeginReview |N/A |Fired when the Track Changes view opens. +|TrackChangesReviewComplete |N/A |Fired when a review in the Track Changes view is completed. +|TrackChangesReviewCancelled |N/A |Fired when a review in the Track Changes view is cancelled. // 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[] -|EventFour |`+{ : }+` |Fired when the event seven description. -|EventEn |`+{ : , : }+` |Fired when event en description. |=== \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc b/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc index da3b8a1a17..b2952a18a9 100644 --- a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc +++ b/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc @@ -2,22 +2,20 @@ |=== |Name |Arguments |Description -| | | -// 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[] -| | | +|getModel |N/A |Return a xref:#trackeddocument[TrackedDocument] `+Object+` of the document. +|resetModel |N/A |Reset the document to its original state. +|hasChanges |N/A |Return a boolean value indicating whether the document contains changes to be reviewed. |=== .Examples [source,js] ---- -// what this example does -tinymce.activeEditor.plugins..(); +// Get the current model of the document +tinymce.activeEditor.plugins.trackchanges.getModel(); -// what this example does -tinymce.activeEditor.plugins..(); +// Reset the document model to its original state +tinymce.activeEditor.plugins.trackchanges.resetModel(); + +// Check if document contains changes to be reviewed +tinymce.activeEditor.plugins.trackchanges.hasChanges(); ---- From ce4c43a61d8d99b2b19112d40d8d086e88298b12 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Mon, 24 Mar 2025 17:41:21 +1000 Subject: [PATCH 16/68] Add description of plugin and examples for API options --- modules/ROOT/pages/trackchanges.adoc | 80 +++-- .../configuration/trackchanges-options.adoc | 311 +++--------------- .../plugin-apis/trackchanges-apis.adoc | 20 +- 3 files changed, 109 insertions(+), 302 deletions(-) diff --git a/modules/ROOT/pages/trackchanges.adoc b/modules/ROOT/pages/trackchanges.adoc index 758c637e97..e50758aa0e 100644 --- a/modules/ROOT/pages/trackchanges.adoc +++ b/modules/ROOT/pages/trackchanges.adoc @@ -21,12 +21,43 @@ include::partial$misc/admon-iframe-only.adoc[] == How it works +The Track Changes plugin monitors edits made to a document by comparing its current state to the original version. Each change is attributed to its respective author and can be approved or rejected before being applied to the document. + +[NOTE] +Since the comparison is made against the original version of the document, if there are unresolved changes by multiple authors affecting the same part, the most recent change will be used for comparison. The `hasChanges` API can be used to implement a safeguard that prevents further edits on a document with unresolved changes. + +The plugin includes a dedicated view for reviewing current changes, accessible via the `{plugincode} toolbar button or the menu option under the `View` menu. The key components are: + +. **Read-only Diff View**: ++ +Highlights the current changes made to the document, using the following color codes: ++ +* Green: New content. +* Blue: Modified content. Modifications to HTML content implies attributes or formatting (e.g. bold, italic, etc.). +* Red: Removed content. + +. **Sidebar**: ++ +Contains a header with the following buttons: ++ +* Show Changes: A toggle button which hides/unhides the change annotations. +* Complete: Ends the review applies the resolved changes. +* Cancel: Ends the review without any further action. + ++ +The sidebar also displays all tracked changes that need to be resolved. Each change can be handled in the following ways: +* Accept: Applies the change to the document. +* Reject: Removes the change from the document. +* Revert: Undoes a previously accepted or rejected change. + == Basic setup 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; +* add `{plugincode}_model` to the editor configuration. +* add `{plugincode}_uid` to the editor configuration. For example: @@ -36,45 +67,22 @@ tinymce.init({ selector: 'textarea', // change this value according to your HTML plugins: 'trackchanges', toolbar: 'trackchanges', - // track changes options + trackchanges_model: { + version: 1, + maxId: 0, + contents: [ + { + type: 'p', + children: [ + { text: 'Hello, World!' } + ] + } + ] + } + trackchanges_uid: 'unique-identifier' // replace this with a unique string to identify the user }); ---- -== Data structure - -=== TrackedDocument - -`TrackedDocument` is an `+Object+` that contains the following fields: - -[cols="1,1,1,3",options="header"] -|=== -| Field | Type | Required? | Description -| `+version+` | `+Number+` | required | -| `+maxId+` | `+Number+` | required | -| `+contents+` | xref:#trackednode[TrackedNode] `+Object+` `+Array+` | required | -|=== - -=== TrackedNode - -`TrackedNode` is an `+Object+` that contains the following fields: - -[cols="1,1,1,3",options="header"] -|=== -| Field | Type | Required? | Description -| `+type+` | `+String+` | required | -| `+attrs+` | `` | optional | -| `+oldAttrs+` | `` | optional | -| `+text+` | `+String+` | required | -| `+_opData+` | xref:#trackedData[TrackedData] `+Object+` `+Array+` | optional | -| `+format+` | xref:#textformat[TextFormat] `+Object+` | optional | -| `+oldFormat+` | xref:#textformat[TextFormat] `+Object+` | optional | -| `+children+` | xref:#trackednode[TrackedNode] `+Object+` `+Array+` | optional | -|=== - -=== TrackedData - -=== TextFormat - == Options The following configuration options affect the behavior of the {pluginname} plugin. diff --git a/modules/ROOT/partials/configuration/trackchanges-options.adoc b/modules/ROOT/partials/configuration/trackchanges-options.adoc index 496ec1f158..1af4b9d22b 100644 --- a/modules/ROOT/partials/configuration/trackchanges-options.adoc +++ b/modules/ROOT/partials/configuration/trackchanges-options.adoc @@ -1,19 +1,9 @@ [[trackchanges_model]] == `trackchanges_model` -//// -What does the option do? -Why use it? -When use it? -What values can it use? -What do these values do? -Are there risks? - - Explain without using ‘risk’ or similar words. - - Use NOTE or IMPORTANT admonitions if helpful. - - For longer or more complicated scenarios, use the limitations section below. -//// +The `trackchanges_model` option sets the initial model of the document to be begin tracking changes. It takes as input an object representing the document. If no value is set, the plugin will generate the model by default. -*Type:* xref:#trackeddocument[TrackedDocument] `+Object+` +//*Type:* xref:#trackeddocument[TrackedDocument] `+Object+` === Example: using `trackchanges_model` @@ -22,306 +12,99 @@ Are there risks? ---- tinymce.init({ selector: 'textarea', // Change this value according to your HTML - : '' + plugins: 'trackchanges', + toolbar: 'trackchanges', + trackchanges_model: { + version: 1, + maxId: 0, + contents: [ + { + type: 'p', + children: [ + { text: 'Hello, World!' } + ] + } + ] + } }); ---- -// Add a working and tested configuration (edit as required) -// or remove if not applicable. -=== Example: disabling the - -To disable , set `` to `false`. - -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : 'false' -}); ----- - -// Remove if not applicable. -=== Limitation of the `` option - -The `` option has the following limitations. - -//// -Known limitations. -Complicated scenarios. -Anything that warrants a CAUTION or WARNING admonition. -//// - [[trackchanges_uid]] == `trackchanges_uid` -*Type:* `+String+` - - -//// -What does the option do? -Why use it? -When use it? -What values can it use? -What do these values do? -Are there risks? - - Explain without using ‘risk’ or similar words. - - Use NOTE or IMPORTANT admonitions if helpful. - - For longer or more complicated scenarios, use the limitations section below. -//// - -=== Example: using `` - -// Add a working and tested configuration. -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : '' -}); ----- - -// Add a working and tested configuration (edit as required) -// or remove if not applicable. -=== Example: disabling the - -To disable , set `` to `false`. - -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : 'false' -}); ----- - -// Remove if not applicable. -=== Limitation of the `` option - -The `` option has the following limitations. - -//// -Known limitations. -Complicated scenarios. -Anything that warrants a CAUTION or WARNING admonition. -//// - -[[trackchanges_role]] -== `trackchanges_role` +The `trackchanges_uid` is a _required_ option that takes as input a unique string to identify the current user. This is used to attribute changes made by the user. *Type:* `+String+` -*Possible values:* `'admin'`, `'reviewer'`, `'contributor'`, `'viewer'`, `'none'`, - -*Default value:* `'admin'` - - -//// -What does the option do? -Why use it? -When use it? -What values can it use? -What do these values do? -Are there risks? - - Explain without using ‘risk’ or similar words. - - Use NOTE or IMPORTANT admonitions if helpful. - - For longer or more complicated scenarios, use the limitations section below. -//// - -=== Example: using `` - -// Add a working and tested configuration. -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : '' -}); ----- - -// Add a working and tested configuration (edit as required) -// or remove if not applicable. -=== Example: disabling the - -To disable , set `` to `false`. - -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : 'false' -}); ----- - -// Remove if not applicable. -=== Limitation of the `` option - -The `` option has the following limitations. - -//// -Known limitations. -Complicated scenarios. -Anything that warrants a CAUTION or WARNING admonition. -//// - -[[trackchanges_user_lookup]] -== `trackchanges_user_lookup` - -*Type:* `+Function+` - - -//// -What does the option do? -Why use it? -When use it? -What values can it use? -What do these values do? -Are there risks? - - Explain without using ‘risk’ or similar words. - - Use NOTE or IMPORTANT admonitions if helpful. - - For longer or more complicated scenarios, use the limitations section below. -//// - -=== Example: using `` +=== Example: using `trackchanges_uid` // Add a working and tested configuration. [source,js] ---- tinymce.init({ selector: 'textarea', // Change this value according to your HTML - : '' + plugins: 'trackchanges', + toolbar: 'trackchanges', + trackchanges_uid: 'unique-identifier' // replace this with a unique string to identify the user }); ---- -// Add a working and tested configuration (edit as required) -// or remove if not applicable. -=== Example: disabling the - -To disable , set `` to `false`. - -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : 'false' -}); ----- - -// Remove if not applicable. -=== Limitation of the `` option - -The `` option has the following limitations. - -//// -Known limitations. -Complicated scenarios. -Anything that warrants a CAUTION or WARNING admonition. -//// - [[trackchanges_css_url]] == `trackchanges_css_url` +The `trackchanges_css_url` option sets the location where a CSS file containing change annotations in the {pluginname} view should be loaded from. To override the default CSS classes, use this option alongside `trackchanges_diff_classes`. + *Type:* `+String+` *Default value:* `'${pluginUrl}/css/trackchanges.css'` - -//// -What does the option do? -Why use it? -When use it? -What values can it use? -What do these values do? -Are there risks? - - Explain without using ‘risk’ or similar words. - - Use NOTE or IMPORTANT admonitions if helpful. - - For longer or more complicated scenarios, use the limitations section below. -//// - -=== Example: using `` +=== Example: using `trackchanges_css_url` // Add a working and tested configuration. [source,js] ---- tinymce.init({ selector: 'textarea', // Change this value according to your HTML - : '' + trackchanges_css_url: './trackchanges.css' }); ---- -// Add a working and tested configuration (edit as required) -// or remove if not applicable. -=== Example: disabling the - -To disable , set `` to `false`. - -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : 'false' -}); ----- - -// Remove if not applicable. -=== Limitation of the `` option - -The `` option has the following limitations. - -//// -Known limitations. -Complicated scenarios. -Anything that warrants a CAUTION or WARNING admonition. -//// - [[trackchanges_diff_classes]] == `trackchanges_diff_classes` +The `trackchanges_diff_classes` option configures the CSS classes applied to the change annotations in the {pluginname} view. This is useful to set custom styles and must be used in combination with the `trackchanges_css_url` option. + +[NOTE] +The CSS class names must exist in the xref:trackchanges_css_url[`+trackchanges_css_url+`]. + *Type:* `+Object+` -//// -What does the option do? -Why use it? -When use it? -What values can it use? -What do these values do? -Are there risks? - - Explain without using ‘risk’ or similar words. - - Use NOTE or IMPORTANT admonitions if helpful. - - For longer or more complicated scenarios, use the limitations section below. -//// +*Default value:* `addition`, `removal`, `modification` -=== Example: using `` +Below are the default CSS classes: -// Add a working and tested configuration. [source,js] ---- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : '' -}); +{ + addition: 'tox-trackchanges__annotation--added', + removal: 'tox-trackchanges__annotation--removed', + modification: 'tox-trackchanges__annotation--modified' +} ---- -// Add a working and tested configuration (edit as required) -// or remove if not applicable. -=== Example: disabling the - -To disable , set `` to `false`. +=== Example: using `trackchanges_diff_classes` [source,js] ---- tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - : 'false' + selector: 'textarea', // change this value according to your HTML + plugins: 'trackchanges', + toolbar: 'trackchanges', + trackchanges_css_url: './trackchanges.css', + trackchanges_diff_classes: { + addition: 'added', + removal: 'removed', + modification: 'modified' + } }); ---- - -// Remove if not applicable. -=== Limitation of the `` option - -The `` option has the following limitations. - -//// -Known limitations. -Complicated scenarios. -Anything that warrants a CAUTION or WARNING admonition. -//// \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc b/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc index b2952a18a9..2ac0f57efe 100644 --- a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc +++ b/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc @@ -2,8 +2,9 @@ |=== |Name |Arguments |Description -|getModel |N/A |Return a xref:#trackeddocument[TrackedDocument] `+Object+` of the document. -|resetModel |N/A |Reset the document to its original state. +|getModel |N/A |Return an object representing the document model used to store tracked changes data. +//|setModel |xref:#trackeddocument[TrackedDocument] `+Object+` | Set the current model of the document. +//|resetModel |N/A |Reset the document to its original state. |hasChanges |N/A |Return a boolean value indicating whether the document contains changes to be reviewed. |=== @@ -13,9 +14,24 @@ // Get the current model of the document tinymce.activeEditor.plugins.trackchanges.getModel(); +// Check if document contains changes to be reviewed +tinymce.activeEditor.plugins.trackchanges.hasChanges(); +---- + +//// +.Examples +[source,js] +---- +// Get the current model of the document +tinymce.activeEditor.plugins.trackchanges.getModel(); + +// Set current model of the document +tinymce.activeEditor.plugins.trackchanges.setModel(model); + // Reset the document model to its original state tinymce.activeEditor.plugins.trackchanges.resetModel(); // Check if document contains changes to be reviewed tinymce.activeEditor.plugins.trackchanges.hasChanges(); ---- +//// \ No newline at end of file From f9b3cf073508c9e2d4d6ad4e6f0adaf5506b4018 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Tue, 25 Mar 2025 10:58:38 +1000 Subject: [PATCH 17/68] Comment out note about stacked changes and minor copy edits --- modules/ROOT/pages/trackchanges.adoc | 17 +++++++++++------ .../partials/plugin-apis/trackchanges-apis.adoc | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/modules/ROOT/pages/trackchanges.adoc b/modules/ROOT/pages/trackchanges.adoc index e50758aa0e..9019d6423a 100644 --- a/modules/ROOT/pages/trackchanges.adoc +++ b/modules/ROOT/pages/trackchanges.adoc @@ -23,10 +23,7 @@ include::partial$misc/admon-iframe-only.adoc[] The Track Changes plugin monitors edits made to a document by comparing its current state to the original version. Each change is attributed to its respective author and can be approved or rejected before being applied to the document. -[NOTE] -Since the comparison is made against the original version of the document, if there are unresolved changes by multiple authors affecting the same part, the most recent change will be used for comparison. The `hasChanges` API can be used to implement a safeguard that prevents further edits on a document with unresolved changes. - -The plugin includes a dedicated view for reviewing current changes, accessible via the `{plugincode} toolbar button or the menu option under the `View` menu. The key components are: +The plugin includes a dedicated view for reviewing current changes, accessible via the `{plugincode}` toolbar button or the menu option under the `View` menu. The key components are: . **Read-only Diff View**: + @@ -41,7 +38,7 @@ Highlights the current changes made to the document, using the following color c Contains a header with the following buttons: + * Show Changes: A toggle button which hides/unhides the change annotations. -* Complete: Ends the review applies the resolved changes. +* Complete: Ends the review and applies the resolved changes. * Cancel: Ends the review without any further action. + @@ -109,4 +106,12 @@ include::partial$events/{plugincode}-events.adoc[] The {pluginname} plugin provides the following APIs. -include::partial$plugin-apis/{plugincode}-apis.adoc[] \ No newline at end of file +include::partial$plugin-apis/{plugincode}-apis.adoc[] + +//// +== Known Limitations + +[NOTE] +Since the comparison is made against the original version of the document, if there are unresolved changes by multiple authors affecting the same part, the most recent change will be used for comparison. The `hasChanges` API can be used to implement a safeguard that prevents further edits on a document with unresolved changes. + +//// \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc b/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc index 2ac0f57efe..339ad43f50 100644 --- a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc +++ b/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc @@ -2,7 +2,7 @@ |=== |Name |Arguments |Description -|getModel |N/A |Return an object representing the document model used to store tracked changes data. +|getModel |N/A |Return an object representing the document model used to store data of the tracked changes. //|setModel |xref:#trackeddocument[TrackedDocument] `+Object+` | Set the current model of the document. //|resetModel |N/A |Reset the document to its original state. |hasChanges |N/A |Return a boolean value indicating whether the document contains changes to be reviewed. From dfba8fc3fa9ce4d522ca627b7188c74422f0276b Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Mon, 31 Mar 2025 16:04:20 +1000 Subject: [PATCH 18/68] add live demo --- antora.yml | 2 +- .../live-demos/trackchanges/example.js | 37 ++++----------- .../live-demos/trackchanges/index.html | 33 ++++++++++++- .../examples/live-demos/trackchanges/index.js | 47 ++++++++++++++----- modules/ROOT/pages/trackchanges.adoc | 2 +- 5 files changed, 75 insertions(+), 46 deletions(-) diff --git a/antora.yml b/antora.yml index 19391046b8..b7016d5189 100644 --- a/antora.yml +++ b/antora.yml @@ -10,7 +10,7 @@ asciidoc: 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 + tinymce_live_demo_url: https://internal-preview.tiny.work/epic/EPIC-134/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/dist/tinymce-webcomponent.min.js jquery_url: https://cdn.jsdelivr.net/npm/@tinymce/tinymce-jquery@2/dist/tinymce-jquery.min.js diff --git a/modules/ROOT/examples/live-demos/trackchanges/example.js b/modules/ROOT/examples/live-demos/trackchanges/example.js index 6b8e2b18e0..814574e2a6 100644 --- a/modules/ROOT/examples/live-demos/trackchanges/example.js +++ b/modules/ROOT/examples/live-demos/trackchanges/example.js @@ -1,30 +1,9 @@ -/* -This file is not normally required. - -Sometimes, however, a plugin, or a particular feature of a plugin, -requires a back-end service. - -In these cases, creating a working demo requires setting up an -emulated version of this service. - -And `example.js` is part of this emulation. - -`index.js` still runs the live demo. - -But `example.js` is what is displayed in the *js* tab of the -live-demo interface on the built docs site. - -So `example.js` has to be a working equivalent to `index.js` *if* -`index.js` was wired up in a standard way, to its required back-end -service. - -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 ‘includes-an-emulated-back-end’ examples -will almost certainly include significant initial input from the -plugin’s developer. - -*/ +tinymce.init({ + selector: 'textarea#trackchanges', + height: 500, + plugins: 'trackchanges', + toolbar: 'trackchanges', + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', + trackchanges_uid: 'adamhenderson', + }); \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/trackchanges/index.html b/modules/ROOT/examples/live-demos/trackchanges/index.html index ebe4fa70ca..d2dabf9f53 100644 --- a/modules/ROOT/examples/live-demos/trackchanges/index.html +++ b/modules/ROOT/examples/live-demos/trackchanges/index.html @@ -1,8 +1,12 @@ - diff --git a/modules/ROOT/examples/live-demos/trackchanges/index.js b/modules/ROOT/examples/live-demos/trackchanges/index.js index 045103dc9d..4d888ade46 100644 --- a/modules/ROOT/examples/live-demos/trackchanges/index.js +++ b/modules/ROOT/examples/live-demos/trackchanges/index.js @@ -1,16 +1,37 @@ +/** Fake user database */ +const userinfos = { + adamhenderson: { + uid: 'adamhenderson', + name: 'Adam Henderson', + avatar: `https://randomuser.me/api/portraits/men/1.jpg`, + }, + michaelcook: { + uid: 'michaelcook', + name: 'Michael Cook', + avatar: `https://randomuser.me/api/portraits/men/2.jpg`, + }, + kalebwilson: { + uid: 'kalebwilson', + name: 'Kaleb Wilson', + avatar: `https://randomuser.me/api/portraits/men/3.jpg`, + }, + kyleeinstein: { + uid: 'kyleeinstein', + name: 'Kyle Einstein', + avatar: `https://randomuser.me/api/portraits/men/4.jpg`, + }, +}; + +const trackchanges_user_lookup = (uid) => new Promise((resolve, reject) => + setTimeout(() => userinfos[uid] ? resolve(userinfos[uid]) : reject(), 1000)); + + tinymce.init({ - selector: 'textarea#', -// below is a basic 6.x working configuration. -// Do not assume it is suitable for demonstrating the plugin to be documented. + selector: 'textarea#trackchanges', height: 500, - plugins: [ - 'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'preview', - 'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen', - 'insertdatetime', 'media', 'table', 'help', 'wordcount' - ], - toolbar: 'undo redo | blocks | ' + - 'bold italic backcolor | alignleft aligncenter ' + - 'alignright alignjustify | bullist numlist outdent indent | ' + - 'removeformat | help', - content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }' + plugins: 'trackchanges', + toolbar: 'trackchanges', + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', + trackchanges_uid: 'adamhenderson', + trackchanges_user_lookup, }); diff --git a/modules/ROOT/pages/trackchanges.adoc b/modules/ROOT/pages/trackchanges.adoc index 9019d6423a..d18ce7e0b0 100644 --- a/modules/ROOT/pages/trackchanges.adoc +++ b/modules/ROOT/pages/trackchanges.adoc @@ -75,7 +75,7 @@ tinymce.init({ ] } ] - } + }, trackchanges_uid: 'unique-identifier' // replace this with a unique string to identify the user }); ---- From 21c486675f337d2f7dd54e54457b6acbf5831e66 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Mon, 31 Mar 2025 16:42:11 +1000 Subject: [PATCH 19/68] rename plugin to Suggested Edits --- modules/ROOT/nav.adoc | 2 +- .../pages/{trackchanges.adoc => suggestededits.adoc} | 12 ++++++------ .../ROOT/partials/index-pages/premium-plugins.adoc | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) rename modules/ROOT/pages/{trackchanges.adoc => suggestededits.adoc} (87%) diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc index 274f9be34e..c06ce2be4c 100644 --- a/modules/ROOT/nav.adoc +++ b/modules/ROOT/nav.adoc @@ -371,7 +371,7 @@ ***** xref:tinydrive-pick.adoc[The Pick API] ***** xref:tinydrive-type-interfaces.adoc[TypeScript interfaces] **** xref:tinydrive-changelog.adoc[Changelog] -*** xref:trackchanges.adoc[Track Changes] +*** xref:suggestededits.adoc[Suggested Edits] ** Open source plugins *** xref:accordion.adoc[Accordion] *** xref:anchor.adoc[Anchor] diff --git a/modules/ROOT/pages/trackchanges.adoc b/modules/ROOT/pages/suggestededits.adoc similarity index 87% rename from modules/ROOT/pages/trackchanges.adoc rename to modules/ROOT/pages/suggestededits.adoc index d18ce7e0b0..34534d0b4d 100644 --- a/modules/ROOT/pages/trackchanges.adoc +++ b/modules/ROOT/pages/suggestededits.adoc @@ -1,9 +1,9 @@ -= Track Changes Plugin -:navtitle: Track Changes += Suggested Edits Plugin +:navtitle: Suggested Edits :description: A view that allows users to review document changes made by multiple authors :description_short: A view of tracked changes made by multiple authors -:keywords: plugin, Track Changes, changes, diff -:pluginname: Track Changes +:keywords: plugin, Suggested Edits, changes, diff +:pluginname: Suggested Edits :plugincode: trackchanges :plugincategory: premium @@ -11,7 +11,7 @@ include::partial$misc/admon-revisionhistory-paid-addon-pricing.adoc[] include::partial$misc/admon-requires-8.0v.adoc[] -The Track Changes plugin allows users to easily review and manage changes made to a document by multiple authors. +The Suggested Edits plugin allows users to easily review and manage changes made to a document by multiple authors. == Interactive example @@ -21,7 +21,7 @@ include::partial$misc/admon-iframe-only.adoc[] == How it works -The Track Changes plugin monitors edits made to a document by comparing its current state to the original version. Each change is attributed to its respective author and can be approved or rejected before being applied to the document. +The Suggested Edits plugin monitors edits made to a document by comparing its current state to the original version. Each change is attributed to its respective author and can be approved or rejected before being applied to the document. The plugin includes a dedicated view for reviewing current changes, accessible via the `{plugincode}` toolbar button or the menu option under the `View` menu. The key components are: diff --git a/modules/ROOT/partials/index-pages/premium-plugins.adoc b/modules/ROOT/partials/index-pages/premium-plugins.adoc index f2770bfe03..3e9cc5fff2 100644 --- a/modules/ROOT/partials/index-pages/premium-plugins.adoc +++ b/modules/ROOT/partials/index-pages/premium-plugins.adoc @@ -204,7 +204,7 @@ Cloud-based file and image management for {productname}. a| [.lead] -xref:trackchanges.adoc[Track Changes] +xref:suggestededits.adoc[Suggested Edits] Review document changes by multiple users. From 26fd1bff4d04774716f989041010a5a53c1ca1bf Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Tue, 1 Apr 2025 15:17:32 +1000 Subject: [PATCH 20/68] replace all instanes of plugin name and code --- .../example.js | 0 .../index.html | 24 ++-- .../{trackchanges => suggestededits}/index.js | 0 modules/ROOT/nav.adoc | 2 +- modules/ROOT/pages/suggestededits.adoc | 12 +- ...ges-cmds.adoc => suggestededits-cmds.adoc} | 4 +- .../configuration/defaultmenuitems.adoc | 2 +- .../configuration/suggestededits-options.adoc | 110 ++++++++++++++++++ .../configuration/trackchanges-options.adoc | 110 ------------------ ...events.adoc => suggestededits-events.adoc} | 6 +- ...ms.adoc => suggestededits-menu-items.adoc} | 2 +- ...ges-apis.adoc => suggestededits-apis.adoc} | 12 +- ...oc => suggestededits-toolbar-buttons.adoc} | 2 +- 13 files changed, 143 insertions(+), 143 deletions(-) rename modules/ROOT/examples/live-demos/{trackchanges => suggestededits}/example.js (100%) rename modules/ROOT/examples/live-demos/{trackchanges => suggestededits}/index.html (84%) rename modules/ROOT/examples/live-demos/{trackchanges => suggestededits}/index.js (100%) rename modules/ROOT/partials/commands/{trackchanges-cmds.adoc => suggestededits-cmds.adoc} (50%) create mode 100644 modules/ROOT/partials/configuration/suggestededits-options.adoc delete mode 100644 modules/ROOT/partials/configuration/trackchanges-options.adoc rename modules/ROOT/partials/events/{trackchanges-events.adoc => suggestededits-events.adoc} (57%) rename modules/ROOT/partials/menu-item-ids/{trackchanges-menu-items.adoc => suggestededits-menu-items.adoc} (75%) rename modules/ROOT/partials/plugin-apis/{trackchanges-apis.adoc => suggestededits-apis.adoc} (70%) rename modules/ROOT/partials/toolbar-button-ids/{trackchanges-toolbar-buttons.adoc => suggestededits-toolbar-buttons.adoc} (59%) diff --git a/modules/ROOT/examples/live-demos/trackchanges/example.js b/modules/ROOT/examples/live-demos/suggestededits/example.js similarity index 100% rename from modules/ROOT/examples/live-demos/trackchanges/example.js rename to modules/ROOT/examples/live-demos/suggestededits/example.js diff --git a/modules/ROOT/examples/live-demos/trackchanges/index.html b/modules/ROOT/examples/live-demos/suggestededits/index.html similarity index 84% rename from modules/ROOT/examples/live-demos/trackchanges/index.html rename to modules/ROOT/examples/live-demos/suggestededits/index.html index d2dabf9f53..7f32961fc0 100644 --- a/modules/ROOT/examples/live-demos/trackchanges/index.html +++ b/modules/ROOT/examples/live-demos/suggestededits/index.html @@ -1,22 +1,12 @@ diff --git a/modules/ROOT/examples/live-demos/trackchanges/index.js b/modules/ROOT/examples/live-demos/suggestededits/index.js similarity index 100% rename from modules/ROOT/examples/live-demos/trackchanges/index.js rename to modules/ROOT/examples/live-demos/suggestededits/index.js diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc index c06ce2be4c..54407f44b0 100644 --- a/modules/ROOT/nav.adoc +++ b/modules/ROOT/nav.adoc @@ -345,6 +345,7 @@ **** xref:introduction-to-tiny-spellchecker.adoc[Spell Checker] **** xref:custom-dictionaries-for-tiny-spellchecker.adoc[Adding custom dictionaries] *** xref:autocorrect.adoc[Spelling Autocorrect] +*** xref:suggestededits.adoc[Suggested Edits] *** xref:tableofcontents.adoc[Table of Contents] *** xref:advanced-templates.adoc[Templates] *** Tiny Drive @@ -371,7 +372,6 @@ ***** xref:tinydrive-pick.adoc[The Pick API] ***** xref:tinydrive-type-interfaces.adoc[TypeScript interfaces] **** xref:tinydrive-changelog.adoc[Changelog] -*** xref:suggestededits.adoc[Suggested Edits] ** Open source plugins *** xref:accordion.adoc[Accordion] *** xref:anchor.adoc[Anchor] diff --git a/modules/ROOT/pages/suggestededits.adoc b/modules/ROOT/pages/suggestededits.adoc index 34534d0b4d..fc5277efd1 100644 --- a/modules/ROOT/pages/suggestededits.adoc +++ b/modules/ROOT/pages/suggestededits.adoc @@ -4,7 +4,7 @@ :description_short: A view of tracked changes made by multiple authors :keywords: plugin, Suggested Edits, changes, diff :pluginname: Suggested Edits -:plugincode: trackchanges +:plugincode: suggestededits :plugincategory: premium include::partial$misc/admon-revisionhistory-paid-addon-pricing.adoc[] @@ -62,9 +62,9 @@ For example: ---- tinymce.init({ selector: 'textarea', // change this value according to your HTML - plugins: 'trackchanges', - toolbar: 'trackchanges', - trackchanges_model: { + plugins: 'suggestededits', + toolbar: 'suggestededits', + suggestededits_model: { version: 1, maxId: 0, contents: [ @@ -76,7 +76,7 @@ tinymce.init({ } ] }, - trackchanges_uid: 'unique-identifier' // replace this with a unique string to identify the user + suggestededits_uid: 'unique-identifier' // replace this with a unique string to identify the user }); ---- @@ -84,7 +84,7 @@ tinymce.init({ The following configuration options affect the behavior of the {pluginname} plugin. -include::partial$configuration/trackchanges-options.adoc[leveloffset=+1] +include::partial$configuration/suggestededits-options.adoc[leveloffset=+1] include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] diff --git a/modules/ROOT/partials/commands/trackchanges-cmds.adoc b/modules/ROOT/partials/commands/suggestededits-cmds.adoc similarity index 50% rename from modules/ROOT/partials/commands/trackchanges-cmds.adoc rename to modules/ROOT/partials/commands/suggestededits-cmds.adoc index 9dcee19963..c7873a96c3 100644 --- a/modules/ROOT/partials/commands/trackchanges-cmds.adoc +++ b/modules/ROOT/partials/commands/suggestededits-cmds.adoc @@ -2,11 +2,11 @@ |=== |Command |Description -|trackchanges |Toggle the Track Changes view +|suggestededits |Toggle the Suggested Edits view |=== .Examples [source,js] ---- -tinymce.activeEditor.execCommand('trackchanges'); +tinymce.activeEditor.execCommand('suggestededits'); ---- diff --git a/modules/ROOT/partials/configuration/defaultmenuitems.adoc b/modules/ROOT/partials/configuration/defaultmenuitems.adoc index e891f9803b..abd816b32a 100644 --- a/modules/ROOT/partials/configuration/defaultmenuitems.adoc +++ b/modules/ROOT/partials/configuration/defaultmenuitems.adoc @@ -5,7 +5,7 @@ tinymce.init({ menu: { 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 trackchanges | visualaid visualchars visualblocks | spellchecker | preview fullscreen | showcomments' }, + view: { title: 'View', items: 'code revisionhistory suggestededits | visualaid visualchars visualblocks | spellchecker | preview fullscreen | showcomments' }, 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' }, diff --git a/modules/ROOT/partials/configuration/suggestededits-options.adoc b/modules/ROOT/partials/configuration/suggestededits-options.adoc new file mode 100644 index 0000000000..96322925a2 --- /dev/null +++ b/modules/ROOT/partials/configuration/suggestededits-options.adoc @@ -0,0 +1,110 @@ +[[suggestededits_model]] +== `suggestededits_model` + +The `suggestededits_model` option sets the initial model of the document to begin tracking changes. It takes as input an object representing the document. If no value is set, the plugin will generate the model by default. + +//*Type:* xref:#trackeddocument[TrackedDocument] `+Object+` + +=== Example: using `suggestededits_model` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + suggestededits_model: { + version: 1, + maxId: 0, + contents: [ + { + type: 'p', + children: [ + { text: 'Hello, World!' } + ] + } + ] + } +}); +---- + +[[suggestededits_uid]] +== `suggestededits_uid` + +The `suggestededits_uid` is a _required_ option that takes as input a unique string to identify the current user. This is used to attribute changes made by the user. + +*Type:* `+String+` + +=== Example: using `suggestededits_uid` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + suggestededits_uid: 'unique-identifier' // replace this with a unique string to identify the user +}); +---- + +[[suggestededits_css_url]] +== `suggestededits_css_url` + +The `suggestededits_css_url` option sets the location where a CSS file containing change annotations in the {pluginname} view should be loaded from. To override the default CSS classes, use this option alongside `suggestededits_diff_classes`. + +*Type:* `+String+` + +*Default value:* `'${pluginUrl}/css/suggestededits.css'` + +=== Example: using `suggestededits_css_url` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + suggestededits_css_url: './suggestededits.css' +}); +---- + +[[suggestededits_diff_classes]] +== `suggestededits_diff_classes` + +The `suggestededits_diff_classes` option configures the CSS classes applied to the change annotations in the {pluginname} view. This is useful to set custom styles and must be used in combination with the `suggestededits_css_url` option. + +[NOTE] +The CSS class names must exist in the xref:suggestededits_css_url[`+suggestededits_css_url+`]. + +*Type:* `+Object+` + +*Default value:* `addition`, `removal`, `modification` + +Below are the default CSS classes: + +[source,js] +---- +{ + addition: 'tox-suggestededits__annotation--added', + removal: 'tox-suggestededits__annotation--removed', + modification: 'tox-suggestededits__annotation--modified' +} +---- + +=== Example: using `suggestededits_diff_classes` + +[source,js] +---- +tinymce.init({ + selector: 'textarea', // change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + suggestededits_css_url: './suggestededits.css', + suggestededits_diff_classes: { + addition: 'added', + removal: 'removed', + modification: 'modified' + } +}); +---- diff --git a/modules/ROOT/partials/configuration/trackchanges-options.adoc b/modules/ROOT/partials/configuration/trackchanges-options.adoc deleted file mode 100644 index 1af4b9d22b..0000000000 --- a/modules/ROOT/partials/configuration/trackchanges-options.adoc +++ /dev/null @@ -1,110 +0,0 @@ -[[trackchanges_model]] -== `trackchanges_model` - -The `trackchanges_model` option sets the initial model of the document to be begin tracking changes. It takes as input an object representing the document. If no value is set, the plugin will generate the model by default. - -//*Type:* xref:#trackeddocument[TrackedDocument] `+Object+` - -=== Example: using `trackchanges_model` - -// Add a working and tested configuration. -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - plugins: 'trackchanges', - toolbar: 'trackchanges', - trackchanges_model: { - version: 1, - maxId: 0, - contents: [ - { - type: 'p', - children: [ - { text: 'Hello, World!' } - ] - } - ] - } -}); ----- - -[[trackchanges_uid]] -== `trackchanges_uid` - -The `trackchanges_uid` is a _required_ option that takes as input a unique string to identify the current user. This is used to attribute changes made by the user. - -*Type:* `+String+` - -=== Example: using `trackchanges_uid` - -// Add a working and tested configuration. -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - plugins: 'trackchanges', - toolbar: 'trackchanges', - trackchanges_uid: 'unique-identifier' // replace this with a unique string to identify the user -}); ----- - -[[trackchanges_css_url]] -== `trackchanges_css_url` - -The `trackchanges_css_url` option sets the location where a CSS file containing change annotations in the {pluginname} view should be loaded from. To override the default CSS classes, use this option alongside `trackchanges_diff_classes`. - -*Type:* `+String+` - -*Default value:* `'${pluginUrl}/css/trackchanges.css'` - -=== Example: using `trackchanges_css_url` - -// Add a working and tested configuration. -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - trackchanges_css_url: './trackchanges.css' -}); ----- - -[[trackchanges_diff_classes]] -== `trackchanges_diff_classes` - -The `trackchanges_diff_classes` option configures the CSS classes applied to the change annotations in the {pluginname} view. This is useful to set custom styles and must be used in combination with the `trackchanges_css_url` option. - -[NOTE] -The CSS class names must exist in the xref:trackchanges_css_url[`+trackchanges_css_url+`]. - -*Type:* `+Object+` - -*Default value:* `addition`, `removal`, `modification` - -Below are the default CSS classes: - -[source,js] ----- -{ - addition: 'tox-trackchanges__annotation--added', - removal: 'tox-trackchanges__annotation--removed', - modification: 'tox-trackchanges__annotation--modified' -} ----- - -=== Example: using `trackchanges_diff_classes` - -[source,js] ----- -tinymce.init({ - selector: 'textarea', // change this value according to your HTML - plugins: 'trackchanges', - toolbar: 'trackchanges', - trackchanges_css_url: './trackchanges.css', - trackchanges_diff_classes: { - addition: 'added', - removal: 'removed', - modification: 'modified' - } -}); ----- diff --git a/modules/ROOT/partials/events/trackchanges-events.adoc b/modules/ROOT/partials/events/suggestededits-events.adoc similarity index 57% rename from modules/ROOT/partials/events/trackchanges-events.adoc rename to modules/ROOT/partials/events/suggestededits-events.adoc index a3fedfbff0..9b411215a0 100644 --- a/modules/ROOT/partials/events/trackchanges-events.adoc +++ b/modules/ROOT/partials/events/suggestededits-events.adoc @@ -3,9 +3,9 @@ The following events are provided by the xref:{plugincode}.adoc[{pluginname} plu [cols="1,1,2",options="header"] |=== |Name |Data |Description -|TrackChangesBeginReview |N/A |Fired when the Track Changes view opens. -|TrackChangesReviewComplete |N/A |Fired when a review in the Track Changes view is completed. -|TrackChangesReviewCancelled |N/A |Fired when a review in the Track Changes view is cancelled. +|suggestededitsBeginReview |N/A |Fired when the Suggested Edits view opens. +|suggestededitsReviewComplete |N/A |Fired when a review in the Suggested Edits view is completed. +|suggestededitsReviewCancelled |N/A |Fired when a review in the Suggested Edits view is cancelled. // 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. diff --git a/modules/ROOT/partials/menu-item-ids/trackchanges-menu-items.adoc b/modules/ROOT/partials/menu-item-ids/suggestededits-menu-items.adoc similarity index 75% rename from modules/ROOT/partials/menu-item-ids/trackchanges-menu-items.adoc rename to modules/ROOT/partials/menu-item-ids/suggestededits-menu-items.adoc index edde0cbb96..d45e2420b5 100644 --- a/modules/ROOT/partials/menu-item-ids/trackchanges-menu-items.adoc +++ b/modules/ROOT/partials/menu-item-ids/suggestededits-menu-items.adoc @@ -2,5 +2,5 @@ |=== |Menu item identifier |xref:menus-configuration-options.adoc#example-the-tinymce-default-menu-items[Default Menu Location] |Description -|`trackchanges` |View |Opens the Track Changes view. +|`suggestededits` |View |Opens the Suggested Edits view. |=== \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc b/modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc similarity index 70% rename from modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc rename to modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc index 339ad43f50..725698b6e5 100644 --- a/modules/ROOT/partials/plugin-apis/trackchanges-apis.adoc +++ b/modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc @@ -12,10 +12,10 @@ [source,js] ---- // Get the current model of the document -tinymce.activeEditor.plugins.trackchanges.getModel(); +tinymce.activeEditor.plugins.suggestededits.getModel(); // Check if document contains changes to be reviewed -tinymce.activeEditor.plugins.trackchanges.hasChanges(); +tinymce.activeEditor.plugins.suggestededits.hasChanges(); ---- //// @@ -23,15 +23,15 @@ tinymce.activeEditor.plugins.trackchanges.hasChanges(); [source,js] ---- // Get the current model of the document -tinymce.activeEditor.plugins.trackchanges.getModel(); +tinymce.activeEditor.plugins.suggestededits.getModel(); // Set current model of the document -tinymce.activeEditor.plugins.trackchanges.setModel(model); +tinymce.activeEditor.plugins.suggestededits.setModel(model); // Reset the document model to its original state -tinymce.activeEditor.plugins.trackchanges.resetModel(); +tinymce.activeEditor.plugins.suggestededits.resetModel(); // Check if document contains changes to be reviewed -tinymce.activeEditor.plugins.trackchanges.hasChanges(); +tinymce.activeEditor.plugins.suggestededits.hasChanges(); ---- //// \ No newline at end of file diff --git a/modules/ROOT/partials/toolbar-button-ids/trackchanges-toolbar-buttons.adoc b/modules/ROOT/partials/toolbar-button-ids/suggestededits-toolbar-buttons.adoc similarity index 59% rename from modules/ROOT/partials/toolbar-button-ids/trackchanges-toolbar-buttons.adoc rename to modules/ROOT/partials/toolbar-button-ids/suggestededits-toolbar-buttons.adoc index 4def3fff9f..45fc5d5f82 100644 --- a/modules/ROOT/partials/toolbar-button-ids/trackchanges-toolbar-buttons.adoc +++ b/modules/ROOT/partials/toolbar-button-ids/suggestededits-toolbar-buttons.adoc @@ -2,5 +2,5 @@ |=== |Toolbar button identifier |Description -|`+trackchanges+` |Open the Track Changes view. +|`+suggestededits+` |Open the Suggested Edits view. |=== \ No newline at end of file From 4db7c6cd4a092e0bd9ee54302f901b6fc435d200 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Tue, 15 Apr 2025 09:20:00 +1000 Subject: [PATCH 21/68] Update docs to include Review Permissions V1 --- .../suggestededits-access/index.html | 34 ++++++++ .../live-demos/suggestededits-access/index.js | 10 +++ .../live-demos/suggestededits/index.js | 1 + .../configuration/suggestededits-options.adoc | 79 +++++++++++++++---- 4 files changed, 109 insertions(+), 15 deletions(-) create mode 100644 modules/ROOT/examples/live-demos/suggestededits-access/index.html create mode 100644 modules/ROOT/examples/live-demos/suggestededits-access/index.js diff --git a/modules/ROOT/examples/live-demos/suggestededits-access/index.html b/modules/ROOT/examples/live-demos/suggestededits-access/index.html new file mode 100644 index 0000000000..97445bffd3 --- /dev/null +++ b/modules/ROOT/examples/live-demos/suggestededits-access/index.html @@ -0,0 +1,34 @@ + diff --git a/modules/ROOT/examples/live-demos/suggestededits-access/index.js b/modules/ROOT/examples/live-demos/suggestededits-access/index.js new file mode 100644 index 0000000000..e6b255cb43 --- /dev/null +++ b/modules/ROOT/examples/live-demos/suggestededits-access/index.js @@ -0,0 +1,10 @@ +tinymce.init({ + selector: 'textarea#trackchanges', + height: 500, + plugins: 'trackchanges', + toolbar: 'trackchanges', + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', + trackchanges_uid: 'adamhenderson', + trackchanges_access: 'read', //change this value to set permission to the Suggested Edits view + readonly: false //set to true to restrict a user's editing permission +}); \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/suggestededits/index.js b/modules/ROOT/examples/live-demos/suggestededits/index.js index 4d888ade46..4334e24a28 100644 --- a/modules/ROOT/examples/live-demos/suggestededits/index.js +++ b/modules/ROOT/examples/live-demos/suggestededits/index.js @@ -35,3 +35,4 @@ tinymce.init({ trackchanges_uid: 'adamhenderson', trackchanges_user_lookup, }); + diff --git a/modules/ROOT/partials/configuration/suggestededits-options.adoc b/modules/ROOT/partials/configuration/suggestededits-options.adoc index 96322925a2..a4cb7e6dcc 100644 --- a/modules/ROOT/partials/configuration/suggestededits-options.adoc +++ b/modules/ROOT/partials/configuration/suggestededits-options.adoc @@ -1,11 +1,31 @@ +[[suggestededits_uid]] +== `suggestededits_uid` + +The `{plugincode}_uid` is a _required_ option that takes as input a unique string to identify the current user. This is used to attribute changes made by the user. + +*Type:* `+String+` + +=== Example: using `{plugincode}_uid` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + suggestededits_uid: 'unique-identifier' // replace this with a unique string to identify the user +}); +---- + [[suggestededits_model]] == `suggestededits_model` -The `suggestededits_model` option sets the initial model of the document to begin tracking changes. It takes as input an object representing the document. If no value is set, the plugin will generate the model by default. +The `{plugincode}_model` option sets the initial model of the document to begin tracking changes. It takes as input an object representing the document. If no value is set, the plugin will generate the model by default. //*Type:* xref:#trackeddocument[TrackedDocument] `+Object+` -=== Example: using `suggestededits_model` +=== Example: using `{plugincode}_model` // Add a working and tested configuration. [source,js] @@ -14,6 +34,7 @@ tinymce.init({ selector: 'textarea', // Change this value according to your HTML plugins: 'suggestededits', toolbar: 'suggestededits', + suggestededits_uid: 'unique-identifier', // replace this with a unique string to identify the user suggestededits_model: { version: 1, maxId: 0, @@ -29,36 +50,64 @@ tinymce.init({ }); ---- -[[suggestededits_uid]] -== `suggestededits_uid` +[[suggestededits_access]] +== `suggestededits_access` -The `suggestededits_uid` is a _required_ option that takes as input a unique string to identify the current user. This is used to attribute changes made by the user. +To configure a user's permission to edit the document and review changes, the `{plugincode}_access` option can be set alongside the editor mode. *Type:* `+String+` -=== Example: using `suggestededits_uid` +*Possible Values*: `'full'`, `'suggest'`, `'read'`, `'none'` -// Add a working and tested configuration. -[source,js] +*Default Value*: `'full'` + +The possible values set the access level of the review permissions as follows: + +[cols="20%,80%"] +|=== +|Value | Review Permission + +|`+'full'+` +|Access to the {pluginname} view, with permission to accept, reject, or add suggestions to changes. + +|`+'suggest'+` +|Access to the {pluginname} view, with permission to add suggestions to changes. + +|`+'read'+` +|Readonly access to the {pluginname} view. + +|`+'none'+` +|No access to the {pluginname} view. +|=== + +[NOTE] +The `{plugincode}_access` option can be used in combination with the editor's read-only mode to restrict a user’s editing permission. + +.Example +[source,javascript] ---- tinymce.init({ selector: 'textarea', // Change this value according to your HTML plugins: 'suggestededits', toolbar: 'suggestededits', - suggestededits_uid: 'unique-identifier' // replace this with a unique string to identify the user + suggestededits_uid: 'unique-identifier', // replace this with a unique string to identify the user + suggestededits_access: 'full' //change this value to set permission to the Suggested Edits view + readonly: false //set to true to restrict a user's editing permission }); ---- +liveDemo::suggestededits-access[] + [[suggestededits_css_url]] == `suggestededits_css_url` -The `suggestededits_css_url` option sets the location where a CSS file containing change annotations in the {pluginname} view should be loaded from. To override the default CSS classes, use this option alongside `suggestededits_diff_classes`. +The `{plugincode}_css_url` option sets the location where a CSS file containing change annotations in the {pluginname} view should be loaded from. To override the default CSS classes, use this option alongside `{plugincode}_diff_classes`. *Type:* `+String+` -*Default value:* `'${pluginUrl}/css/suggestededits.css'` +*Default value:* `'${pluginUrl}/css/{plugincode}.css'` -=== Example: using `suggestededits_css_url` +=== Example: using `{plugincode}_css_url` // Add a working and tested configuration. [source,js] @@ -72,10 +121,10 @@ tinymce.init({ [[suggestededits_diff_classes]] == `suggestededits_diff_classes` -The `suggestededits_diff_classes` option configures the CSS classes applied to the change annotations in the {pluginname} view. This is useful to set custom styles and must be used in combination with the `suggestededits_css_url` option. +The `{plugincode}_diff_classes` option configures the CSS classes applied to the change annotations in the {pluginname} view. This is useful to set custom styles and must be used in combination with the `{plugincode}_css_url` option. [NOTE] -The CSS class names must exist in the xref:suggestededits_css_url[`+suggestededits_css_url+`]. +The CSS class names must exist in the xref:{plugincode}_css_url[`+{plugincode}_css_url+`]. *Type:* `+Object+` @@ -92,7 +141,7 @@ Below are the default CSS classes: } ---- -=== Example: using `suggestededits_diff_classes` +=== Example: using `{plugincode}_diff_classes` [source,js] ---- From 6f5286604c537be2d6f9377fc10c8c187906f37e Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Tue, 15 Apr 2025 10:02:52 +1000 Subject: [PATCH 22/68] Fix demo for Review Permissions --- .../suggestededits-access/index.html | 2 +- .../live-demos/suggestededits-access/index.js | 32 +++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/modules/ROOT/examples/live-demos/suggestededits-access/index.html b/modules/ROOT/examples/live-demos/suggestededits-access/index.html index 97445bffd3..eb09c543be 100644 --- a/modules/ROOT/examples/live-demos/suggestededits-access/index.html +++ b/modules/ROOT/examples/live-demos/suggestededits-access/index.html @@ -1,4 +1,4 @@ - diff --git a/modules/ROOT/examples/live-demos/suggestededits-suggestions/index.js b/modules/ROOT/examples/live-demos/suggestededits-suggestions/index.js new file mode 100644 index 0000000000..0484a81b82 --- /dev/null +++ b/modules/ROOT/examples/live-demos/suggestededits-suggestions/index.js @@ -0,0 +1,38 @@ +/** Fake user database */ +const userinfos = { + adamhenderson: { + uid: 'adamhenderson', + name: 'Adam Henderson', + avatar: `https://randomuser.me/api/portraits/men/1.jpg`, + }, + michaelcook: { + uid: 'michaelcook', + name: 'Michael Cook', + avatar: `https://randomuser.me/api/portraits/men/2.jpg`, + }, + kalebwilson: { + uid: 'kalebwilson', + name: 'Kaleb Wilson', + avatar: `https://randomuser.me/api/portraits/men/3.jpg`, + }, + kyleeinstein: { + uid: 'kyleeinstein', + name: 'Kyle Einstein', + avatar: `https://randomuser.me/api/portraits/men/4.jpg`, + }, +}; + +const trackchanges_user_lookup = (uid) => new Promise((resolve, reject) => + setTimeout(() => userinfos[uid] ? resolve(userinfos[uid]) : reject(), 1000)); + +tinymce.init({ + selector: 'textarea#trackchanges_suggestions', + height: 500, + plugins: 'trackchanges', + toolbar: 'trackchanges', + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', + trackchanges_uid: 'adamhenderson', + trackchanges_access: 'suggest', //change this value to set permission to the Suggested Edits view + readonly: false, //set to true to restrict a user's editing permission + trackchanges_user_lookup +}); \ No newline at end of file diff --git a/modules/ROOT/pages/suggestededits.adoc b/modules/ROOT/pages/suggestededits.adoc index fc5277efd1..5301618573 100644 --- a/modules/ROOT/pages/suggestededits.adoc +++ b/modules/ROOT/pages/suggestededits.adoc @@ -80,6 +80,14 @@ tinymce.init({ }); ---- +== Suggestions + +The plugin also enables users to provide suggestions or feedback to edits before they are resolved. This feature is only available if xref:{plugincode}_access[`+suggestededits_access+`] is set to `admin` or `suggest`. + +Example: Using Suggestions + +liveDemo::suggestededits-suggestions[] + == Options The following configuration options affect the behavior of the {pluginname} plugin. diff --git a/modules/ROOT/partials/configuration/suggestededits-options.adoc b/modules/ROOT/partials/configuration/suggestededits-options.adoc index a4cb7e6dcc..2e16c037e0 100644 --- a/modules/ROOT/partials/configuration/suggestededits-options.adoc +++ b/modules/ROOT/partials/configuration/suggestededits-options.adoc @@ -124,7 +124,7 @@ tinymce.init({ The `{plugincode}_diff_classes` option configures the CSS classes applied to the change annotations in the {pluginname} view. This is useful to set custom styles and must be used in combination with the `{plugincode}_css_url` option. [NOTE] -The CSS class names must exist in the xref:{plugincode}_css_url[`+{plugincode}_css_url+`]. +The CSS class names must exist in the xref:{plugincode}_css_url[`+suggestededits_css_url+`]. *Type:* `+Object+` From 9b7ef267ebaaaa71387c48a7e970455c38f7397e Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Fri, 9 May 2025 13:30:18 +1000 Subject: [PATCH 24/68] Revise Suggestions content --- modules/ROOT/pages/suggestededits.adoc | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/modules/ROOT/pages/suggestededits.adoc b/modules/ROOT/pages/suggestededits.adoc index 5301618573..b7479d5c65 100644 --- a/modules/ROOT/pages/suggestededits.adoc +++ b/modules/ROOT/pages/suggestededits.adoc @@ -47,6 +47,8 @@ The sidebar also displays all tracked changes that need to be resolved. Each cha * Reject: Removes the change from the document. * Revert: Undoes a previously accepted or rejected change. +The plugin also enables users to view and provide suggestions to edits. All users with access to the {pluginname} View can view suggestions. To allow users to provide suggestions, xref:{plugincode}_access[`{plugincode}_access`] must be set to either `admin` or `suggest`. + == Basic setup To setup the {pluginname} plugin in the editor: @@ -80,14 +82,6 @@ tinymce.init({ }); ---- -== Suggestions - -The plugin also enables users to provide suggestions or feedback to edits before they are resolved. This feature is only available if xref:{plugincode}_access[`+suggestededits_access+`] is set to `admin` or `suggest`. - -Example: Using Suggestions - -liveDemo::suggestededits-suggestions[] - == Options The following configuration options affect the behavior of the {pluginname} plugin. From 25127a5921dfc058f9fc17b42c803f87a3ad0bdd Mon Sep 17 00:00:00 2001 From: MitchCTiny Date: Tue, 20 May 2025 12:19:19 +1000 Subject: [PATCH 25/68] DOC-3174: Updating suggestedits docs --- modules/ROOT/pages/suggestededits.adoc | 27 ++-- .../configuration/suggestededits-options.adoc | 49 +++++--- .../plugin-apis/suggestededits-apis.adoc | 116 +++++++++++++++++- 3 files changed, 160 insertions(+), 32 deletions(-) diff --git a/modules/ROOT/pages/suggestededits.adoc b/modules/ROOT/pages/suggestededits.adoc index b7479d5c65..2b316254ff 100644 --- a/modules/ROOT/pages/suggestededits.adoc +++ b/modules/ROOT/pages/suggestededits.adoc @@ -49,37 +49,30 @@ The sidebar also displays all tracked changes that need to be resolved. Each cha The plugin also enables users to view and provide suggestions to edits. All users with access to the {pluginname} View can view suggestions. To allow users to provide suggestions, xref:{plugincode}_access[`{plugincode}_access`] must be set to either `admin` or `suggest`. -== Basic setup +== Initial setup + +The Suggested Edits plugin uses a document model to track changes. If the model is not provided in the editor configuration, the plugin will create a new model from the current content of the editor. This model can be retrieved from the editor at any time using the xref:#get_model[`getModel` API], and should be saved externally 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; -* add `{plugincode}_model` to the editor configuration. -* add `{plugincode}_uid` to the editor configuration. +* add `{plugincode}_model` to the editor configuration, if a document is already being tracked. For example: [source,js] ---- +const suggestededits_model = `` // model provided by suggestededits plugin API + tinymce.init({ - selector: 'textarea', // change this value according to your HTML + selector: 'textarea#suggestededits', // change this value according to your HTML plugins: 'suggestededits', toolbar: 'suggestededits', - suggestededits_model: { - version: 1, - maxId: 0, - contents: [ - { - type: 'p', - children: [ - { text: 'Hello, World!' } - ] - } - ] - }, - suggestededits_uid: 'unique-identifier' // replace this with a unique string to identify the user + suggestededits_model, // model provided by suggestededits plugin API }); + + ---- == Options diff --git a/modules/ROOT/partials/configuration/suggestededits-options.adoc b/modules/ROOT/partials/configuration/suggestededits-options.adoc index 2e16c037e0..24d8cda1ef 100644 --- a/modules/ROOT/partials/configuration/suggestededits-options.adoc +++ b/modules/ROOT/partials/configuration/suggestededits-options.adoc @@ -21,8 +21,9 @@ tinymce.init({ [[suggestededits_model]] == `suggestededits_model` -The `{plugincode}_model` option sets the initial model of the document to begin tracking changes. It takes as input an object representing the document. If no value is set, the plugin will generate the model by default. +The `{plugincode}_model` option sets the initial model of the document to begin tracking changes. It takes as input an object representing the document, containing all edits made to the document up to that point. This model should be saved externally alongside the document, and loaded into the editor each time the document is opened. This will ensure that both the document and the model are in sync, and that the plugin can track edits correctly. +If the model is not provided in the editor configuration, the plugin will create a new model from the current content of the editor. This model can be retrieved from the editor at any time using the xref:#get_model[`getModel` API]. //*Type:* xref:#trackeddocument[TrackedDocument] `+Object+` === Example: using `{plugincode}_model` @@ -35,18 +36,7 @@ tinymce.init({ plugins: 'suggestededits', toolbar: 'suggestededits', suggestededits_uid: 'unique-identifier', // replace this with a unique string to identify the user - suggestededits_model: { - version: 1, - maxId: 0, - contents: [ - { - type: 'p', - children: [ - { text: 'Hello, World!' } - ] - } - ] - } + suggestededits_model // Model representing the document with up to date edits }); ---- @@ -57,7 +47,7 @@ To configure a user's permission to edit the document and review changes, the `{ *Type:* `+String+` -*Possible Values*: `'full'`, `'suggest'`, `'read'`, `'none'` +*Possible Values*: `'full'`, `'suggest'`, `'read'`, `'none'` *Default Value*: `'full'` @@ -98,6 +88,37 @@ tinymce.init({ liveDemo::suggestededits-access[] +[[suggestededits_content]] +== `suggestededits_content` +The `{plugincode}_content` option determines where the initial content of the document is loaded from. With this option, you can set the content to be loaded from either the editor or the model, allowing you to control the source of truth for the document. + +When set to `'html'`, the editor loads the initial content from the HTML in the textarea or the `content` property. In this case, if a model is provided, it will need to match the content in the editor for the plugin to work correctly + +When set to `'model'`, the editor loads the initial content from the `{plugincode}_model` option. In this case, the content in the editor will be overwritten with the content from the model. This would allow you to only require the model for document tracking, though it is still recommended to save the content in the editor externally. + +In either case, if a model is not provided, the plugin will generate a new model from the current content of the editor, whether it is empty or not. + +*Type:* `+String+` + +*Possible Values*: `'html'`, `'model'` + +*Default value:* `'html'` + +=== Example: using `{plugincode}_css_url` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + suggestededits_uid: 'unique-identifier', // replace this with a unique string to identify the user + suggestededits_model, + suggestededits_content: 'model' // change this value to set the content source +}); +---- + [[suggestededits_css_url]] == `suggestededits_css_url` diff --git a/modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc b/modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc index 725698b6e5..6a547b89ad 100644 --- a/modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc +++ b/modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc @@ -3,7 +3,7 @@ |Name |Arguments |Description |getModel |N/A |Return an object representing the document model used to store data of the tracked changes. -//|setModel |xref:#trackeddocument[TrackedDocument] `+Object+` | Set the current model of the document. +|setModel |xref:#trackeddocument[TrackedDocument] `+Object+` | Set the current model of the document. //|resetModel |N/A |Reset the document to its original state. |hasChanges |N/A |Return a boolean value indicating whether the document contains changes to be reviewed. |=== @@ -14,10 +14,124 @@ // Get the current model of the document tinymce.activeEditor.plugins.suggestededits.getModel(); +// Set current model of the document +tinymce.activeEditor.plugins.suggestededits.setModel(model); + // Check if document contains changes to be reviewed tinymce.activeEditor.plugins.suggestededits.hasChanges(); ---- +[[get_model]] +.`getModel` Example +[source,js] +---- +const documentId = ''; // Replace with the actual document ID + +tinymce.init({ + selector: 'textarea#suggestededits', // change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits save', + suggestededits_model, + setup: (editor) => { + editor.ui.registry.addButton('save', { + text: 'Save', + onAction: () => { + // Get the current content of the editor + const content = editor.getContent(); + + // Get the current model of the document + const model = editor.plugins.suggestededits.getModel(); + + fetch(`/api/documents/${documentId}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ content, model }), + }) + .then((response) => response.json()) + .then((data) => console.log('Document saved:', data)) + .catch((error) => console.error('Error saving document:', error)); + + // Save the model to the server + fetch(`/api/models/${documentId}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(model), + }) + .then((response) => response.json()) + .then((data) => console.log('Model saved:', data)) + .catch((error) => console.error('Error saving model:', error)); + } + }); + } +}); + +---- + +[[set_model]] +.`setModel` Example +[source,js] +---- +const documentId = ''; // Replace with the actual document ID + +tinymce.init({ + selector: 'textarea#suggestededits', // change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + // No model provided in the editor configuration, it will be fetched from the server + init_instance_callback: (editor) => { + // Fetch the document from the server + fetch(`/api/documents/${documentId}`) + .then((response) => { + // Set the content in the editor + editor.setContent(response); + }) + .catch((error) => console.error(`Error fetching document ${documentId}:`, error)); + + // Fetch the document model from the server + fetch(`/api/models/${documentId}`) + .then((response) => response.json()) + .then((model) => { + // Set the model in the editor + editor.plugins.suggestededits.setModel(model); + }) + .catch((error) => console.error(`Error fetching document ${documentId} model:`, error)); + } +}); +---- + +[[has_changes]] +.`hasChanges` Example +[source,js] +---- +tinymce.init({ + selector: 'textarea#suggestededits', // change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + setup: (editor) => { + editor.ui.registry.addButton('save', { + text: 'Save', + onAction: () => { + // Get the current model of the document + const hasChanges = editor.plugins.suggestededits.hasChanges(); + + if (hasChanges) { + editor.notificationManager.open({ + text: 'There are changes to be reviewed.', + type: 'warning', + timeout: 5000, + }); + } else { + // Insert save logic here + } + } + }); + } +}); +---- //// .Examples [source,js] From 584785f55ef97da61e6652b7367f2ae729174b98 Mon Sep 17 00:00:00 2001 From: MitchCTiny Date: Tue, 20 May 2025 14:59:43 +1000 Subject: [PATCH 26/68] DOC-3174: Remove unused options --- .../configuration/suggestededits-options.adoc | 82 +------------------ 1 file changed, 1 insertion(+), 81 deletions(-) diff --git a/modules/ROOT/partials/configuration/suggestededits-options.adoc b/modules/ROOT/partials/configuration/suggestededits-options.adoc index 24d8cda1ef..e4a3cdeb94 100644 --- a/modules/ROOT/partials/configuration/suggestededits-options.adoc +++ b/modules/ROOT/partials/configuration/suggestededits-options.adoc @@ -1,23 +1,3 @@ -[[suggestededits_uid]] -== `suggestededits_uid` - -The `{plugincode}_uid` is a _required_ option that takes as input a unique string to identify the current user. This is used to attribute changes made by the user. - -*Type:* `+String+` - -=== Example: using `{plugincode}_uid` - -// Add a working and tested configuration. -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - plugins: 'suggestededits', - toolbar: 'suggestededits', - suggestededits_uid: 'unique-identifier' // replace this with a unique string to identify the user -}); ----- - [[suggestededits_model]] == `suggestededits_model` @@ -104,7 +84,7 @@ In either case, if a model is not provided, the plugin will generate a new model *Default value:* `'html'` -=== Example: using `{plugincode}_css_url` +=== Example: using `{plugincode}_content` // Add a working and tested configuration. [source,js] @@ -118,63 +98,3 @@ tinymce.init({ suggestededits_content: 'model' // change this value to set the content source }); ---- - -[[suggestededits_css_url]] -== `suggestededits_css_url` - -The `{plugincode}_css_url` option sets the location where a CSS file containing change annotations in the {pluginname} view should be loaded from. To override the default CSS classes, use this option alongside `{plugincode}_diff_classes`. - -*Type:* `+String+` - -*Default value:* `'${pluginUrl}/css/{plugincode}.css'` - -=== Example: using `{plugincode}_css_url` - -// Add a working and tested configuration. -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - suggestededits_css_url: './suggestededits.css' -}); ----- - -[[suggestededits_diff_classes]] -== `suggestededits_diff_classes` - -The `{plugincode}_diff_classes` option configures the CSS classes applied to the change annotations in the {pluginname} view. This is useful to set custom styles and must be used in combination with the `{plugincode}_css_url` option. - -[NOTE] -The CSS class names must exist in the xref:{plugincode}_css_url[`+suggestededits_css_url+`]. - -*Type:* `+Object+` - -*Default value:* `addition`, `removal`, `modification` - -Below are the default CSS classes: - -[source,js] ----- -{ - addition: 'tox-suggestededits__annotation--added', - removal: 'tox-suggestededits__annotation--removed', - modification: 'tox-suggestededits__annotation--modified' -} ----- - -=== Example: using `{plugincode}_diff_classes` - -[source,js] ----- -tinymce.init({ - selector: 'textarea', // change this value according to your HTML - plugins: 'suggestededits', - toolbar: 'suggestededits', - suggestededits_css_url: './suggestededits.css', - suggestededits_diff_classes: { - addition: 'added', - removal: 'removed', - modification: 'modified' - } -}); ----- From 7791c9a623923d73b7e3aece9bd93b0c914d5450 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Wed, 28 May 2025 12:08:05 +1000 Subject: [PATCH 27/68] Update explanation of plugin and add UID options --- modules/ROOT/pages/suggestededits.adoc | 25 ++++- .../configuration/suggestededits-options.adoc | 105 +----------------- .../configuration/suggestededits_access.adoc | 47 ++++++++ .../configuration/suggestededits_content.adoc | 30 +++++ .../configuration/suggestededits_model.adoc | 21 ++++ .../configuration/userlookup_fetch.adoc | 19 ++++ .../configuration/userlookup_userid.adoc | 17 +++ 7 files changed, 161 insertions(+), 103 deletions(-) create mode 100644 modules/ROOT/partials/configuration/suggestededits_access.adoc create mode 100644 modules/ROOT/partials/configuration/suggestededits_content.adoc create mode 100644 modules/ROOT/partials/configuration/suggestededits_model.adoc create mode 100644 modules/ROOT/partials/configuration/userlookup_fetch.adoc create mode 100644 modules/ROOT/partials/configuration/userlookup_userid.adoc diff --git a/modules/ROOT/pages/suggestededits.adoc b/modules/ROOT/pages/suggestededits.adoc index 2b316254ff..3d5e5f7c9b 100644 --- a/modules/ROOT/pages/suggestededits.adoc +++ b/modules/ROOT/pages/suggestededits.adoc @@ -21,9 +21,14 @@ include::partial$misc/admon-iframe-only.adoc[] == How it works -The Suggested Edits plugin monitors edits made to a document by comparing its current state to the original version. Each change is attributed to its respective author and can be approved or rejected before being applied to the document. +The Suggested Edits plugin builds a document model of the editor content to track edits made by multiple authors. This model is used to compare the current content of the editor with the original version, highlighting changes such as insertions, modifications, and deletions. -The plugin includes a dedicated view for reviewing current changes, accessible via the `{plugincode}` toolbar button or the menu option under the `View` menu. The key components are: +This allows users to review the changes made to the document, provide feedback on them, and accept or reject them as needed. See xref:#suggestededits_access[`suggestededits_access`] option for more information on how to configure user permissions for editing and reviewing content. + +[NOTE] +The model's content should be considered as metadata of the editor's HTML content, and both should be saved together to ensure correctness. See xref:#suggestededits_content[`suggestededits_content`] for more information on how to configure the source of content loaded into the editor. + +A dedicated read-only view is provided for reviewing current changes, accessible via the `{plugincode}` toolbar button or the menu option under the `View` menu. The key components are: . **Read-only Diff View**: + @@ -47,7 +52,21 @@ The sidebar also displays all tracked changes that need to be resolved. Each cha * Reject: Removes the change from the document. * Revert: Undoes a previously accepted or rejected change. -The plugin also enables users to view and provide suggestions to edits. All users with access to the {pluginname} View can view suggestions. To allow users to provide suggestions, xref:{plugincode}_access[`{plugincode}_access`] must be set to either `admin` or `suggest`. +== Types of suggestions + +There are four basic types of suggestions that are tracked by the Suggested Edits plugin: + +==== Insert +Tracks the addition of new content to the document. + +==== Modify +Tracks HTML attribute changes or formatting changes to existing content, such as bold or italic text. Note that if multiple users modify the same content, the original author will still be attributed with the change. + +==== Delete +Tracks the removal of content from the document. + +==== Replace +Tracks the replacement of existing content with new content. This is treated as a combination of a delete and an insert, where the original content is selected and replaced by new content. Note that if multiple users replace the same content, the most recent author will be attributed with the change. == Initial setup diff --git a/modules/ROOT/partials/configuration/suggestededits-options.adoc b/modules/ROOT/partials/configuration/suggestededits-options.adoc index e4a3cdeb94..50aed5dfe6 100644 --- a/modules/ROOT/partials/configuration/suggestededits-options.adoc +++ b/modules/ROOT/partials/configuration/suggestededits-options.adoc @@ -1,100 +1,5 @@ -[[suggestededits_model]] -== `suggestededits_model` - -The `{plugincode}_model` option sets the initial model of the document to begin tracking changes. It takes as input an object representing the document, containing all edits made to the document up to that point. This model should be saved externally alongside the document, and loaded into the editor each time the document is opened. This will ensure that both the document and the model are in sync, and that the plugin can track edits correctly. - -If the model is not provided in the editor configuration, the plugin will create a new model from the current content of the editor. This model can be retrieved from the editor at any time using the xref:#get_model[`getModel` API]. -//*Type:* xref:#trackeddocument[TrackedDocument] `+Object+` - -=== Example: using `{plugincode}_model` - -// Add a working and tested configuration. -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - plugins: 'suggestededits', - toolbar: 'suggestededits', - suggestededits_uid: 'unique-identifier', // replace this with a unique string to identify the user - suggestededits_model // Model representing the document with up to date edits -}); ----- - -[[suggestededits_access]] -== `suggestededits_access` - -To configure a user's permission to edit the document and review changes, the `{plugincode}_access` option can be set alongside the editor mode. - -*Type:* `+String+` - -*Possible Values*: `'full'`, `'suggest'`, `'read'`, `'none'` - -*Default Value*: `'full'` - -The possible values set the access level of the review permissions as follows: - -[cols="20%,80%"] -|=== -|Value | Review Permission - -|`+'full'+` -|Access to the {pluginname} view, with permission to accept, reject, or add suggestions to changes. - -|`+'suggest'+` -|Access to the {pluginname} view, with permission to add suggestions to changes. - -|`+'read'+` -|Readonly access to the {pluginname} view. - -|`+'none'+` -|No access to the {pluginname} view. -|=== - -[NOTE] -The `{plugincode}_access` option can be used in combination with the editor's read-only mode to restrict a user’s editing permission. - -.Example -[source,javascript] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - plugins: 'suggestededits', - toolbar: 'suggestededits', - suggestededits_uid: 'unique-identifier', // replace this with a unique string to identify the user - suggestededits_access: 'full' //change this value to set permission to the Suggested Edits view - readonly: false //set to true to restrict a user's editing permission -}); ----- - -liveDemo::suggestededits-access[] - -[[suggestededits_content]] -== `suggestededits_content` -The `{plugincode}_content` option determines where the initial content of the document is loaded from. With this option, you can set the content to be loaded from either the editor or the model, allowing you to control the source of truth for the document. - -When set to `'html'`, the editor loads the initial content from the HTML in the textarea or the `content` property. In this case, if a model is provided, it will need to match the content in the editor for the plugin to work correctly - -When set to `'model'`, the editor loads the initial content from the `{plugincode}_model` option. In this case, the content in the editor will be overwritten with the content from the model. This would allow you to only require the model for document tracking, though it is still recommended to save the content in the editor externally. - -In either case, if a model is not provided, the plugin will generate a new model from the current content of the editor, whether it is empty or not. - -*Type:* `+String+` - -*Possible Values*: `'html'`, `'model'` - -*Default value:* `'html'` - -=== Example: using `{plugincode}_content` - -// Add a working and tested configuration. -[source,js] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - plugins: 'suggestededits', - toolbar: 'suggestededits', - suggestededits_uid: 'unique-identifier', // replace this with a unique string to identify the user - suggestededits_model, - suggestededits_content: 'model' // change this value to set the content source -}); ----- +include::partial$configuration/userlookup_userid.adoc[] +include::partial$configuration/userlookup_fetch.adoc[] +include::partial$configuration/suggestededits_model.adoc[] +include::partial$configuration/suggestededits_content.adoc[] +include::partial$configuration/suggestededits_access.adoc[] diff --git a/modules/ROOT/partials/configuration/suggestededits_access.adoc b/modules/ROOT/partials/configuration/suggestededits_access.adoc new file mode 100644 index 0000000000..fd0f1020df --- /dev/null +++ b/modules/ROOT/partials/configuration/suggestededits_access.adoc @@ -0,0 +1,47 @@ +[[suggestededits_access]] +== `suggestededits_access` + +To configure a user's permission to edit the document and review changes, the `{plugincode}_access` option can be set alongside the editor mode. + +*Type:* `+String+` + +*Possible Values*: `'full'`, `'suggest'`, `'read'`, `'none'` + +*Default Value*: `'full'` + +The possible values set the access level of the review permissions as follows: + +[cols="20%,80%"] +|=== +|Value | Review Permission + +|`+'full'+` +|Access to the {pluginname} view, with permission to accept, reject, or add suggestions to changes. + +|`+'suggest'+` +|Access to the {pluginname} view, with permission to add suggestions to changes. + +|`+'read'+` +|Readonly access to the {pluginname} view. + +|`+'none'+` +|No access to the {pluginname} view. +|=== + +[NOTE] +The `{plugincode}_access` option can be used in combination with the editor's read-only mode to restrict a user’s editing permission. + +.Example +[source,javascript] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + suggestededits_uid: 'unique-identifier', // replace this with a unique string to identify the user + suggestededits_access: 'full' //change this value to set permission to the Suggested Edits view + readonly: false //set to true to restrict a user's editing permission +}); +---- + +liveDemo::suggestededits-access[] \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/suggestededits_content.adoc b/modules/ROOT/partials/configuration/suggestededits_content.adoc new file mode 100644 index 0000000000..eae0d545bb --- /dev/null +++ b/modules/ROOT/partials/configuration/suggestededits_content.adoc @@ -0,0 +1,30 @@ +[[suggestededits_content]] +== `suggestededits_content` +The `{plugincode}_content` option determines where the initial content of the document is loaded from. With this option, you can set the content to be loaded from either the editor or the model, allowing you to control the source of truth for the document. + +When set to `'html'`, the editor loads the initial content from the HTML in the textarea or the `content` property. In this case, if a model is provided, it will need to match the content in the editor for the plugin to work correctly + +When set to `'model'`, the editor loads the initial content from the `{plugincode}_model` option. In this case, the content in the editor will be overwritten with the content from the model. This would allow you to only require the model for document tracking, though it is still recommended to save the content in the editor externally. + +In either case, if a model is not provided, the plugin will generate a new model from the current content of the editor, whether it is empty or not. + +*Type:* `+String+` + +*Possible Values*: `'html'`, `'model'` + +*Default value:* `'html'` + +=== Example: using `{plugincode}_content` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + suggestededits_uid: 'unique-identifier', // replace this with a unique string to identify the user + suggestededits_model, + suggestededits_content: 'model' // change this value to set the content source +}); +---- diff --git a/modules/ROOT/partials/configuration/suggestededits_model.adoc b/modules/ROOT/partials/configuration/suggestededits_model.adoc new file mode 100644 index 0000000000..5bc8f8c045 --- /dev/null +++ b/modules/ROOT/partials/configuration/suggestededits_model.adoc @@ -0,0 +1,21 @@ +[[suggestededits_model]] +== `suggestededits_model` + +The `{plugincode}_model` option sets the initial model of the document to begin tracking changes. It takes as input an object representing the document, containing all edits made to the document up to that point. This model should be saved externally alongside the document, and loaded into the editor each time the document is opened. This will ensure that both the document and the model are in sync, and that the plugin can track edits correctly. + +If the model is not provided in the editor configuration, the plugin will create a new model from the current content of the editor. This model can be retrieved from the editor at any time using the xref:#get_model[`getModel` API]. +//*Type:* xref:#trackeddocument[TrackedDocument] `+Object+` + +=== Example: using `{plugincode}_model` + +// Add a working and tested configuration. +[source,js] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + suggestededits_uid: 'unique-identifier', // replace this with a unique string to identify the user + suggestededits_model // Model representing the document with up to date edits +}); +---- diff --git a/modules/ROOT/partials/configuration/userlookup_fetch.adoc b/modules/ROOT/partials/configuration/userlookup_fetch.adoc new file mode 100644 index 0000000000..0c18dccbf6 --- /dev/null +++ b/modules/ROOT/partials/configuration/userlookup_fetch.adoc @@ -0,0 +1,19 @@ +[[userlookup_fetch]] +== `userlookup_fetch` + +Required option to fetch a list of user IDs to display in the Suggested Edits view. This option uses the xref:#userlookupapi[`UserLookup API`]. + +*Type:* `+Array+` + +.Example +[source,javascript] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + userlookup_userid: 'unique-identifier', // replace this with a unique string to identify the user + userlookup_fetch: (ids) => fetch(`/api/users?ids=${ids.join(',')}`) + .then((r) => r.json()) +}); +---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/userlookup_userid.adoc b/modules/ROOT/partials/configuration/userlookup_userid.adoc new file mode 100644 index 0000000000..1ec962b857 --- /dev/null +++ b/modules/ROOT/partials/configuration/userlookup_userid.adoc @@ -0,0 +1,17 @@ +[[userlookup_userid]] +== `userlookup_userid` + +Required option to set the current user's unique ID in the editor, allowing the plugin to track changes made by this user and display them correctly in the Suggested Edits view. This option uses the xref:#userlookupapi[`UserLookup API`]. + +*Type:* `+String+` + +.Example +[source,javascript] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + userlookup_userid: 'unique-identifier' // replace this with a unique string to identify the user +}); +---- \ No newline at end of file From c93b4a3cbaf109880659ac132aa4af575994cc4d Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Tue, 3 Jun 2025 16:05:55 +1000 Subject: [PATCH 28/68] fix UID options --- modules/ROOT/partials/configuration/userlookup_fetch.adoc | 8 ++++---- .../ROOT/partials/configuration/userlookup_userid.adoc | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/ROOT/partials/configuration/userlookup_fetch.adoc b/modules/ROOT/partials/configuration/userlookup_fetch.adoc index 0c18dccbf6..32ff29efae 100644 --- a/modules/ROOT/partials/configuration/userlookup_fetch.adoc +++ b/modules/ROOT/partials/configuration/userlookup_fetch.adoc @@ -1,5 +1,5 @@ -[[userlookup_fetch]] -== `userlookup_fetch` +[[fetch_users]] +== `fetch_users` Required option to fetch a list of user IDs to display in the Suggested Edits view. This option uses the xref:#userlookupapi[`UserLookup API`]. @@ -12,8 +12,8 @@ tinymce.init({ selector: 'textarea', // Change this value according to your HTML plugins: 'suggestededits', toolbar: 'suggestededits', - userlookup_userid: 'unique-identifier', // replace this with a unique string to identify the user - userlookup_fetch: (ids) => fetch(`/api/users?ids=${ids.join(',')}`) + user_id: 'unique-identifier', // replace this with a unique string to identify the user + fetch_users: (ids) => fetch(`/api/users?ids=${ids.join(',')}`) .then((r) => r.json()) }); ---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/userlookup_userid.adoc b/modules/ROOT/partials/configuration/userlookup_userid.adoc index 1ec962b857..8f105f22c8 100644 --- a/modules/ROOT/partials/configuration/userlookup_userid.adoc +++ b/modules/ROOT/partials/configuration/userlookup_userid.adoc @@ -1,5 +1,5 @@ -[[userlookup_userid]] -== `userlookup_userid` +[[user_id]] +== `user_id` Required option to set the current user's unique ID in the editor, allowing the plugin to track changes made by this user and display them correctly in the Suggested Edits view. This option uses the xref:#userlookupapi[`UserLookup API`]. @@ -12,6 +12,6 @@ tinymce.init({ selector: 'textarea', // Change this value according to your HTML plugins: 'suggestededits', toolbar: 'suggestededits', - userlookup_userid: 'unique-identifier' // replace this with a unique string to identify the user + user_id: 'unique-identifier' // replace this with a unique string to identify the user }); ---- \ No newline at end of file From e978936a751d742769cfbaf883cae540badda4e4 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Mon, 9 Jun 2025 11:52:09 +1000 Subject: [PATCH 29/68] Update interactive demo --- .../live-demos/suggestededits/example.js | 53 ++- .../live-demos/suggestededits/index.html | 2 +- .../live-demos/suggestededits/index.js | 395 +++++++++++++++++- 3 files changed, 430 insertions(+), 20 deletions(-) diff --git a/modules/ROOT/examples/live-demos/suggestededits/example.js b/modules/ROOT/examples/live-demos/suggestededits/example.js index 814574e2a6..bbaeaddee0 100644 --- a/modules/ROOT/examples/live-demos/suggestededits/example.js +++ b/modules/ROOT/examples/live-demos/suggestededits/example.js @@ -1,9 +1,48 @@ +/** Fake user database */ +const userDb = { + adamhenderson: { + id: 'adamhenderson', + name: 'Adam Henderson', + avatar: `https://randomuser.me/api/portraits/men/1.jpg`, + }, + michaelcook: { + id: 'michaelcook', + name: 'Michael Cook', + avatar: `https://randomuser.me/api/portraits/men/2.jpg`, + }, + kalebwilson: { + id: 'kalebwilson', + name: 'Kaleb Wilson', + avatar: `https://randomuser.me/api/portraits/men/3.jpg`, + }, + kyleeinstein: { + id: 'kyleeinstein', + name: 'Kyle Einstein', + avatar: `https://randomuser.me/api/portraits/men/4.jpg`, + }, +}; + +const suggestededits_model = null; //Replace with the object returned by the plugin's getModel API, or null if there is no model. + +const fetch_users = (ids) => { + return new Promise((resolve, reject) => { + const users = ids.map(id => userDb[id]); + if (users.length > 0) { + resolve(users); + } else { + reject(new Error('No users found')); + } + }); +} tinymce.init({ - selector: 'textarea#trackchanges', - height: 500, - plugins: 'trackchanges', - toolbar: 'trackchanges', - content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', - trackchanges_uid: 'adamhenderson', - }); \ No newline at end of file + selector: 'textarea#suggested-edits', + height: 500, + plugins: 'suggestededits', + toolbar: 'suggestededits', + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', + suggestededits_model, // If there is no model, the plugin will generate a default model based on the editor content. + user_id: 'michaelcook', + fetch_users, +}); + diff --git a/modules/ROOT/examples/live-demos/suggestededits/index.html b/modules/ROOT/examples/live-demos/suggestededits/index.html index 7f32961fc0..b4199ee062 100644 --- a/modules/ROOT/examples/live-demos/suggestededits/index.html +++ b/modules/ROOT/examples/live-demos/suggestededits/index.html @@ -1,4 +1,4 @@ - ---- == Options diff --git a/modules/ROOT/partials/configuration/suggestededits-options.adoc b/modules/ROOT/partials/configuration/suggestededits-options.adoc index 50aed5dfe6..9c981f1dda 100644 --- a/modules/ROOT/partials/configuration/suggestededits-options.adoc +++ b/modules/ROOT/partials/configuration/suggestededits-options.adoc @@ -1,5 +1,5 @@ -include::partial$configuration/userlookup_userid.adoc[] -include::partial$configuration/userlookup_fetch.adoc[] +include::partial$configuration/userlookup_user_id.adoc[] +include::partial$configuration/userlookup_fetch_users.adoc[] include::partial$configuration/suggestededits_model.adoc[] include::partial$configuration/suggestededits_content.adoc[] include::partial$configuration/suggestededits_access.adoc[] diff --git a/modules/ROOT/partials/configuration/suggestededits_access.adoc b/modules/ROOT/partials/configuration/suggestededits_access.adoc index fd0f1020df..73c4eb8d60 100644 --- a/modules/ROOT/partials/configuration/suggestededits_access.adoc +++ b/modules/ROOT/partials/configuration/suggestededits_access.adoc @@ -38,8 +38,9 @@ tinymce.init({ selector: 'textarea', // Change this value according to your HTML plugins: 'suggestededits', toolbar: 'suggestededits', - suggestededits_uid: 'unique-identifier', // replace this with a unique string to identify the user - suggestededits_access: 'full' //change this value to set permission to the Suggested Edits view + user_id: 'unique-identifier', // replace this with a unique string to identify the user + fetch_users, // Function to fetch users for the user lookup API + suggestededits_access: 'full', //change this value to set the user's permission to the Suggested Edits view readonly: false //set to true to restrict a user's editing permission }); ---- diff --git a/modules/ROOT/partials/configuration/suggestededits_content.adoc b/modules/ROOT/partials/configuration/suggestededits_content.adoc index eae0d545bb..d29e11fc57 100644 --- a/modules/ROOT/partials/configuration/suggestededits_content.adoc +++ b/modules/ROOT/partials/configuration/suggestededits_content.adoc @@ -16,15 +16,15 @@ In either case, if a model is not provided, the plugin will generate a new model === Example: using `{plugincode}_content` -// Add a working and tested configuration. [source,js] ---- tinymce.init({ selector: 'textarea', // Change this value according to your HTML plugins: 'suggestededits', toolbar: 'suggestededits', - suggestededits_uid: 'unique-identifier', // replace this with a unique string to identify the user - suggestededits_model, - suggestededits_content: 'model' // change this value to set the content source + user_id: 'unique-identifier', // Replace this with a unique string to identify the user + fetch_users, // Function to fetch users for the user lookup API + suggestededits_model, // Load the saved model into the editor + suggestededits_content: 'model' // Only set this if you want to load the initial content from the model }); ---- diff --git a/modules/ROOT/partials/configuration/suggestededits_model.adoc b/modules/ROOT/partials/configuration/suggestededits_model.adoc index 5bc8f8c045..efc9db83cc 100644 --- a/modules/ROOT/partials/configuration/suggestededits_model.adoc +++ b/modules/ROOT/partials/configuration/suggestededits_model.adoc @@ -4,18 +4,27 @@ The `{plugincode}_model` option sets the initial model of the document to begin tracking changes. It takes as input an object representing the document, containing all edits made to the document up to that point. This model should be saved externally alongside the document, and loaded into the editor each time the document is opened. This will ensure that both the document and the model are in sync, and that the plugin can track edits correctly. If the model is not provided in the editor configuration, the plugin will create a new model from the current content of the editor. This model can be retrieved from the editor at any time using the xref:#get_model[`getModel` API]. -//*Type:* xref:#trackeddocument[TrackedDocument] `+Object+` + +*Type:* `+Object+` === Example: using `{plugincode}_model` -// Add a working and tested configuration. [source,js] ---- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - plugins: 'suggestededits', - toolbar: 'suggestededits', - suggestededits_uid: 'unique-identifier', // replace this with a unique string to identify the user - suggestededits_model // Model representing the document with up to date edits +async function fetchSavedModel(documentId) { + // Replace this URL and logic with your actual backend API + const response = await fetch(`/api/models/${documentId}`); + return await response.json(); +} + +fetchSavedModel('your-document-id').then((savedModel) => { + tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + plugins: 'suggestededits', + toolbar: 'suggestededits', + user_id: 'unique-identifier', // Replace with a unique string to identify the user + fetch_users, // Function to fetch users for the user lookup API + suggestededits_model: savedModel // Load the saved model into the editor + }); }); ---- diff --git a/modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc b/modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc index 6a547b89ad..c0998d5564 100644 --- a/modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc +++ b/modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc @@ -2,10 +2,10 @@ |=== |Name |Arguments |Description -|getModel |N/A |Return an object representing the document model used to store data of the tracked changes. -|setModel |xref:#trackeddocument[TrackedDocument] `+Object+` | Set the current model of the document. +|getModel |N/A |Return an object representing the document model used to store data of the suggested edits. +|setModel | `+Object+` | Set the current model of the document. //|resetModel |N/A |Reset the document to its original state. -|hasChanges |N/A |Return a boolean value indicating whether the document contains changes to be reviewed. +|hasChanges |N/A |Return a boolean value indicating whether the document contains edits to be reviewed. |=== .Examples @@ -25,7 +25,7 @@ tinymce.activeEditor.plugins.suggestededits.hasChanges(); .`getModel` Example [source,js] ---- -const documentId = ''; // Replace with the actual document ID +const documentId = ''; // Replace with your document ID tinymce.init({ selector: 'textarea#suggestededits', // change this value according to your HTML @@ -75,30 +75,40 @@ tinymce.init({ .`setModel` Example [source,js] ---- -const documentId = ''; // Replace with the actual document ID +const documentIds = ['doc1', 'doc2', 'doc3']; // Example document IDs tinymce.init({ selector: 'textarea#suggestededits', // change this value according to your HTML plugins: 'suggestededits', toolbar: 'suggestededits', - // No model provided in the editor configuration, it will be fetched from the server - init_instance_callback: (editor) => { - // Fetch the document from the server - fetch(`/api/documents/${documentId}`) - .then((response) => { - // Set the content in the editor - editor.setContent(response); - }) - .catch((error) => console.error(`Error fetching document ${documentId}:`, error)); - - // Fetch the document model from the server - fetch(`/api/models/${documentId}`) - .then((response) => response.json()) - .then((model) => { - // Set the model in the editor - editor.plugins.suggestededits.setModel(model); - }) - .catch((error) => console.error(`Error fetching document ${documentId} model:`, error)); + setup: (editor) => { + // Function to load a document and its model + function loadDocument(documentId) { + // Fetch and set the document content + fetch(`/api/documents/${documentId}`) + .then((response) => response.text()) + .then((content) => { + editor.setContent(content); + }) + .catch((error) => console.error(`Error fetching document ${documentId}:`, error)); + + // Fetch and set the suggested edits model + fetch(`/api/models/${documentId}`) + .then((response) => response.json()) + .then((model) => { + editor.plugins.suggestededits.setModel(model); + }) + .catch((error) => console.error(`Error fetching model for ${documentId}:`, error)); + } + + // Example: Attach to a button click event + document.getElementById('loadDocBtn').addEventListener('click', () => { + const selectedId = document.getElementById('docSelect').value; + loadDocument(selectedId); + }); + + // Optionally, load the first document on init + loadDocument(documentIds[0]); } }); ---- From 811fe8fa7bf3cdfb26175bf2eb53f6431816e30f Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Tue, 10 Jun 2025 09:57:31 +1000 Subject: [PATCH 33/68] Fix UID options --- .../ROOT/partials/configuration/suggestededits-options.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/partials/configuration/suggestededits-options.adoc b/modules/ROOT/partials/configuration/suggestededits-options.adoc index 9c981f1dda..ba27189681 100644 --- a/modules/ROOT/partials/configuration/suggestededits-options.adoc +++ b/modules/ROOT/partials/configuration/suggestededits-options.adoc @@ -1,5 +1,5 @@ -include::partial$configuration/userlookup_user_id.adoc[] -include::partial$configuration/userlookup_fetch_users.adoc[] +include::partial$configuration/suggestededits_user_id.adoc[] +include::partial$configuration/suggestededits_fetch_users.adoc[] include::partial$configuration/suggestededits_model.adoc[] include::partial$configuration/suggestededits_content.adoc[] include::partial$configuration/suggestededits_access.adoc[] From 6db05728d5add729cf6a17233efb34ce5d08a576 Mon Sep 17 00:00:00 2001 From: MitchCTiny Date: Thu, 19 Jun 2025 11:36:27 +1000 Subject: [PATCH 34/68] DOC-3174: Adding icons --- antora-playbook.yml | 2 +- antora.yml | 2 +- modules/ROOT/images/icons/checkmark-filled.svg | 3 +++ modules/ROOT/images/icons/close-filled.svg | 3 +++ modules/ROOT/images/icons/feedback.svg | 3 +++ modules/ROOT/images/icons/suggestededits-badge.svg | 1 + modules/ROOT/images/icons/suggestededits.svg | 5 +++++ modules/ROOT/partials/configuration/icon_list.adoc | 5 +++++ 8 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 modules/ROOT/images/icons/checkmark-filled.svg create mode 100644 modules/ROOT/images/icons/close-filled.svg create mode 100644 modules/ROOT/images/icons/feedback.svg create mode 100644 modules/ROOT/images/icons/suggestededits-badge.svg create mode 100644 modules/ROOT/images/icons/suggestededits.svg diff --git a/antora-playbook.yml b/antora-playbook.yml index 1ff597c1d2..94ce607ae1 100644 --- a/antora-playbook.yml +++ b/antora-playbook.yml @@ -8,7 +8,7 @@ content: branches: HEAD start_path: ./ - url: https://github.com/tinymce/tinymce-docs.git - branches: [ tinymce/5, tinymce/6, tinymce/7] + branches: [ tinymce/5, tinymce/6, tinymce/7 ] urls: html_extension_style: indexify latest_version_segment: latest diff --git a/antora.yml b/antora.yml index b7016d5189..1c000e450b 100644 --- a/antora.yml +++ b/antora.yml @@ -10,7 +10,7 @@ asciidoc: 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://internal-preview.tiny.work/epic/EPIC-134/tinymce.min.js + tinymce_live_demo_url: https://cdn.tiny.cloud/1/qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc/tinymce/8-dev/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/dist/tinymce-webcomponent.min.js jquery_url: https://cdn.jsdelivr.net/npm/@tinymce/tinymce-jquery@2/dist/tinymce-jquery.min.js diff --git a/modules/ROOT/images/icons/checkmark-filled.svg b/modules/ROOT/images/icons/checkmark-filled.svg new file mode 100644 index 0000000000..5fb476da1d --- /dev/null +++ b/modules/ROOT/images/icons/checkmark-filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/modules/ROOT/images/icons/close-filled.svg b/modules/ROOT/images/icons/close-filled.svg new file mode 100644 index 0000000000..f4362e0de8 --- /dev/null +++ b/modules/ROOT/images/icons/close-filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/modules/ROOT/images/icons/feedback.svg b/modules/ROOT/images/icons/feedback.svg new file mode 100644 index 0000000000..8aefd52267 --- /dev/null +++ b/modules/ROOT/images/icons/feedback.svg @@ -0,0 +1,3 @@ + + + diff --git a/modules/ROOT/images/icons/suggestededits-badge.svg b/modules/ROOT/images/icons/suggestededits-badge.svg new file mode 100644 index 0000000000..4c1409ca15 --- /dev/null +++ b/modules/ROOT/images/icons/suggestededits-badge.svg @@ -0,0 +1 @@ + diff --git a/modules/ROOT/images/icons/suggestededits.svg b/modules/ROOT/images/icons/suggestededits.svg new file mode 100644 index 0000000000..dbd5bb6d0f --- /dev/null +++ b/modules/ROOT/images/icons/suggestededits.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/modules/ROOT/partials/configuration/icon_list.adoc b/modules/ROOT/partials/configuration/icon_list.adoc index c8a777f63d..69835f6847 100644 --- a/modules/ROOT/partials/configuration/icon_list.adoc +++ b/modules/ROOT/partials/configuration/icon_list.adoc @@ -37,11 +37,13 @@ | `+checklist-rtl+` | image:icons/checklist-rtl.svg[checklist-rtl.svg] | `+checklist-rtl.svg+` | `+checklist+` | image:icons/checklist.svg[checklist.svg] | `+checklist.svg+` | `+checkmark+` | image:icons/checkmark.svg[checkmark.svg] | `+checkmark.svg+` +| `+checkmark-filled+` | image:icons/checkmark-filled.svg[checkmark-filled.svg] | `+checkmark-filled.svg+` | `+chevron-down+` | image:icons/chevron-down.svg[chevron-down.svg] | `+chevron-down.svg+` | `+chevron-left+` | image:icons/chevron-left.svg[chevron-left.svg] | `+chevron-left.svg+` | `+chevron-right+` | image:icons/chevron-right.svg[chevron-right.svg] | `+chevron-right.svg+` | `+chevron-up+` | image:icons/chevron-up.svg[chevron-up.svg] | `+chevron-up.svg+` | `+close+` | image:icons/close.svg[close.svg] | `+close.svg+` +| `+close-filled+` | image:icons/close-filled.svg[close-filled.svg] | `+close-filled.svg+` | `+code-sample+` | image:icons/code-sample.svg[code-sample.svg] | `+code-sample.svg+` | `+color-levels+` | image:icons/color-levels.svg[color-levels.svg] | `+color-levels.svg+` | `+color-picker+` | image:icons/color-picker.svg[color-picker.svg] | `+color-picker.svg+` @@ -71,6 +73,7 @@ | `+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+` +| `+feedback+` | image:icons/feedback.svg[feedback.svg] | `+feedback.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+` @@ -176,6 +179,8 @@ | `+strike-through+` | image:icons/strike-through.svg[strike-through.svg] | `+strike-through.svg+` | `+subscript+` | image:icons/subscript.svg[subscript.svg] | `+subscript.svg+` | `+superscript+` | image:icons/superscript.svg[superscript.svg] | `+superscript.svg+` +| `+suggestededits+` | image:icons/suggestededits.svg[suggestededits.svg] | `+suggestededits.svg+` +| `+suggestededits-badge+` | image:icons/suggestededits-badge.svg[suggestededits-badge.svg] | `+suggestededits-badge.svg+` | `+table-caption+` | image:icons/table-caption.svg[table-caption.svg] | `+table-caption.svg+` | `+table-cell-classes+` | image:icons/table-cell-classes.svg[table-cell-classes.svg] | `+table-cell-classes.svg+` | `+table-cell-properties+` | image:icons/table-cell-properties.svg[table-cell-properties.svg] | `+table-cell-properties.svg+` From ef516e7eca9fe85a1c20cdd88ed760ca17231fc9 Mon Sep 17 00:00:00 2001 From: kimwoodfield Date: Wed, 2 Jul 2025 09:43:55 +1000 Subject: [PATCH 35/68] DOC-3174: Add `Using the User Lookup API` page --- modules/ROOT/nav.adoc | 1 + modules/ROOT/pages/userlookup.adoc | 185 +++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 modules/ROOT/pages/userlookup.adoc diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc index 54407f44b0..e62abddba1 100644 --- a/modules/ROOT/nav.adoc +++ b/modules/ROOT/nav.adoc @@ -62,6 +62,7 @@ *** xref:localize-your-language.adoc[Localization] *** xref:spell-checking.adoc[Spell checking] *** xref:editor-content-css.adoc[CSS for rendering content] +*** xref:userlookup.adoc[Using the UserLookup API] ** Environment setup guides *** React framework **** xref:react-cloud.adoc[Using the Tiny Cloud] diff --git a/modules/ROOT/pages/userlookup.adoc b/modules/ROOT/pages/userlookup.adoc new file mode 100644 index 0000000000..3a2bd02711 --- /dev/null +++ b/modules/ROOT/pages/userlookup.adoc @@ -0,0 +1,185 @@ += Using the User Lookup API +:description: TinyMCE User Lookup provides an API to identify the current user and retrieve user details via integration-defined methods. +:keywords: userLookup, fetchUsers, userId, avatar, user metadata + +The {productname} User Lookup API enables integrations to retrieve and cache user details (such as names and avatars) and identify the current user within the editor. + +This is useful when building features that rely on user context, such as commenting, or displaying a list of elements container user information, and lets you manage user data efficiently with built-in caching. + +== Using the User Lookup API + +Follow the steps below to configure and use the `userLookup` API within your integration. + +[[step-1-set-the-current-user]] +=== 1. Set the current user ID + +The first step is to tell the editor which user is currently active. This is done using the `+user_id+` initialization option. + +[source,js] +---- +tinymce.init({ + selector: '#editor', + user_id: 'user-42', // <1> + // ... +}); +---- +**This ID will be used as the value of `+editor.userLookup.userId+`.** + +To access it: + +[source,js] +---- +editor.on('init', () => { + console.log('Current user:', editor.userLookup.userId); +}); +---- + +[[step-2-provide-a-user-fetcher]] +=== 2. Provide a function to fetch user details + +To simulate a backend lookup, define a local object that maps user IDs to their corresponding data. + +[source,js] +---- +const userDirectory = { + 'user-1': { id: 'user-1', name: 'Jane Doe', avatar: 'https://example.com/avatar/jane.png' }, + 'user-2': { id: 'user-2', name: 'John Smith' }, + 'user-42': { id: 'user-42', name: 'Alex Taylor', avatar: 'https://example.com/avatar/alex.png' } +}; + +tinymce.init({ + selector: '#editor', + user_id: 'user-42', + fetch_users: (userIds) => { + const results = userIds.map((id) => { + const user = Object.values(userDirectory).find((user) => user.id === id); + if (user) { + return user; + } else { + throw new Error(`User ${id} not found`); + } + }); + return Promise.resolve(results); + } +}); +---- + +This example demonstrates how to simulate user lookup in-browser. In a production environment, this function could be swapped out for a network request. + +The returned array should include objects with: + +* `id` (string) - Required +* `name` (string) - Optional (defaults to `id`) +* `avatar` (string, URL or data URI) - Optional (auto-generated SVG fallback if missing) +* `custom` (object) - Optional metadata + +[[step-3-fetch-user-information]] +=== 3. Fetch user information + +Once the editor is initialized, use the API to look up multiple users: + +[source,js] +---- +editor.on('init', () => { + const users = editor.userLookup.fetchUsers(['user-1', 'user-2']); + + users['user-1'].then((user) => { + console.log('User 1 name:', user.name); + }); + + Promise.all(Object.values(users)).then((allUsers) => { + allUsers.forEach((user) => { + console.log(`Fetched: ${user.name} (${user.id})`); + }); + }); +}); +---- + +NOTE: All lookups are cached. If a user has already been fetched, the same promise will be returned without calling `fetch_users` again. + +[[step-4-handle-missing-or-default-users]] +=== 4. Handle default users if `fetch_users` is not provided + +If no `fetch_users` function is configured, TinyMCE will return fallback users: + +* `name` will default to the ID +* `avatar` will be a generated SVG using the first letter of the name + +This is useful for simpler setups or prototyping. + +[source,js] +---- +tinymce.init({ + selector: '#editor', + user_id: 'anonymous-guest' +}); + +editor.on('init', () => { + const users = editor.userLookup.fetchUsers(['anonymous-guest']); + users['anonymous-guest'].then((user) => { + console.log('Generated fallback user:', user); + }); +}); +---- + +[[step-5-integrate-user-lookup-in-a-ui]] +=== 5. Integrate User Lookup in a UI Button (Optional) + +Here's how you might use the API to show the current user's name via a toolbar button. + +[source,js] +---- +setup: (editor) => { + editor.ui.registry.addButton('show-user', { + text: 'Show User', + onAction: () => { + const currentUser = editor.userLookup.userId; + const users = editor.userLookup.fetchUsers([currentUser]); + + users[currentUser].then((user) => { + editor.notificationManager.open({ + text: `Logged in as: ${user.name}`, + type: 'info' + }); + }); + } + }); +} +---- + +Then add this to your toolbar: + +[source,js] +---- +toolbar: 'show-user' +---- + +[[summary]] +== Summary + +The `userLookup` API provides two main functions: + +[cols="2,4",options="header"] +|=== +|Function|Description + +|`editor.userLookup.userId`|Returns the current user’s ID, set via the `user_id` option. +|`editor.userLookup.fetchUsers(userIds)`|Fetches and caches user information from a backend. +|=== + +== Example User Object + +Each returned user object from `fetchUsers()` has the following structure: + +[source,js] +---- +{ + id: 'user-1', + name: 'Jane Doe', + avatar: 'https://example.com/jane.png', + custom: { + role: 'admin', + department: 'engineering' + } +} +---- From 4a826c59bfd27911d3a28aeb5a9974af4d526946 Mon Sep 17 00:00:00 2001 From: Sorita Heng Date: Wed, 2 Jul 2025 11:07:16 +1000 Subject: [PATCH 36/68] Update UID options partials --- .../ROOT/pages/apis/tinymce.userlookup.adoc | 142 ++++++++++++++++++ ...dits_fetch_users.adoc => fetch_users.adoc} | 4 +- .../configuration/suggestededits-options.adoc | 4 +- .../configuration/suggestededits_user_id.adoc | 17 --- .../ROOT/partials/configuration/user_id.adoc | 15 ++ 5 files changed, 160 insertions(+), 22 deletions(-) create mode 100644 modules/ROOT/pages/apis/tinymce.userlookup.adoc rename modules/ROOT/partials/configuration/{suggestededits_fetch_users.adoc => fetch_users.adoc} (61%) delete mode 100644 modules/ROOT/partials/configuration/suggestededits_user_id.adoc create mode 100644 modules/ROOT/partials/configuration/user_id.adoc diff --git a/modules/ROOT/pages/apis/tinymce.userlookup.adoc b/modules/ROOT/pages/apis/tinymce.userlookup.adoc new file mode 100644 index 0000000000..d22d33e10f --- /dev/null +++ b/modules/ROOT/pages/apis/tinymce.userlookup.adoc @@ -0,0 +1,142 @@ += tinymce.UserLookup +:navtitle: tinymce.UserLookup +:description: This is the user lookup api. +:keywords: user lookup, fetchUsers() +:moxie-type: api + +This is the user lookup API. + +== Summary + +Provides user lookup capabilities for TinyMCE. Used to retrieve and cache user information via API, typically passed as `fetch_users` in the config. + +== Properties + +[cols="1,1,3", options="header"] +|=== +| Name | Type | Summary + +| userId +| String +| Current user's ID for the TinyMCE editor instance + +|=== + +== Methods + +[cols="1,3", options="header"] +|=== +| Name | Summary + +| fetchUsers() +| Retrieves and caches user information for specified user IDs, returning an array of promises + +|=== + +=== fetchUsers(userIds: Array): Promise + +Retrieves and caches user information for the specified user IDs, returning an array of promises. + +.Parameters +[cols="1,3", options="header"] +|=== +| Parameter | Description + +| userIds (Array) +| An array of user IDs to fetch information for. + +|=== + +== Using the UserLookup API + +=== 1. Configuring `fetch_users` + +`fetch_users` must be provided when initializing TinyMCE. It receives an array of IDs and must return a Promise resolving to an array of user objects. + +.Example: +[source,js] +---- +tinymce.init({ + selector: 'textarea', + user_id: 'current-user-id', + /** + * @param {string[]} ids + * @returns {Promise>} + */ + fetch_users: (ids) => fetch(`/api/users?ids=${ids.join(',')}`) + .then((r) => r.json()) +}); +---- + +=== 2. Accessing the Current User ID + +[source,js] +---- +const editor = tinymce.activeEditor; +console.log('Logged in as', editor.userLookup.userId); +---- + +=== 3. Retrieving User Information + +[source,js] +---- +const [ meP, colleagueP ] = editor.userLookup.fetchUsers([ + editor.userLookup.userId, + 'user-42' +]); + +Promise.all([ meP, colleagueP ]) + .then(([ me, colleague ]) => { + console.log(`${me.name} is chatting with ${colleague.name}`); + }) + .catch(console.error); +---- + +=== 4. Caching & Concurrency + +- First request triggers `fetch_users` to query the external source. +- Subsequent requests for the same user ID reuse the cached Promise. + +=== 5. Error Handling + +- If `fetch_users` omits an ID, the corresponding Promise rejects with: + `"User not found"` +- Network or validation failures are propagated as rejected Promises. +- If `fetch_users` is not configured, `fetchUsers()` throws synchronously. + +=== 6. Custom Properties + +Custom user fields (e.g., roles, preferences, `createdAt`) can be included in the resolved object. These will be returned unchanged. + +== User Object Structure + +[cols="1,1,1,3", options="header"] +|=== +| Field | Type | Required | Description + +| id +| string +| Yes +| Unique user identifier + +| name +| string +| No +| Display name + +| avatar +| string +| No +| URL of the avatar image + +| description +| string +| No +| Short bio or description + +| custom +| object +| No +| Arbitrary metadata (roles, preferences, createdAt, etc.) + +|=== diff --git a/modules/ROOT/partials/configuration/suggestededits_fetch_users.adoc b/modules/ROOT/partials/configuration/fetch_users.adoc similarity index 61% rename from modules/ROOT/partials/configuration/suggestededits_fetch_users.adoc rename to modules/ROOT/partials/configuration/fetch_users.adoc index 39f7b42abe..35578cdf9c 100644 --- a/modules/ROOT/partials/configuration/suggestededits_fetch_users.adoc +++ b/modules/ROOT/partials/configuration/fetch_users.adoc @@ -1,7 +1,7 @@ [[fetch_users]] == `fetch_users` -A **required callback function** that fetches user data for the Suggested Edits view. This function is called with an array of user IDs and should return a `Promise` that resolves to an array of user objects. The callback is used by the xref:#userlookupapi[`UserLookup API`]. +A callback function that retrieves user data for the plugin. It receives an array of user IDs and returns a `Promise` resolving to an array of user objects. The callback uses the xref:#userlookupapi[`UserLookup API`]. *Type:* `Function` @@ -16,8 +16,6 @@ A **required callback function** that fetches user data for the Suggested Edits ---- tinymce.init({ selector: 'textarea', // Change this value according to your HTML - plugins: 'suggestededits', - toolbar: 'suggestededits', user_id: 'unique-identifier', // Replace this with a unique string to identify the user fetch_users: (ids) => fetch(`/api/users?ids=${ids.join(',')}`) .then((r) => r.json()) diff --git a/modules/ROOT/partials/configuration/suggestededits-options.adoc b/modules/ROOT/partials/configuration/suggestededits-options.adoc index ba27189681..dff06d1326 100644 --- a/modules/ROOT/partials/configuration/suggestededits-options.adoc +++ b/modules/ROOT/partials/configuration/suggestededits-options.adoc @@ -1,5 +1,5 @@ -include::partial$configuration/suggestededits_user_id.adoc[] -include::partial$configuration/suggestededits_fetch_users.adoc[] +include::partial$configuration/user_id.adoc[] +include::partial$configuration/fetch_users.adoc[] include::partial$configuration/suggestededits_model.adoc[] include::partial$configuration/suggestededits_content.adoc[] include::partial$configuration/suggestededits_access.adoc[] diff --git a/modules/ROOT/partials/configuration/suggestededits_user_id.adoc b/modules/ROOT/partials/configuration/suggestededits_user_id.adoc deleted file mode 100644 index 8f105f22c8..0000000000 --- a/modules/ROOT/partials/configuration/suggestededits_user_id.adoc +++ /dev/null @@ -1,17 +0,0 @@ -[[user_id]] -== `user_id` - -Required option to set the current user's unique ID in the editor, allowing the plugin to track changes made by this user and display them correctly in the Suggested Edits view. This option uses the xref:#userlookupapi[`UserLookup API`]. - -*Type:* `+String+` - -.Example -[source,javascript] ----- -tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - plugins: 'suggestededits', - toolbar: 'suggestededits', - user_id: 'unique-identifier' // replace this with a unique string to identify the user -}); ----- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/user_id.adoc b/modules/ROOT/partials/configuration/user_id.adoc new file mode 100644 index 0000000000..baba6cd210 --- /dev/null +++ b/modules/ROOT/partials/configuration/user_id.adoc @@ -0,0 +1,15 @@ +[[user_id]] +== `user_id` + +This option specifies a unique identifier for the current user, enabling the plugin to distinguish between different users in the editor. The option uses the xref:#userlookupapi[`UserLookup API`]. + +*Type:* `+String+` + +.Example +[source,javascript] +---- +tinymce.init({ + selector: 'textarea', // Change this value according to your HTML + user_id: 'unique-identifier' // replace this with a unique string to identify the user +}); +---- \ No newline at end of file From 61d2d7f83f25c6d347c2352540ef667c32453e39 Mon Sep 17 00:00:00 2001 From: MitchCTiny Date: Wed, 2 Jul 2025 13:33:40 +1000 Subject: [PATCH 37/68] DOC-3174: Some edits --- .../ROOT/pages/apis/tinymce.userlookup.adoc | 142 ------------------ modules/ROOT/pages/userlookup.adoc | 22 +-- .../partials/configuration/fetch_users.adoc | 5 +- .../configuration/suggestededits_content.adoc | 6 +- .../ROOT/partials/configuration/user_id.adoc | 9 +- 5 files changed, 20 insertions(+), 164 deletions(-) delete mode 100644 modules/ROOT/pages/apis/tinymce.userlookup.adoc diff --git a/modules/ROOT/pages/apis/tinymce.userlookup.adoc b/modules/ROOT/pages/apis/tinymce.userlookup.adoc deleted file mode 100644 index d22d33e10f..0000000000 --- a/modules/ROOT/pages/apis/tinymce.userlookup.adoc +++ /dev/null @@ -1,142 +0,0 @@ -= tinymce.UserLookup -:navtitle: tinymce.UserLookup -:description: This is the user lookup api. -:keywords: user lookup, fetchUsers() -:moxie-type: api - -This is the user lookup API. - -== Summary - -Provides user lookup capabilities for TinyMCE. Used to retrieve and cache user information via API, typically passed as `fetch_users` in the config. - -== Properties - -[cols="1,1,3", options="header"] -|=== -| Name | Type | Summary - -| userId -| String -| Current user's ID for the TinyMCE editor instance - -|=== - -== Methods - -[cols="1,3", options="header"] -|=== -| Name | Summary - -| fetchUsers() -| Retrieves and caches user information for specified user IDs, returning an array of promises - -|=== - -=== fetchUsers(userIds: Array): Promise - -Retrieves and caches user information for the specified user IDs, returning an array of promises. - -.Parameters -[cols="1,3", options="header"] -|=== -| Parameter | Description - -| userIds (Array) -| An array of user IDs to fetch information for. - -|=== - -== Using the UserLookup API - -=== 1. Configuring `fetch_users` - -`fetch_users` must be provided when initializing TinyMCE. It receives an array of IDs and must return a Promise resolving to an array of user objects. - -.Example: -[source,js] ----- -tinymce.init({ - selector: 'textarea', - user_id: 'current-user-id', - /** - * @param {string[]} ids - * @returns {Promise>} - */ - fetch_users: (ids) => fetch(`/api/users?ids=${ids.join(',')}`) - .then((r) => r.json()) -}); ----- - -=== 2. Accessing the Current User ID - -[source,js] ----- -const editor = tinymce.activeEditor; -console.log('Logged in as', editor.userLookup.userId); ----- - -=== 3. Retrieving User Information - -[source,js] ----- -const [ meP, colleagueP ] = editor.userLookup.fetchUsers([ - editor.userLookup.userId, - 'user-42' -]); - -Promise.all([ meP, colleagueP ]) - .then(([ me, colleague ]) => { - console.log(`${me.name} is chatting with ${colleague.name}`); - }) - .catch(console.error); ----- - -=== 4. Caching & Concurrency - -- First request triggers `fetch_users` to query the external source. -- Subsequent requests for the same user ID reuse the cached Promise. - -=== 5. Error Handling - -- If `fetch_users` omits an ID, the corresponding Promise rejects with: - `"User not found"` -- Network or validation failures are propagated as rejected Promises. -- If `fetch_users` is not configured, `fetchUsers()` throws synchronously. - -=== 6. Custom Properties - -Custom user fields (e.g., roles, preferences, `createdAt`) can be included in the resolved object. These will be returned unchanged. - -== User Object Structure - -[cols="1,1,1,3", options="header"] -|=== -| Field | Type | Required | Description - -| id -| string -| Yes -| Unique user identifier - -| name -| string -| No -| Display name - -| avatar -| string -| No -| URL of the avatar image - -| description -| string -| No -| Short bio or description - -| custom -| object -| No -| Arbitrary metadata (roles, preferences, createdAt, etc.) - -|=== diff --git a/modules/ROOT/pages/userlookup.adoc b/modules/ROOT/pages/userlookup.adoc index 3a2bd02711..7f18e7a3e3 100644 --- a/modules/ROOT/pages/userlookup.adoc +++ b/modules/ROOT/pages/userlookup.adoc @@ -15,15 +15,7 @@ Follow the steps below to configure and use the `userLookup` API within your int The first step is to tell the editor which user is currently active. This is done using the `+user_id+` initialization option. -[source,js] ----- -tinymce.init({ - selector: '#editor', - user_id: 'user-42', // <1> - // ... -}); ----- -**This ID will be used as the value of `+editor.userLookup.userId+`.** +include::partial$configuration/user_id.adoc[leveloffset=+2] To access it: @@ -37,19 +29,21 @@ editor.on('init', () => { [[step-2-provide-a-user-fetcher]] === 2. Provide a function to fetch user details -To simulate a backend lookup, define a local object that maps user IDs to their corresponding data. +To simulate a backend lookup, define a local object that maps user IDs to their corresponding data. + +include::partial$configuration/fetch_users.adoc[] [source,js] ---- const userDirectory = { - 'user-1': { id: 'user-1', name: 'Jane Doe', avatar: 'https://example.com/avatar/jane.png' }, - 'user-2': { id: 'user-2', name: 'John Smith' }, - 'user-42': { id: 'user-42', name: 'Alex Taylor', avatar: 'https://example.com/avatar/alex.png' } + 'janedoe': { id: 'janedoe', name: 'Jane Doe', avatar: 'https://example.com/avatar/jane.png' }, + 'johnsmith': { id: 'johnsmith', name: 'John Smith' }, + 'alextaylor': { id: 'alextaylor', name: 'Alex Taylor', avatar: 'https://example.com/avatar/alex.png' } }; tinymce.init({ selector: '#editor', - user_id: 'user-42', + user_id: 'alextaylor', fetch_users: (userIds) => { const results = userIds.map((id) => { const user = Object.values(userDirectory).find((user) => user.id === id); diff --git a/modules/ROOT/partials/configuration/fetch_users.adoc b/modules/ROOT/partials/configuration/fetch_users.adoc index 35578cdf9c..478c875cc2 100644 --- a/modules/ROOT/partials/configuration/fetch_users.adoc +++ b/modules/ROOT/partials/configuration/fetch_users.adoc @@ -1,7 +1,7 @@ [[fetch_users]] == `fetch_users` -A callback function that retrieves user data for the plugin. It receives an array of user IDs and returns a `Promise` resolving to an array of user objects. The callback uses the xref:#userlookupapi[`UserLookup API`]. +A **required callback function** that fetches user data for the Suggested Edits view. This function is called with an array of user IDs and should return a `Promise` that resolves to an array of user objects. The callback is used by the xref:userlookup.adoc[`UserLookup`] API. *Type:* `Function` @@ -11,7 +11,8 @@ A callback function that retrieves user data for the plugin. It receives an arra *Returns:* - `Promise>`: A promise that resolves to an array of user objects. -.Example +=== Example: using `fetch_users` option + [source,javascript] ---- tinymce.init({ diff --git a/modules/ROOT/partials/configuration/suggestededits_content.adoc b/modules/ROOT/partials/configuration/suggestededits_content.adoc index d29e11fc57..6bf6fb53df 100644 --- a/modules/ROOT/partials/configuration/suggestededits_content.adoc +++ b/modules/ROOT/partials/configuration/suggestededits_content.adoc @@ -1,10 +1,10 @@ [[suggestededits_content]] == `suggestededits_content` -The `{plugincode}_content` option determines where the initial content of the document is loaded from. With this option, you can set the content to be loaded from either the editor or the model, allowing you to control the source of truth for the document. +The `suggestededits_content` option determines where the initial content of the document is loaded from. With this option, you can set the content to be loaded from either the editor or the model, allowing you to control the source of truth for the document. When set to `'html'`, the editor loads the initial content from the HTML in the textarea or the `content` property. In this case, if a model is provided, it will need to match the content in the editor for the plugin to work correctly -When set to `'model'`, the editor loads the initial content from the `{plugincode}_model` option. In this case, the content in the editor will be overwritten with the content from the model. This would allow you to only require the model for document tracking, though it is still recommended to save the content in the editor externally. +When set to `'model'`, the editor loads the initial content from the `suggestededits_model` option. In this case, the content in the editor will be overwritten with the content from the model. This would allow you to only require the model for document tracking, though it is still recommended to save the content in the editor externally. In either case, if a model is not provided, the plugin will generate a new model from the current content of the editor, whether it is empty or not. @@ -14,7 +14,7 @@ In either case, if a model is not provided, the plugin will generate a new model *Default value:* `'html'` -=== Example: using `{plugincode}_content` +=== Example: using `suggestededits_content` [source,js] ---- diff --git a/modules/ROOT/partials/configuration/user_id.adoc b/modules/ROOT/partials/configuration/user_id.adoc index baba6cd210..04b8f599b8 100644 --- a/modules/ROOT/partials/configuration/user_id.adoc +++ b/modules/ROOT/partials/configuration/user_id.adoc @@ -1,15 +1,18 @@ [[user_id]] == `user_id` -This option specifies a unique identifier for the current user, enabling the plugin to distinguish between different users in the editor. The option uses the xref:#userlookupapi[`UserLookup API`]. +This option sets the unique identifier for the current user in the editor. It is used in the the xref:userlookup.adoc[`UserLookup`] API. *Type:* `+String+` -.Example +*Default value:* `'Anonymous'` + +=== Example: using `user_id` option + [source,javascript] ---- tinymce.init({ selector: 'textarea', // Change this value according to your HTML - user_id: 'unique-identifier' // replace this with a unique string to identify the user + user_id: 'alextaylor' // replace this with a unique string to identify the user }); ---- \ No newline at end of file From ba633dcbcf53bf0b357e4565d2f86801a299bd99 Mon Sep 17 00:00:00 2001 From: kimwoodfield Date: Fri, 4 Jul 2025 09:34:18 +1000 Subject: [PATCH 38/68] DOC-3174: Add `UserLookup` partials to `revisionhistory` and `tinycomments` pages --- .../ROOT/pages/comments-embedded-mode.adoc | 4 +++ modules/ROOT/pages/revisionhistory.adoc | 4 +++ .../DEPRECATED/generic_8_userlookup.adoc | 1 + .../partials/configuration/fetch_users.adoc | 25 +++++++++++++++---- .../configuration/revisionhistory_author.adoc | 2 ++ .../configuration/tinycomments_author.adoc | 2 ++ .../tinycomments_author_avatar.adoc | 2 ++ .../tinycomments_author_name.adoc | 2 ++ .../ROOT/partials/configuration/user_id.adoc | 2 +- 9 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 modules/ROOT/partials/DEPRECATED/generic_8_userlookup.adoc diff --git a/modules/ROOT/pages/comments-embedded-mode.adoc b/modules/ROOT/pages/comments-embedded-mode.adoc index f0f8c1fa6f..cd50daa629 100644 --- a/modules/ROOT/pages/comments-embedded-mode.adoc +++ b/modules/ROOT/pages/comments-embedded-mode.adoc @@ -30,6 +30,10 @@ liveDemo::comments-embedded[] == Options +include::partial$configuration/user_id.adoc[leveloffset=+1] + +include::partial$configuration/fetch_users.adoc[leveloffset=+1] + include::partial$configuration/tinycomments_author.adoc[leveloffset=+1] include::partial$configuration/tinycomments_author_avatar.adoc[leveloffset=+1] diff --git a/modules/ROOT/pages/revisionhistory.adoc b/modules/ROOT/pages/revisionhistory.adoc index 287e7cd506..0df0343897 100644 --- a/modules/ROOT/pages/revisionhistory.adoc +++ b/modules/ROOT/pages/revisionhistory.adoc @@ -109,6 +109,10 @@ include::partial$configuration/revisionhistory_fetch_revision.adoc[leveloffset=+ include::partial$configuration/revisionhistory_allow_restore.adoc[leveloffset=+1] +include::partial$configuration/user_id.adoc[leveloffset=+1] + +include::partial$configuration/fetch_users.adoc[leveloffset=+1] + include::partial$configuration/revisionhistory_author.adoc[leveloffset=+1] include::partial$configuration/revisionhistory_display_author.adoc[leveloffset=+1] diff --git a/modules/ROOT/partials/DEPRECATED/generic_8_userlookup.adoc b/modules/ROOT/partials/DEPRECATED/generic_8_userlookup.adoc new file mode 100644 index 0000000000..c7757b6111 --- /dev/null +++ b/modules/ROOT/partials/DEPRECATED/generic_8_userlookup.adoc @@ -0,0 +1 @@ +IMPORTANT: This option has been deprecated in {productname} 8.0 and may be removed in a future major {productname} release. Use a combination of `user_id` and `fetch_users` instead. | `xref:apis/tinymce.editor.userlookup.adoc[UserLookup]` diff --git a/modules/ROOT/partials/configuration/fetch_users.adoc b/modules/ROOT/partials/configuration/fetch_users.adoc index 478c875cc2..bc86db7fb6 100644 --- a/modules/ROOT/partials/configuration/fetch_users.adoc +++ b/modules/ROOT/partials/configuration/fetch_users.adoc @@ -1,7 +1,7 @@ [[fetch_users]] == `fetch_users` -A **required callback function** that fetches user data for the Suggested Edits view. This function is called with an array of user IDs and should return a `Promise` that resolves to an array of user objects. The callback is used by the xref:userlookup.adoc[`UserLookup`] API. +A **required callback function** that fetches user data. This function is called with an array of user IDs and should return a `Promise` that resolves to an array of user objects. The callback is used by the xref:userlookup.adoc[`UserLookup`] API. *Type:* `Function` @@ -15,10 +15,25 @@ A **required callback function** that fetches user data for the Suggested Edits [source,javascript] ---- +const userDirectory = { + 'janedoe': { id: 'janedoe', name: 'Jane Doe', avatar: 'https://example.com/avatar/jane.png' }, + 'johnsmith': { id: 'johnsmith', name: 'John Smith' }, + 'alextaylor': { id: 'alextaylor', name: 'Alex Taylor', avatar: 'https://example.com/avatar/alex.png' } +}; + tinymce.init({ - selector: 'textarea', // Change this value according to your HTML - user_id: 'unique-identifier', // Replace this with a unique string to identify the user - fetch_users: (ids) => fetch(`/api/users?ids=${ids.join(',')}`) - .then((r) => r.json()) + selector: '#editor', + user_id: 'alextaylor', + fetch_users: (userIds) => { + const results = userIds.map((id) => { + const user = Object.values(userDirectory).find((user) => user.id === id); + if (user) { + return user; + } else { + throw new Error(`User ${id} not found`); + } + }); + return Promise.resolve(results); + } }); ---- \ No newline at end of file diff --git a/modules/ROOT/partials/configuration/revisionhistory_author.adoc b/modules/ROOT/partials/configuration/revisionhistory_author.adoc index 5e9d867c4e..35978bbf7d 100644 --- a/modules/ROOT/partials/configuration/revisionhistory_author.adoc +++ b/modules/ROOT/partials/configuration/revisionhistory_author.adoc @@ -1,6 +1,8 @@ [[revisionhistory_author]] == `revisionhistory_author` +include::partial$DEPRECATED/generic_8_userlookup.adoc[] + This option configures the author for the `initial` and `draft` revisions. *Type:* xref:#author[Author] `+Object+` diff --git a/modules/ROOT/partials/configuration/tinycomments_author.adoc b/modules/ROOT/partials/configuration/tinycomments_author.adoc index 2fd8b7f9a1..cd88b59723 100644 --- a/modules/ROOT/partials/configuration/tinycomments_author.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_author.adoc @@ -1,6 +1,8 @@ [[tinycomments_author]] == `+tinycomments_author+` +include::partial$DEPRECATED/generic_8_userlookup.adoc[] + This option sets the author id to be used when creating or replying to comments. *Type:* `+String+` diff --git a/modules/ROOT/partials/configuration/tinycomments_author_avatar.adoc b/modules/ROOT/partials/configuration/tinycomments_author_avatar.adoc index a36c4b990c..e9cb63768d 100644 --- a/modules/ROOT/partials/configuration/tinycomments_author_avatar.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_author_avatar.adoc @@ -1,6 +1,8 @@ [[tinycomments_author_avatar]] == `+tinycomments_author_avatar+` +include::partial$DEPRECATED/generic_8_userlookup.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: * will be scaled to a 36px diameter circle; and diff --git a/modules/ROOT/partials/configuration/tinycomments_author_name.adoc b/modules/ROOT/partials/configuration/tinycomments_author_name.adoc index e13792222b..d1e459b17c 100644 --- a/modules/ROOT/partials/configuration/tinycomments_author_name.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_author_name.adoc @@ -1,6 +1,8 @@ [[tinycomments_author_name]] == `+tinycomments_author_name+` +include::partial$DEPRECATED/generic_8_userlookup.adoc[] + _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+` diff --git a/modules/ROOT/partials/configuration/user_id.adoc b/modules/ROOT/partials/configuration/user_id.adoc index 04b8f599b8..7ddc942d09 100644 --- a/modules/ROOT/partials/configuration/user_id.adoc +++ b/modules/ROOT/partials/configuration/user_id.adoc @@ -1,5 +1,5 @@ [[user_id]] -== `user_id` +== `+user_id+` This option sets the unique identifier for the current user in the editor. It is used in the the xref:userlookup.adoc[`UserLookup`] API. From da9ae91cfb641d62194fc2688c99752c1161f4f8 Mon Sep 17 00:00:00 2001 From: kimwoodfield Date: Wed, 9 Jul 2025 09:28:35 +1000 Subject: [PATCH 39/68] DOC-3174: Replace reference to `userDb` with `userinfos` --- modules/ROOT/examples/live-demos/suggestededits-access/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ROOT/examples/live-demos/suggestededits-access/index.js b/modules/ROOT/examples/live-demos/suggestededits-access/index.js index 88725bfd67..2063023699 100644 --- a/modules/ROOT/examples/live-demos/suggestededits-access/index.js +++ b/modules/ROOT/examples/live-demos/suggestededits-access/index.js @@ -24,7 +24,7 @@ const userinfos = { const fetch_users = (ids) => { return new Promise((resolve, reject) => { - const users = ids.map(id => userDb[id]); + const users = ids.map(id => userinfos[id]); if (users.length > 0) { resolve(users); } else { From 6da83e83f2314f1da5c8ca7cb0e1739888ac1369 Mon Sep 17 00:00:00 2001 From: kimwoodfield Date: Wed, 9 Jul 2025 10:18:23 +1000 Subject: [PATCH 40/68] DOC-3174: Remove usage of `uid` in `suggestededits` --- .../live-demos/suggestededits-access/index.js | 8 ++--- .../suggestededits-suggestions/index.js | 32 ++++++++++++------- .../live-demos/suggestededits/index.js | 16 +++++----- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/modules/ROOT/examples/live-demos/suggestededits-access/index.js b/modules/ROOT/examples/live-demos/suggestededits-access/index.js index 2063023699..6c8dd32358 100644 --- a/modules/ROOT/examples/live-demos/suggestededits-access/index.js +++ b/modules/ROOT/examples/live-demos/suggestededits-access/index.js @@ -1,22 +1,22 @@ /** Fake user database */ const userinfos = { adamhenderson: { - uid: 'adamhenderson', + id: 'adamhenderson', name: 'Adam Henderson', avatar: `https://randomuser.me/api/portraits/men/1.jpg`, }, michaelcook: { - uid: 'michaelcook', + id: 'michaelcook', name: 'Michael Cook', avatar: `https://randomuser.me/api/portraits/men/2.jpg`, }, kalebwilson: { - uid: 'kalebwilson', + id: 'kalebwilson', name: 'Kaleb Wilson', avatar: `https://randomuser.me/api/portraits/men/3.jpg`, }, kyleeinstein: { - uid: 'kyleeinstein', + id: 'kyleeinstein', name: 'Kyle Einstein', avatar: `https://randomuser.me/api/portraits/men/4.jpg`, }, diff --git a/modules/ROOT/examples/live-demos/suggestededits-suggestions/index.js b/modules/ROOT/examples/live-demos/suggestededits-suggestions/index.js index 0484a81b82..a95f462a59 100644 --- a/modules/ROOT/examples/live-demos/suggestededits-suggestions/index.js +++ b/modules/ROOT/examples/live-demos/suggestededits-suggestions/index.js @@ -1,38 +1,46 @@ /** Fake user database */ const userinfos = { adamhenderson: { - uid: 'adamhenderson', + id: 'adamhenderson', name: 'Adam Henderson', avatar: `https://randomuser.me/api/portraits/men/1.jpg`, }, michaelcook: { - uid: 'michaelcook', + id: 'michaelcook', name: 'Michael Cook', avatar: `https://randomuser.me/api/portraits/men/2.jpg`, }, kalebwilson: { - uid: 'kalebwilson', + id: 'kalebwilson', name: 'Kaleb Wilson', avatar: `https://randomuser.me/api/portraits/men/3.jpg`, }, kyleeinstein: { - uid: 'kyleeinstein', + id: 'kyleeinstein', name: 'Kyle Einstein', avatar: `https://randomuser.me/api/portraits/men/4.jpg`, }, }; -const trackchanges_user_lookup = (uid) => new Promise((resolve, reject) => - setTimeout(() => userinfos[uid] ? resolve(userinfos[uid]) : reject(), 1000)); +const fetch_users = (ids) => { + return new Promise((resolve, reject) => { + const users = ids.map(id => userinfos[id]); + if (users.length > 0) { + resolve(users); + } else { + reject(new Error('No users found')); + } + }); +} tinymce.init({ - selector: 'textarea#trackchanges_suggestions', + selector: 'textarea#suggestededits_suggestions', height: 500, - plugins: 'trackchanges', - toolbar: 'trackchanges', + plugins: 'suggestededits', + toolbar: 'suggestededits', content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', - trackchanges_uid: 'adamhenderson', - trackchanges_access: 'suggest', //change this value to set permission to the Suggested Edits view + user_id: 'adamhenderson', + suggestededits_access: 'feedback', //change this value to set permission to the Suggested Edits view readonly: false, //set to true to restrict a user's editing permission - trackchanges_user_lookup + fetch_users }); \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/suggestededits/index.js b/modules/ROOT/examples/live-demos/suggestededits/index.js index de48f9e9a2..2bdbf5038e 100644 --- a/modules/ROOT/examples/live-demos/suggestededits/index.js +++ b/modules/ROOT/examples/live-demos/suggestededits/index.js @@ -56,7 +56,7 @@ const model = { "_opData": { "id": 1, "type": "insert", - "uid": "adamhenderson", + "id": "adamhenderson", "timestamp": 1749214950000 } }, @@ -79,7 +79,7 @@ const model = { "_opData": { "id": 3, "type": "insert", - "uid": "adamhenderson", + "id": "adamhenderson", "timestamp": 1749215051000 } }, @@ -88,7 +88,7 @@ const model = { "_opData": { "id": 2, "type": "remove", - "uid": "adamhenderson", + "id": "adamhenderson", "timestamp": 1749215053000 } }, @@ -100,7 +100,7 @@ const model = { "_opData": { "id": 4, "type": "remove", - "uid": "adamhenderson", + "id": "adamhenderson", "timestamp": 1749215055000 } }, @@ -109,7 +109,7 @@ const model = { "_opData": { "id": 4, "type": "insert", - "uid": "adamhenderson", + "id": "adamhenderson", "timestamp": 1749215055000 } }, @@ -121,7 +121,7 @@ const model = { "_opData": { "id": 5, "type": "insert", - "uid": "adamhenderson", + "id": "adamhenderson", "timestamp": 1749215056000 } }, @@ -133,7 +133,7 @@ const model = { "_opData": { "id": 6, "type": "remove", - "uid": "adamhenderson", + "id": "adamhenderson", "timestamp": 1749215060000 } }, @@ -145,7 +145,7 @@ const model = { "_opData": { "id": 7, "type": "insert", - "uid": "adamhenderson", + "id": "adamhenderson", "timestamp": 1749215064000 } }, From 73b8ad2875449d540568c88245e778c3fff74f8d Mon Sep 17 00:00:00 2001 From: kimwoodfield Date: Wed, 9 Jul 2025 10:23:24 +1000 Subject: [PATCH 41/68] DOC-3174: Fix indentations within `Types of suggestions` --- modules/ROOT/pages/suggestededits.adoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/ROOT/pages/suggestededits.adoc b/modules/ROOT/pages/suggestededits.adoc index b0751193a7..3452f67af2 100644 --- a/modules/ROOT/pages/suggestededits.adoc +++ b/modules/ROOT/pages/suggestededits.adoc @@ -56,16 +56,16 @@ The sidebar also displays all tracked changes that need to be resolved. Each cha There are four basic types of suggestions that are tracked by the Suggested Edits plugin: -==== Insert +=== Insert Tracks the addition of new content to the document. -==== Modify +=== Modify Tracks HTML attribute changes or formatting changes to existing content, such as bold or italic text. Note that if multiple users modify the same content, the original author will still be attributed with the change. -==== Delete +=== Delete Tracks the removal of content from the document. -==== Replace +=== Replace Tracks the replacement of existing content with new content. This is treated as a combination of a delete and an insert, where the original content is selected and replaced by new content. Note that if multiple users replace the same content, the most recent author will be attributed with the change. == Initial setup From b05d7dddde47589857e02940ba06499b662a64b6 Mon Sep 17 00:00:00 2001 From: kimwoodfield Date: Thu, 10 Jul 2025 09:46:59 +1000 Subject: [PATCH 42/68] DOC-3174: Update interactive demos and examples for `embedded` mode in `tinycomments` --- .../live-demos/comments-embedded/index.js | 2 +- .../ROOT/pages/comments-embedded-mode.adoc | 24 ++++++++++++++++--- .../tinycomments_can_delete.adoc | 6 ++--- .../tinycomments_can_delete_comment.adoc | 6 ++--- .../tinycomments_can_edit_comment.adoc | 6 ++--- .../tinycomments_can_resolve.adoc | 2 +- .../plugins/comments-open-sidebar.adoc | 2 +- 7 files changed, 33 insertions(+), 15 deletions(-) diff --git a/modules/ROOT/examples/live-demos/comments-embedded/index.js b/modules/ROOT/examples/live-demos/comments-embedded/index.js index d0aa9d9c21..6514394809 100644 --- a/modules/ROOT/examples/live-demos/comments-embedded/index.js +++ b/modules/ROOT/examples/live-demos/comments-embedded/index.js @@ -16,7 +16,7 @@ tinymce.init({ quickbars_image_toolbar: 'alignleft aligncenter alignright | rotateleft rotateright | imageoptions', tinycomments_mode: 'embedded', sidebar_show: 'showcomments', - tinycomments_author: currentAuthor, + user_id: currentAuthor, tinycomments_can_resolve: (req, done, fail) => { const allowed = req.comments.length > 0 && req.comments[0].author === currentAuthor; diff --git a/modules/ROOT/pages/comments-embedded-mode.adoc b/modules/ROOT/pages/comments-embedded-mode.adoc index cd50daa629..33ec7af23b 100644 --- a/modules/ROOT/pages/comments-embedded-mode.adoc +++ b/modules/ROOT/pages/comments-embedded-mode.adoc @@ -11,17 +11,35 @@ To add the {pluginname} plugin in embedded mode to the {productname}, configure [source,js] ---- +const userDirectory = { + 'author': { + id: 'author', + name: 'Name of the commenter', + avatar: 'https://example.com/avatar/john.png' + }, +}; + 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', + user_id: 'author', + fetch_users: (userIds) => { + const results = userIds.map((id) => { + const user = Object.values(userDirectory).find((user) => user.id === id); + if (user) { + return user; + } else { + throw new Error(`User ${id} not found`); + } + }); + return Promise.resolve(results); + }, tinycomments_mode: 'embedded' }); ---- -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_". +This is the minimum recommended setup for the {pluginname} plugin in embedded mode. If the `+user_id+` or `+tinycomments_author+` options are not configured, all users will be assigned the name "_ANON_". [[comments-embedded-live-demo]] == Interactive example diff --git a/modules/ROOT/partials/configuration/tinycomments_can_delete.adoc b/modules/ROOT/partials/configuration/tinycomments_can_delete.adoc index d4b795e43c..1343742668 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 (`+user_id+`) cannot delete comment conversations created by other authors. *Type:* `+Function+` @@ -9,7 +9,7 @@ _Optional_: This option sets the author permissions for _deleting comment conver [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 }); @@ -30,7 +30,7 @@ tinymce.init({ plugins: 'tinycomments', toolbar: 'addcomment showcomments', tinycomments_mode: 'embedded', - tinycomments_author: currentAuthor, + user_id: currentAuthor, tinycomments_can_delete: (req, done, fail) => { const allowed = req.comments.length > 0 && req.comments[0].author === currentAuthor; done({ diff --git a/modules/ROOT/partials/configuration/tinycomments_can_delete_comment.adoc b/modules/ROOT/partials/configuration/tinycomments_can_delete_comment.adoc index 3d7f0e6be5..ad5cacfd63 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 (`+user_id+`) **cannot** delete comments added by other authors. *Type:* `+Function+` @@ -9,7 +9,7 @@ _Optional_: This option sets the author permissions for _deleting comments_. If [source,js] ---- (req, done, fail) => { - const allowed = req.comment.author === ; + const allowed = req.comment.author === ; done({ canDelete: allowed }); @@ -30,7 +30,7 @@ tinymce.init({ plugins: 'tinycomments', toolbar: 'addcomment showcomments', tinycomments_mode: 'embedded', - tinycomments_author: currentAuthor, + user_id: currentAuthor, tinycomments_can_delete_comment: (req, done, fail) => { const allowed = req.comment.author === currentAuthor; done({ diff --git a/modules/ROOT/partials/configuration/tinycomments_can_edit_comment.adoc b/modules/ROOT/partials/configuration/tinycomments_can_edit_comment.adoc index dcf1339e64..cecf188172 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 (`+user_id+`) cannot edit comments added by other authors. *Type:* `+Function+` @@ -9,7 +9,7 @@ _Optional_: This option sets the author permissions for _editing comments_. If t [source,js] ---- (req, done, fail) => { - const allowed = req.comment.author === ; + const allowed = req.comment.author === ; done({ canEdit: allowed }); @@ -29,7 +29,7 @@ tinymce.init({ plugins: 'tinycomments', toolbar: 'addcomment showcomments', tinycomments_mode: 'embedded', - tinycomments_author: currentAuthor, + user_id: currentAuthor, tinycomments_can_edit_comment: (req, done, fail) => { const allowed = req.comment.author === currentAuthor; done({ diff --git a/modules/ROOT/partials/configuration/tinycomments_can_resolve.adoc b/modules/ROOT/partials/configuration/tinycomments_can_resolve.adoc index 491cb7ba97..5873857e0b 100644 --- a/modules/ROOT/partials/configuration/tinycomments_can_resolve.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_can_resolve.adoc @@ -16,7 +16,7 @@ tinymce.init({ plugins: 'tinycomments', toolbar: 'addcomment showcomments', tinycomments_mode: 'embedded', - tinycomments_author: currentAuthor, + user_id: currentAuthor, tinycomments_can_resolve: (req, done, fail) => { const allowed = req.comments.length > 0 && req.comments[0].author === currentAuthor; done({ diff --git a/modules/ROOT/partials/plugins/comments-open-sidebar.adoc b/modules/ROOT/partials/plugins/comments-open-sidebar.adoc index 03cbc525aa..ce46de407e 100644 --- a/modules/ROOT/partials/plugins/comments-open-sidebar.adoc +++ b/modules/ROOT/partials/plugins/comments-open-sidebar.adoc @@ -30,7 +30,7 @@ tinymce.init({ selector: 'textarea', // change this value according to your html plugins: 'tinycomments', tinycomments_mode: 'embedded', - tinycomments_author: currentAuthor, + user_id: currentAuthor, tinycomments_can_resolve: canResolveCommentsCallback, sidebar_show: 'showcomments' }); From f6365f1a3225c4e0630e012d61af83ecaa432d8d Mon Sep 17 00:00:00 2001 From: kimwoodfield Date: Thu, 10 Jul 2025 11:47:52 +1000 Subject: [PATCH 43/68] DOC-3174: Update interactive demos and examples for `revisionhistory` --- .../live-demos/revisionhistory/index.js | 22 ++++++++++++++++--- .../revisionhistory_fetch_revision.adoc | 16 +++++++------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/modules/ROOT/examples/live-demos/revisionhistory/index.js b/modules/ROOT/examples/live-demos/revisionhistory/index.js index 946faa0854..4b80d64bfc 100644 --- a/modules/ROOT/examples/live-demos/revisionhistory/index.js +++ b/modules/ROOT/examples/live-demos/revisionhistory/index.js @@ -4,6 +4,14 @@ const getRandomDelay = () => { return Math.floor(Math.random() * (maxDelay - minDelay + 1)) + minDelay; }; +const userDirectory = { + 'john.doe': { + id: 'john.doe', + name: 'John Doe', + avatar: 'https://example.com/avatar/john.png' + } +}; + const lightRevisions = [ { revisionId: '3', @@ -202,9 +210,17 @@ tinymce.init({ 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' + user_id: 'john.doe', + fetch_users: (userIds) => { + const results = userIds.map((id) => { + const user = Object.values(userDirectory).find((user) => user.id === id); + if (user) { + return user; + } else { + throw new Error(`User ${id} not found`); + } + }); + return Promise.resolve(results); }, revisionhistory_display_author: true }); diff --git a/modules/ROOT/partials/configuration/revisionhistory_fetch_revision.adoc b/modules/ROOT/partials/configuration/revisionhistory_fetch_revision.adoc index d729459112..56116855b8 100644 --- a/modules/ROOT/partials/configuration/revisionhistory_fetch_revision.adoc +++ b/modules/ROOT/partials/configuration/revisionhistory_fetch_revision.adoc @@ -65,15 +65,15 @@ tinymce.init({ 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; + 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); + resolve(newRevision); }) }); ---- From 193d1c4992c24cc8eaa8a009f50a00145bd6b9fe Mon Sep 17 00:00:00 2001 From: MitchCTiny Date: Thu, 10 Jul 2025 14:09:48 +1000 Subject: [PATCH 44/68] DOC-3174: Rewrite suggested edits --- .../live-demos/suggestededits/index.js | 17 ++-- modules/ROOT/pages/suggestededits.adoc | 91 +++++++++++-------- 2 files changed, 60 insertions(+), 48 deletions(-) diff --git a/modules/ROOT/examples/live-demos/suggestededits/index.js b/modules/ROOT/examples/live-demos/suggestededits/index.js index 2bdbf5038e..9e8966f590 100644 --- a/modules/ROOT/examples/live-demos/suggestededits/index.js +++ b/modules/ROOT/examples/live-demos/suggestededits/index.js @@ -53,7 +53,7 @@ const model = { }, { "text": "interactive ", - "_opData": { + "opData": { "id": 1, "type": "insert", "id": "adamhenderson", @@ -76,7 +76,7 @@ const model = { }, { "text": ": type in the editor, apply formatting or delete some content.", - "_opData": { + "opData": { "id": 3, "type": "insert", "id": "adamhenderson", @@ -85,7 +85,7 @@ const model = { }, { "text": " by typing in the editor and", - "_opData": { + "opData": { "id": 2, "type": "remove", "id": "adamhenderson", @@ -97,7 +97,7 @@ const model = { }, { "text": "t", - "_opData": { + "opData": { "id": 4, "type": "remove", "id": "adamhenderson", @@ -106,7 +106,7 @@ const model = { }, { "text": "T", - "_opData": { + "opData": { "id": 4, "type": "insert", "id": "adamhenderson", @@ -118,7 +118,7 @@ const model = { }, { "text": ",", - "_opData": { + "opData": { "id": 5, "type": "insert", "id": "adamhenderson", @@ -130,7 +130,7 @@ const model = { }, { "text": "ing", - "_opData": { + "opData": { "id": 6, "type": "remove", "id": "adamhenderson", @@ -142,7 +142,7 @@ const model = { }, { "text": " to see your changes", - "_opData": { + "opData": { "id": 7, "type": "insert", "id": "adamhenderson", @@ -406,4 +406,3 @@ tinymce.init({ user_id: 'michaelcook', fetch_users, }); - diff --git a/modules/ROOT/pages/suggestededits.adoc b/modules/ROOT/pages/suggestededits.adoc index 3452f67af2..d38f0e3875 100644 --- a/modules/ROOT/pages/suggestededits.adoc +++ b/modules/ROOT/pages/suggestededits.adoc @@ -1,17 +1,15 @@ = Suggested Edits Plugin :navtitle: Suggested Edits -:description: A view that allows users to review document changes made by multiple authors +:description: Suggested Edits keeps track of changes and review edits made by multiple authors in a document. :description_short: A view of tracked changes made by multiple authors -:keywords: plugin, Suggested Edits, changes, diff +:keywords: plugin, Suggested Edits, changes, diff, track changes, review changes, collaboration, multiple authors :pluginname: Suggested Edits :plugincode: suggestededits :plugincategory: premium -include::partial$misc/admon-revisionhistory-paid-addon-pricing.adoc[] +include::partial$misc/admon-paid-addon-pricing.adoc[] -include::partial$misc/admon-requires-8.0v.adoc[] - -The Suggested Edits plugin allows users to easily review and manage changes made to a document by multiple authors. +The {pluginname} plugin allows multiple users to collaborate on a document. The plugin shows which user suggested which edits, whether they added, removed, modified, or replaced any content, and allows users to provide feedback on those suggestions or give a final review by approving or rejecting them. == Interactive example @@ -21,52 +19,67 @@ include::partial$misc/admon-iframe-only.adoc[] == How it works -The Suggested Edits plugin builds a document model of the editor content to track edits made by multiple authors. This model is used to compare the current content of the editor with the original version, highlighting changes such as insertions, modifications, and deletions. +The {pluginname} plugin keeps track of every suggested edit made to the document by the current user, as the edits are made, and stores this metadata in an internal model of the document. These suggestions can then be reviewed in the `'suggestededits'` xref:custom-view.adoc[editor view], where each edit is highlighted in the document, and where you can accept, reject, or provide feedback. The `'suggestededits'` view is accessible via either the `suggestededits` toolbar button or menu button within the `View` menu. -This allows users to review the changes made to the document, provide feedback on them, and accept or reject them as needed. See xref:#suggestededits_access[`suggestededits_access`] option for more information on how to configure user permissions for editing and reviewing content. +[IMPORTANT] +These edits, and any feedback provided, are stored in the model provided by the plugin xref:#get_model[`+get_model()+` API]. This model should be saved externally alongside the document, and loaded into the editor with the xref:#suggestededits_model[`+suggestededits_model+` option]. This will ensure that both the document and the model are in sync, and that every user's contributions are tracked correctly. -[NOTE] -The model's content should be considered as metadata of the editor's HTML content, and both should be saved together to ensure correctness. See xref:#suggestededits_content[`suggestededits_content`] for more information on how to configure the source of content loaded into the editor. +== Reviewing edits + +The {pluginname} plugin provides a dedicated `'suggestededits'` xref:custom-view.adoc[editor view] for viewing and reviewing edits made by multiple authors. Which actions you can take in this view depends on the xref:#suggestededits_access[`+suggestededits_access+` option]. + +=== Header + +The view contains a few controls to manage the review process: + +* Show edits: A toggle button which hides/unhides the highlighted annotations. +* Complete review: Ends the review, applying the resolved changes to the document. +* Cancel: Exits the review with no change to the document. -A dedicated read-only view is provided for reviewing current changes, accessible via the `{plugincode}` toolbar button or the menu option under the `View` menu. The key components are: +=== Document -. **Read-only Diff View**: -+ -Highlights the current changes made to the document, using the following color codes: -+ -* Green: New content. -* Blue: Modified content. Modifications to HTML content implies attributes or formatting (e.g. bold, italic, etc.). +The current editor document is displayed in a sandboxed iframe, with each suggested edit highlighted as they appear in the document. The following color coding is used to indicate the type of change: + +* Green: Added content. +* Blue: Modified attributes or formatting (e.g. bold, italic, etc.). * Red: Removed content. -. **Sidebar**: -+ -Contains a header with the following buttons: -+ -* Show Changes: A toggle button which hides/unhides the change annotations. -* Complete: Ends the review and applies the resolved changes. -* Cancel: Ends the review without any further action. +Replaced content is represented as both added and removed content, and indicates that some content was removed and replaced with new content in a single edit. When a suggestion is selected, whether in the document or in the sidebar, the corresponding highlighted suggestion in the document will be outlined in blue and scrolled into view. + +=== Sidebar + +Each suggested edit is listed as a card in the sidebar and color coded by the type of change, along with the user who made the suggestion, when the edit was made, and any feedback provided on that suggestion. When selected, each suggestion can be handled in the following ways: + +* Accept: Resolves the edit and will be applied to the document when . +* Reject: Removes the change from the document. +* Revert: Undoes a previously accepted or rejected change. +* Provide feedback: Opens a text area for you to provide feedback on the suggestion. + +Any feedback will be stored in the model and displayed underneath the card details and in chronological order. This feedback thread can be used to discuss the suggestion with the author or other reviewers. The feedback author can edit or delete their own feedback. + +At the top of the sidebar, there is also a dropdown menu to apply review actions in bulk to all suggested edits: -+ -The sidebar also displays all tracked changes that need to be resolved. Each change can be handled in the following ways: -* Accept: Applies the change to the document. -* Reject: Removes the change from the document. -* Revert: Undoes a previously accepted or rejected change. +* Accept all. +* Reject all. +* Revert all. -== Types of suggestions +=== Finishing a review -There are four basic types of suggestions that are tracked by the Suggested Edits plugin: +When you complete a review, any resolved suggestions will be applied to the document and will no longer be tracked in the model as suggestions, including any feedback on resolved suggestions. This means that any accepted edits will remain in the docuemnt, and any rejected edits will be reverted to the state before the suggestion was made. More specifically, review actions will apply the following to the document: -=== Insert -Tracks the addition of new content to the document. +* When added content is - +** Accepted: The content will remain in the document. +** Rejected: The content will be removed from the document. -=== Modify -Tracks HTML attribute changes or formatting changes to existing content, such as bold or italic text. Note that if multiple users modify the same content, the original author will still be attributed with the change. +* When modified content is - +** Accepted: The content will keep the current formats and attributes. +** Rejected: The content will revert to the formats and attributes it had before the edit was made. -=== Delete -Tracks the removal of content from the document. +* When removed content is - +** Accepted: The content will be remain removed from the document. +** Rejected: The content will be restored to the document. -=== Replace -Tracks the replacement of existing content with new content. This is treated as a combination of a delete and an insert, where the original content is selected and replaced by new content. Note that if multiple users replace the same content, the most recent author will be attributed with the change. +If you cancel your review, no resolved suggestions will be applied to the document and all suggestions will remain in the model, including any feedback provided during that review session. == Initial setup From e3ec479a5abed38dd75428fa51467b7b53accb3a Mon Sep 17 00:00:00 2001 From: MitchCTiny Date: Mon, 14 Jul 2025 12:15:45 +1000 Subject: [PATCH 45/68] DOC-3174: Edits --- modules/ROOT/pages/suggestededits.adoc | 16 ++++++++++++---- .../configuration/suggestededits-options.adoc | 5 ----- .../suggestededits-toolbar-buttons.adoc | 3 ++- 3 files changed, 14 insertions(+), 10 deletions(-) delete mode 100644 modules/ROOT/partials/configuration/suggestededits-options.adoc diff --git a/modules/ROOT/pages/suggestededits.adoc b/modules/ROOT/pages/suggestededits.adoc index d38f0e3875..6cdb819b56 100644 --- a/modules/ROOT/pages/suggestededits.adoc +++ b/modules/ROOT/pages/suggestededits.adoc @@ -19,10 +19,10 @@ include::partial$misc/admon-iframe-only.adoc[] == How it works -The {pluginname} plugin keeps track of every suggested edit made to the document by the current user, as the edits are made, and stores this metadata in an internal model of the document. These suggestions can then be reviewed in the `'suggestededits'` xref:custom-view.adoc[editor view], where each edit is highlighted in the document, and where you can accept, reject, or provide feedback. The `'suggestededits'` view is accessible via either the `suggestededits` toolbar button or menu button within the `View` menu. +The {pluginname} plugin keeps track of every suggested edit made to the document by the current user, as the edits are made, and stores this metadata in an internal model of the document. These suggestions can then be reviewed in the `'suggestededits'` xref:custom-view.adoc[editor view], where each edit is highlighted in the document, and where you can accept, reject, or provide feedback. The `'suggestededits'` view is accessible via either the `suggestededits` toolbar button or menu button within the `View` menu. These edits, and any feedback provided, are stored in the model provided by the plugin xref:#get_model[`+get_model()+` API]. [IMPORTANT] -These edits, and any feedback provided, are stored in the model provided by the plugin xref:#get_model[`+get_model()+` API]. This model should be saved externally alongside the document, and loaded into the editor with the xref:#suggestededits_model[`+suggestededits_model+` option]. This will ensure that both the document and the model are in sync, and that every user's contributions are tracked correctly. +This model should be saved externally alongside the document, and loaded into the editor with the xref:#suggestededits_model[`+suggestededits_model+` option]. This will ensure that both the document and the model are in sync, and that every user's contributions are tracked correctly. == Reviewing edits @@ -83,7 +83,7 @@ If you cancel your review, no resolved suggestions will be applied to the docume == Initial setup -The Suggested Edits plugin uses a document model to track changes. If the model is not provided in the editor configuration, the plugin will create a new model from the current content of the editor. This model can be retrieved from the editor at any time using the xref:#get_model[`getModel` API], and should be saved externally +The {pluginname} plugin requires a model to store . If the model is not provided in the editor configuration, the plugin will create a new model from the current content of the editor. This model can be retrieved from the editor at any time using the xref:#get_model[`getModel` API], and should be saved externally To setup the {pluginname} plugin in the editor: @@ -109,7 +109,15 @@ tinymce.init({ The following configuration options affect the behavior of the {pluginname} plugin. -include::partial$configuration/suggestededits-options.adoc[leveloffset=+1] +include::partial$configuration/user_id.adoc[leveloffset=+1] + +include::partial$configuration/fetch_users.adoc[leveloffset=+1] + +include::partial$configuration/suggestededits_model.adoc[leveloffset=+1] + +include::partial$configuration/suggestededits_content.adoc[leveloffset=+1] + +include::partial$configuration/suggestededits_access.adoc[leveloffset=+1] include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] diff --git a/modules/ROOT/partials/configuration/suggestededits-options.adoc b/modules/ROOT/partials/configuration/suggestededits-options.adoc deleted file mode 100644 index dff06d1326..0000000000 --- a/modules/ROOT/partials/configuration/suggestededits-options.adoc +++ /dev/null @@ -1,5 +0,0 @@ -include::partial$configuration/user_id.adoc[] -include::partial$configuration/fetch_users.adoc[] -include::partial$configuration/suggestededits_model.adoc[] -include::partial$configuration/suggestededits_content.adoc[] -include::partial$configuration/suggestededits_access.adoc[] diff --git a/modules/ROOT/partials/toolbar-button-ids/suggestededits-toolbar-buttons.adoc b/modules/ROOT/partials/toolbar-button-ids/suggestededits-toolbar-buttons.adoc index 45fc5d5f82..13ee6351ea 100644 --- a/modules/ROOT/partials/toolbar-button-ids/suggestededits-toolbar-buttons.adoc +++ b/modules/ROOT/partials/toolbar-button-ids/suggestededits-toolbar-buttons.adoc @@ -2,5 +2,6 @@ |=== |Toolbar button identifier |Description -|`+suggestededits+` |Open the Suggested Edits view. +|`+suggestededits+` |Open the Review edits view. +|`+suggestededits-label+` |Opens the Review edits view. |=== \ No newline at end of file From 71b19affb871297ce489b6a45c4bb2b54e325077 Mon Sep 17 00:00:00 2001 From: MitchCTiny Date: Mon, 14 Jul 2025 14:20:41 +1000 Subject: [PATCH 46/68] DOC-3246: More docs --- modules/ROOT/pages/suggestededits.adoc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/ROOT/pages/suggestededits.adoc b/modules/ROOT/pages/suggestededits.adoc index 6cdb819b56..669b273aba 100644 --- a/modules/ROOT/pages/suggestededits.adoc +++ b/modules/ROOT/pages/suggestededits.adoc @@ -83,28 +83,28 @@ If you cancel your review, no resolved suggestions will be applied to the docume == Initial setup -The {pluginname} plugin requires a model to store . If the model is not provided in the editor configuration, the plugin will create a new model from the current content of the editor. This model can be retrieved from the editor at any time using the xref:#get_model[`getModel` API], and should be saved externally - 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; -* add `{plugincode}_model` to the editor configuration, if a document is already being tracked. For example: [source,js] ---- -const suggestededits_model = `` // model provided by the getModel API - tinymce.init({ selector: 'textarea#suggestededits', // change this value according to your HTML plugins: 'suggestededits', toolbar: 'suggestededits', - suggestededits_model, }); ---- +This configuration will add {pluginname} to the editor toolbar, allowing users to access the plugin features. However, to fully utilize the plugin, you will need to provide additional configuration options. + +The {pluginname} plugin requires a model to store. If the model is not provided in the editor configuration, or is `+undefined+`, the plugin will generate a new model. The model contains all the current suggested edits, so unless you are starting a new document, the current model for the document should always be provided. This model can be retrieved from the editor at any time using the xref:#get_model[`getModel` API], and should be saved externally alongside the document. + +The {pluginname} plugin also requires a unique user identifier to attribute suggestions made by each user, including edits and feedback. The current user should be set with the xref:#user_id[`+user_id+` option]. The user ID should be a unique string that identifies the user, such as a username or an email address. Each suggestion in the model will have a uid, allowing other users to see who made which suggestion. + == Options The following configuration options affect the behavior of the {pluginname} plugin. From 791592a4863dc5fa1b28553c4870b45b465b42e7 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Mon, 14 Jul 2025 14:24:24 +1000 Subject: [PATCH 47/68] DOC-3246: Fixed, premium-plugin table, removed template material, fixed whitespace, added missing available-toolbar-buttons. --- modules/ROOT/pages/available-toolbar-buttons.adoc | 7 +++++++ .../ROOT/partials/commands/suggestededits-cmds.adoc | 4 ++-- .../ROOT/partials/events/suggestededits-events.adoc | 4 ---- .../ROOT/partials/index-pages/premium-plugins.adoc | 12 ++++++------ 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/modules/ROOT/pages/available-toolbar-buttons.adoc b/modules/ROOT/pages/available-toolbar-buttons.adoc index aeb089d9cd..0a95913626 100644 --- a/modules/ROOT/pages/available-toolbar-buttons.adoc +++ b/modules/ROOT/pages/available-toolbar-buttons.adoc @@ -239,6 +239,13 @@ include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] :!pluginpage: +:plugincategory: premium +:pluginname: Suggested Edits +:plugincode: suggestededits +:pluginpage: suggestededits.adoc +include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] +:!pluginpage: + :plugincategory: opensource :pluginname: Table :plugincode: table diff --git a/modules/ROOT/partials/commands/suggestededits-cmds.adoc b/modules/ROOT/partials/commands/suggestededits-cmds.adoc index c7873a96c3..b4da1ed6e1 100644 --- a/modules/ROOT/partials/commands/suggestededits-cmds.adoc +++ b/modules/ROOT/partials/commands/suggestededits-cmds.adoc @@ -1,8 +1,8 @@ [cols="1,3",options="header"] |=== -|Command |Description +|Command |Description -|suggestededits |Toggle the Suggested Edits view +|suggestededits |Toggle the Suggested Edits view |=== .Examples diff --git a/modules/ROOT/partials/events/suggestededits-events.adoc b/modules/ROOT/partials/events/suggestededits-events.adoc index 9b411215a0..32e882c06d 100644 --- a/modules/ROOT/partials/events/suggestededits-events.adoc +++ b/modules/ROOT/partials/events/suggestededits-events.adoc @@ -6,8 +6,4 @@ The following events are provided by the xref:{plugincode}.adoc[{pluginname} plu |suggestededitsBeginReview |N/A |Fired when the Suggested Edits view opens. |suggestededitsReviewComplete |N/A |Fired when a review in the Suggested Edits view is completed. |suggestededitsReviewCancelled |N/A |Fired when a review in the Suggested Edits view is cancelled. -// 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. |=== \ No newline at end of file diff --git a/modules/ROOT/partials/index-pages/premium-plugins.adoc b/modules/ROOT/partials/index-pages/premium-plugins.adoc index 3e9cc5fff2..91cee3bd6c 100644 --- a/modules/ROOT/partials/index-pages/premium-plugins.adoc +++ b/modules/ROOT/partials/index-pages/premium-plugins.adoc @@ -177,6 +177,12 @@ xref:autocorrect.adoc[Spelling Autocorrect] Add autocorrection of common typos and spelling errors as well as capitalization correction to {productname}. +a| +[.lead] +xref:suggestededits.adoc[Suggested Edits] + +Review document changes by multiple users. + a| [.lead] xref:advanced-templates.adoc[Templates] @@ -201,12 +207,6 @@ 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| -[.lead] -xref:suggestededits.adoc[Suggested Edits] - -Review document changes by multiple users. - |=== From 461d4e1d77c4e40895304c791a834a2a792e49ea Mon Sep 17 00:00:00 2001 From: kimwoodfield Date: Tue, 15 Jul 2025 11:16:55 +1000 Subject: [PATCH 48/68] DOC-3246: Add deprecation messaging to `tinycomments_fetch_author_info` option --- modules/ROOT/pages/comments-callback-mode.adoc | 2 ++ .../partials/configuration/tinycomments_fetch_author_info.adoc | 2 ++ 2 files changed, 4 insertions(+) diff --git a/modules/ROOT/pages/comments-callback-mode.adoc b/modules/ROOT/pages/comments-callback-mode.adoc index 85275ec9fc..44e9b67016 100644 --- a/modules/ROOT/pages/comments-callback-mode.adoc +++ b/modules/ROOT/pages/comments-callback-mode.adoc @@ -67,6 +67,8 @@ include::partial$configuration/tinycomments_resolve.adoc[leveloffset=+1] include::partial$configuration/tinycomments_fetch.adoc[leveloffset=+1] +include::partial$configuration/fetch_users.adoc[leveloffset=+1] + include::partial$configuration/tinycomments_fetch_author_info.adoc[leveloffset=+1] include::partial$plugins/comments-open-sidebar.adoc[] diff --git a/modules/ROOT/partials/configuration/tinycomments_fetch_author_info.adoc b/modules/ROOT/partials/configuration/tinycomments_fetch_author_info.adoc index 077409d53d..801ebe839d 100644 --- a/modules/ROOT/partials/configuration/tinycomments_fetch_author_info.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_fetch_author_info.adoc @@ -1,6 +1,8 @@ [[tinycomments_fetch_author_info]] == `+tinycomments_fetch_author_info+` +include::partial$DEPRECATED/generic_8_userlookup.adoc[] + The {pluginname} plugin uses the `+tinycomments_fetch_author_info+` callback function to provide author details for comments displayed in the editor. This function is called whenever a comment is rendered, and it allows the editor to display the author’s name and avatar based on the current user. From bac3a5b8fd576272cb97ddf27ef54fd038cc01f0 Mon Sep 17 00:00:00 2001 From: kimwoodfield Date: Tue, 15 Jul 2025 12:35:49 +1000 Subject: [PATCH 49/68] DOC-3246: Update interactive examples on `comments-with-mentions` page --- .../comments-callback-with-mentions/index.js | 19 ++++--- .../comments-embedded-with-mentions/index.js | 53 +++++++++++-------- 2 files changed, 43 insertions(+), 29 deletions(-) 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 index bb74433204..48eaff62dd 100644 --- a/modules/ROOT/examples/live-demos/comments-callback-with-mentions/index.js +++ b/modules/ROOT/examples/live-demos/comments-callback-with-mentions/index.js @@ -320,9 +320,6 @@ import ('https://cdn.jsdelivr.net/npm/@faker-js/faker@9/dist/index.min.js').then }); setTimeout(() => done({ conversations: fetchedConversations }), fakeDelay); }; - - // Read the above `getAuthorInfo` function to see how this could be implemented - const tinycomments_fetch_author_info = (done) => done(getAuthorInfo(currentUid)); tinymce.init({ selector: 'textarea#comments-callback-with-mentions', @@ -350,9 +347,18 @@ import ('https://cdn.jsdelivr.net/npm/@faker-js/faker@9/dist/index.min.js').then mentions_select, tinycomments_mode: 'callback', - tinycomments_author: currentUser.id, - tinycomments_author_name: currentUser.fullName, - tinycomments_avatar: currentUser.image, + user_id: currentUser.id, + fetch_users: (userIds) => { + const results = userIds.map((id) => { + const user = Object.values(userDb).find((user) => user.id === id); + if (user) { + return user; + } else { + throw new Error(`User ${id} not found`); + } + }); + return Promise.resolve(results); + }, tinycomments_create, tinycomments_reply, tinycomments_delete, @@ -362,6 +368,5 @@ import ('https://cdn.jsdelivr.net/npm/@faker-js/faker@9/dist/index.min.js').then tinycomments_delete_comment, tinycomments_edit_comment, tinycomments_fetch, - tinycomments_fetch_author_info }); }); 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 index c2639167f7..eed950f3ef 100644 --- a/modules/ROOT/examples/live-demos/comments-embedded-with-mentions/index.js +++ b/modules/ROOT/examples/live-demos/comments-embedded-with-mentions/index.js @@ -1,19 +1,24 @@ 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" - }; + /* This represents a database of users on the server */ + 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 currentUser = { - id: 'jennynichols', - name: 'Jenny Nichols', - fullName: 'Jenny Nichols', - description: 'Marketing Director', - image: "https://i.pravatar.cc/150?img=10" - }; + const adminUser = userDb['johnsmith']; + const currentUser = userDb['jennynichols']; const fakeDelay = 500; const numberOfUsers = 200; @@ -32,11 +37,6 @@ import ('https://cdn.jsdelivr.net/npm/@faker-js/faker@9/dist/index.min.js').then 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, ''); @@ -155,9 +155,18 @@ import ('https://cdn.jsdelivr.net/npm/@faker-js/faker@9/dist/index.min.js').then tinycomments_mode: 'embedded', sidebar_show: 'showcomments', - tinycomments_author: currentUser.id, - tinycomments_author_name: currentUser.fullName, - tinycomments_avatar: currentUser.image, + user_id: currentUser.id, + fetch_users: (userIds) => { + const results = userIds.map((id) => { + const user = Object.values(userDb).find((user) => user.id === id); + if (user) { + return user; + } else { + throw new Error(`User ${id} not found`); + } + }); + return Promise.resolve(results); + }, tinycomments_can_resolve, }); }); From 2f646817b0e2e70bc899eb5fc6d6467733019ba2 Mon Sep 17 00:00:00 2001 From: kimwoodfield Date: Tue, 15 Jul 2025 12:55:49 +1000 Subject: [PATCH 50/68] DOC-3246: Include `user_id` and `fetch_users` options in `Required Comments options for embedded mode` section --- modules/ROOT/pages/comments-with-mentions.adoc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/ROOT/pages/comments-with-mentions.adoc b/modules/ROOT/pages/comments-with-mentions.adoc index 950c59350b..f648a0ddea 100644 --- a/modules/ROOT/pages/comments-with-mentions.adoc +++ b/modules/ROOT/pages/comments-with-mentions.adoc @@ -64,9 +64,18 @@ include::partial$configuration/tinycomments_lookup.adoc[leveloffset=+1] When using embedded mode, the {pluginname} plugin requires the following options: +* xref:user_id[`+user_id+`] +* xref:fetch_users[`+fetch_users+`] + +Or: + * xref:tinycomments_author[`+tinycomments_author+`] * xref:tinycomments_author_name[`+tinycomments_author_name+`] +include::partial$configuration/user_id.adoc[leveloffset=+1] + +include::partial$configuration/fetch_users.adoc[leveloffset=+1] + include::partial$configuration/tinycomments_author.adoc[leveloffset=+1] include::partial$configuration/tinycomments_author_name.adoc[leveloffset=+1] From 7bdb429e4b151357d0956a494566ac557199826e Mon Sep 17 00:00:00 2001 From: kimwoodfield Date: Tue, 15 Jul 2025 12:56:22 +1000 Subject: [PATCH 51/68] DOC-3246: Update `tinycomments_mentions_enabled` to include `user_id` and `fetch_users` --- .../tinycomments_mentions_enabled.adoc | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/partials/configuration/tinycomments_mentions_enabled.adoc b/modules/ROOT/partials/configuration/tinycomments_mentions_enabled.adoc index 45e0df05ce..26169dcb1a 100644 --- a/modules/ROOT/partials/configuration/tinycomments_mentions_enabled.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_mentions_enabled.adoc @@ -13,14 +13,28 @@ The {pluginname} plugin offers the `+tinycomments_mentions_enabled+` option to c [source,js] ---- +const userDirectory = { + 'johnsmith': { id: 'johnsmith', name: 'John Smith' }, +}; + 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', + user_id: 'johnsmith', + fetch_users: (userIds) => { + const results = userIds.map((id) => { + const user = Object.values(userDirectory).find((user) => user.id === id); + if (user) { + return user; + } else { + throw new Error(`User ${id} not found`); + } + }); + return Promise.resolve(results); + }, mentions_fetch, mentions_menu_complete, mentions_menu_hover, From 43dc3a3bf729874fada64911068ed29aa38e5a90 Mon Sep 17 00:00:00 2001 From: MitchCTiny Date: Tue, 15 Jul 2025 21:00:05 +1000 Subject: [PATCH 52/68] DOC-3246: Demo updates --- .../live-demos/suggestededits/example.js | 80 ++++---- .../live-demos/suggestededits/index.js | 180 ++++++++++-------- modules/ROOT/pages/suggestededits.adoc | 16 +- .../configuration/suggestededits_model.adoc | 2 +- 4 files changed, 152 insertions(+), 126 deletions(-) diff --git a/modules/ROOT/examples/live-demos/suggestededits/example.js b/modules/ROOT/examples/live-demos/suggestededits/example.js index bbaeaddee0..c29f73160f 100644 --- a/modules/ROOT/examples/live-demos/suggestededits/example.js +++ b/modules/ROOT/examples/live-demos/suggestededits/example.js @@ -1,48 +1,40 @@ -/** Fake user database */ -const userDb = { - adamhenderson: { - id: 'adamhenderson', - name: 'Adam Henderson', - avatar: `https://randomuser.me/api/portraits/men/1.jpg`, - }, - michaelcook: { - id: 'michaelcook', - name: 'Michael Cook', - avatar: `https://randomuser.me/api/portraits/men/2.jpg`, - }, - kalebwilson: { - id: 'kalebwilson', - name: 'Kaleb Wilson', - avatar: `https://randomuser.me/api/portraits/men/3.jpg`, - }, - kyleeinstein: { - id: 'kyleeinstein', - name: 'Kyle Einstein', - avatar: `https://randomuser.me/api/portraits/men/4.jpg`, - }, -}; - -const suggestededits_model = null; //Replace with the object returned by the plugin's getModel API, or null if there is no model. - -const fetch_users = (ids) => { - return new Promise((resolve, reject) => { - const users = ids.map(id => userDb[id]); - if (users.length > 0) { - resolve(users); - } else { - reject(new Error('No users found')); - } - }); -} - -tinymce.init({ +const config = { selector: 'textarea#suggested-edits', height: 500, - plugins: 'suggestededits', - toolbar: 'suggestededits', - content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', - suggestededits_model, // If there is no model, the plugin will generate a default model based on the editor content. + plugins: 'suggestededits advlist anchor autolink code charmap emoticons fullscreen help image link lists media preview searchreplace table', + toolbar: 'undo redo | suggestededits | styles fontsizeinput | bold italic | align bullist numlist | table link image | code', user_id: 'michaelcook', - fetch_users, -}); + fetch_users: (userIds) => Promise.all(userIds + .map((userId) => + fetch(`/users/${userId}`) // Fetch user data from the server + .then((response) => response.json()) + .catch(() => ({ id: userId })) // Still return a valid user object even if the fetch fails + )), + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', +} + +const loadTinymce = async () => { + const documentPromise = fetch(`/documents/${documentId}`); // Fetch the document from the server + const modelPromise = fetch(`/models/${documentId}`); // Fetch the model from the same server + + await documentPromise + .then((response) => response.text()) + .then(async (doc) => { + const tinymceElement = document.querySelector('div#tinymce'); + tinymceElement.innerHTML = doc; + + await modelPromise + .then((response) => response.json()) + .then((model) => { + tinymce.init({ + ...config, + suggestededits_model: model, + }); + }) + .catch(() => { + tinymce.init(config); // Initialize without a model if the model fetch fails + }); + }); +}; +loadTinymce(); diff --git a/modules/ROOT/examples/live-demos/suggestededits/index.js b/modules/ROOT/examples/live-demos/suggestededits/index.js index 9e8966f590..fe32e857f1 100644 --- a/modules/ROOT/examples/live-demos/suggestededits/index.js +++ b/modules/ROOT/examples/live-demos/suggestededits/index.js @@ -1,30 +1,39 @@ /** Fake user database */ const userDb = { - adamhenderson: { - id: 'adamhenderson', - name: 'Adam Henderson', - avatar: `https://randomuser.me/api/portraits/men/1.jpg`, + adamhayes: { + id: 'adamhayes', + name: 'Adam Hayes', + avatar: `https://randomuser.me/api/portraits/men/4.jpg`, }, - michaelcook: { - id: 'michaelcook', - name: 'Michael Cook', - avatar: `https://randomuser.me/api/portraits/men/2.jpg`, + martincook: { + id: 'martincook', + name: 'Martin Cook', + avatar: `https://randomuser.me/api/portraits/men/5.jpg`, }, kalebwilson: { id: 'kalebwilson', name: 'Kaleb Wilson', - avatar: `https://randomuser.me/api/portraits/men/3.jpg`, - }, - kyleeinstein: { - id: 'kyleeinstein', - name: 'Kyle Einstein', - avatar: `https://randomuser.me/api/portraits/men/4.jpg`, + avatar: `https://randomuser.me/api/portraits/men/6.jpg`, }, + sarahjones: { + id: 'sarahjones', + name: 'Sarah Jones', + avatar: `https://randomuser.me/api/portraits/women/1.jpg`, + } }; const model = { + "history": { + "2": [ + { + "id": 1, + "uid": "sarahjones", + "timestamp": 1752576936000, + "feedback": "Nice improvement!" + } + ] + }, "version": 1, - "maxId": 7, "contents": [ { "type": "p", @@ -56,8 +65,8 @@ const model = { "opData": { "id": 1, "type": "insert", - "id": "adamhenderson", - "timestamp": 1749214950000 + "uid": "adamhayes", + "timestamp": 1752015064000 } }, { @@ -75,42 +84,21 @@ const model = { "text": "Try out the Suggested Edits feature" }, { - "text": ": type in the editor, apply formatting or delete some content.", + "text": ": type in the editor, apply formatting or delete some content. T", "opData": { - "id": 3, + "id": 2, "type": "insert", - "id": "adamhenderson", - "timestamp": 1749215051000 + "uid": "adamhayes", + "timestamp": 1752415064000 } }, { - "text": " by typing in the editor and", + "text": " by typing in the editor and t", "opData": { "id": 2, "type": "remove", - "id": "adamhenderson", - "timestamp": 1749215053000 - } - }, - { - "text": " " - }, - { - "text": "t", - "opData": { - "id": 4, - "type": "remove", - "id": "adamhenderson", - "timestamp": 1749215055000 - } - }, - { - "text": "T", - "opData": { - "id": 4, - "type": "insert", - "id": "adamhenderson", - "timestamp": 1749215055000 + "uid": "adamhayes", + "timestamp": 1752415064000 } }, { @@ -119,10 +107,10 @@ const model = { { "text": ",", "opData": { - "id": 5, + "id": 3, "type": "insert", - "id": "adamhenderson", - "timestamp": 1749215056000 + "uid": "adamhayes", + "timestamp": 1752515064000 } }, { @@ -131,10 +119,10 @@ const model = { { "text": "ing", "opData": { - "id": 6, + "id": 4, "type": "remove", - "id": "adamhenderson", - "timestamp": 1749215060000 + "uid": "adamhayes", + "timestamp": 1752515064000 } }, { @@ -143,10 +131,10 @@ const model = { { "text": " to see your changes", "opData": { - "id": 7, + "id": 5, "type": "insert", - "id": "adamhenderson", - "timestamp": 1749215064000 + "uid": "kalebwilson", + "timestamp": 1752615064000 } }, { @@ -165,6 +153,12 @@ const model = { }, { "text": "pricing page", + "opData": { + "id": 6, + "type": "modify", + "uid": "kalebwilson", + "timestamp": 1752615064000 + }, "format": [ { "type": "a", @@ -172,6 +166,15 @@ const model = { "href": "https://www.tiny.cloud/pricing" } } + ], + "oldFormat": [ + { + "type": "a", + "attrs": { + "href": "https://www.tiny.cloud/pricing" + } + }, + "em" ] }, { @@ -304,6 +307,12 @@ const model = { }, { "type": "h2", + "opData": { + "id": 7, + "type": "insert", + "uid": "martincook", + "timestamp": 1752576331000 + }, "children": [ { "text": "Found a bug?" @@ -314,10 +323,31 @@ const model = { "type": "p", "children": [ { - "text": "If you believe you have found a bug please create an issue on the " + "text": " ", + "opData": { + "id": 7, + "type": "remove", + "uid": "martincook", + "timestamp": 1752576331000 + } + }, + { + "text": "If you believe you have found a bug please create an issue on the ", + "opData": { + "id": 7, + "type": "insert", + "uid": "martincook", + "timestamp": 1752576331000 + } }, { "text": "GitHub repo", + "opData": { + "id": 7, + "type": "insert", + "uid": "martincook", + "timestamp": 1752576331000 + }, "format": [ { "type": "a", @@ -328,7 +358,13 @@ const model = { ] }, { - "text": " to report it to the developers." + "text": " to report it to the developers.", + "opData": { + "id": 7, + "type": "insert", + "uid": "martincook", + "timestamp": 1752576331000 + } } ] }, @@ -380,29 +416,21 @@ const model = { } ] } - ], - "history": {} -} - -const fetch_users = (ids) => { - return new Promise((resolve, reject) => { - const users = ids.map(id => userDb[id]); - if (users.length > 0) { - resolve(users); - } else { - reject(new Error('No users found')); - } - }); -} + ] +}; tinymce.init({ selector: 'textarea#suggested-edits', height: 500, - plugins: 'suggestededits', - toolbar: 'suggestededits', - content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', - suggestededits_content: 'model', + plugins: 'suggestededits advlist anchor autolink code charmap emoticons fullscreen help image link lists media preview searchreplace table', + toolbar: 'undo redo | suggestededits | styles fontsizeinput | bold italic | align bullist numlist | table link image | code', + user_id: 'kalebwilson', + fetch_users: (userIds) => Promise.all(userIds + .map((userId) => new Promise((resolve) => + resolve(userDb[userId] || { id: userId })) + )), + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', suggestededits_model: model, - user_id: 'michaelcook', - fetch_users, + suggestededits_content: 'html', + suggestededits_access: 'full' }); diff --git a/modules/ROOT/pages/suggestededits.adoc b/modules/ROOT/pages/suggestededits.adoc index 669b273aba..4b1304ae09 100644 --- a/modules/ROOT/pages/suggestededits.adoc +++ b/modules/ROOT/pages/suggestededits.adoc @@ -101,17 +101,19 @@ tinymce.init({ This configuration will add {pluginname} to the editor toolbar, allowing users to access the plugin features. However, to fully utilize the plugin, you will need to provide additional configuration options. -The {pluginname} plugin requires a model to store. If the model is not provided in the editor configuration, or is `+undefined+`, the plugin will generate a new model. The model contains all the current suggested edits, so unless you are starting a new document, the current model for the document should always be provided. This model can be retrieved from the editor at any time using the xref:#get_model[`getModel` API], and should be saved externally alongside the document. -The {pluginname} plugin also requires a unique user identifier to attribute suggestions made by each user, including edits and feedback. The current user should be set with the xref:#user_id[`+user_id+` option]. The user ID should be a unique string that identifies the user, such as a username or an email address. Each suggestion in the model will have a uid, allowing other users to see who made which suggestion. == Options -The following configuration options affect the behavior of the {pluginname} plugin. +The {pluginname} plugin requires a model to store. If the model is not provided in the editor configuration, or is `+undefined+`, the plugin will generate a new model. The model contains all the current suggested edits, so unless you are starting a new document, the current model for the document should always be provided. This model can be retrieved from the editor at any time using the xref:#get_model[`getModel` API], and should be saved externally alongside the document. -include::partial$configuration/user_id.adoc[leveloffset=+1] +Both the xref:#user_id[`+user_id+`] and xref:#fetch_users[`+fetch_users+`] options are required to configure the xref:userlookup.adoc[User Lookup API]. This API is used in the {pluginname} plugin to provide user information for each user who has made a change, allowing other users to see who made which suggestion. -include::partial$configuration/fetch_users.adoc[leveloffset=+1] +* The current user ID should be set with the xref:#user_id[`+user_id+` option]. The user ID should be a unique string that identifies the user, such as a username or an email address. + +* The xref:#fetch_users[`+fetch_users+` option] is required to provide the name and avatar for each user who has made a change, to then appear in the review. This option can be configured to retrieve this information from a backend service, as it provides an array of user IDs and expects a promise of an array, containing the appropriate data for the requested user IDs. + +The following configuration options affect the behavior of the {pluginname} plugin. include::partial$configuration/suggestededits_model.adoc[leveloffset=+1] @@ -119,6 +121,10 @@ include::partial$configuration/suggestededits_content.adoc[leveloffset=+1] include::partial$configuration/suggestededits_access.adoc[leveloffset=+1] +include::partial$configuration/user_id.adoc[leveloffset=+1] + +include::partial$configuration/fetch_users.adoc[leveloffset=+1] + include::partial$misc/plugin-toolbar-button-id-boilerplate.adoc[] include::partial$misc/plugin-menu-item-id-boilerplate.adoc[] diff --git a/modules/ROOT/partials/configuration/suggestededits_model.adoc b/modules/ROOT/partials/configuration/suggestededits_model.adoc index efc9db83cc..dd9b20b2af 100644 --- a/modules/ROOT/partials/configuration/suggestededits_model.adoc +++ b/modules/ROOT/partials/configuration/suggestededits_model.adoc @@ -13,7 +13,7 @@ If the model is not provided in the editor configuration, the plugin will create ---- async function fetchSavedModel(documentId) { // Replace this URL and logic with your actual backend API - const response = await fetch(`/api/models/${documentId}`); + const response = await fetch(`/models/${documentId}`); return await response.json(); } From 85b8ac57d0d5127f50bb58b4cf2df44068c006e0 Mon Sep 17 00:00:00 2001 From: Mitchell Crompton Date: Tue, 15 Jul 2025 21:32:20 +1000 Subject: [PATCH 53/68] Apply suggestions from code review Co-authored-by: Andrew Herron --- .../partials/configuration/suggestededits_content.adoc | 8 +++++--- .../ROOT/partials/configuration/suggestededits_model.adoc | 6 ++++-- modules/ROOT/partials/events/suggestededits-events.adoc | 6 +++--- .../ROOT/partials/plugin-apis/suggestededits-apis.adoc | 4 ++-- .../suggestededits-toolbar-buttons.adoc | 2 +- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/modules/ROOT/partials/configuration/suggestededits_content.adoc b/modules/ROOT/partials/configuration/suggestededits_content.adoc index 6bf6fb53df..454981f115 100644 --- a/modules/ROOT/partials/configuration/suggestededits_content.adoc +++ b/modules/ROOT/partials/configuration/suggestededits_content.adoc @@ -2,11 +2,13 @@ == `suggestededits_content` The `suggestededits_content` option determines where the initial content of the document is loaded from. With this option, you can set the content to be loaded from either the editor or the model, allowing you to control the source of truth for the document. -When set to `'html'`, the editor loads the initial content from the HTML in the textarea or the `content` property. In this case, if a model is provided, it will need to match the content in the editor for the plugin to work correctly +In a `'html'`-first approach, the editor loads content normally and the {pluginname} plugin provides augmentation. The integrator is responsible for saving the model at the same time as the editor content and providing it on the next load using the `suggestededits_model` option. This allows {pluginname} to be integrated quickly into a CMS by adding the model as an additional hidden field alongside the editor content. -When set to `'model'`, the editor loads the initial content from the `suggestededits_model` option. In this case, the content in the editor will be overwritten with the content from the model. This would allow you to only require the model for document tracking, though it is still recommended to save the content in the editor externally. +If a model is not provided the plugin will generate a new one from the initial content of the editor. -In either case, if a model is not provided, the plugin will generate a new model from the current content of the editor, whether it is empty or not. +When `suggestededits_content` is set to `'model'`, the plugin bypasses the editor's content load procedures and instead uses the `suggestededits_model` option to generate initial content. This would allow an integrator to only require the model for document tracking, and treat the editor content as simply a rendering of it. + +If a model is not provided, the plugin will allow the editor to load content normally and generate a new model from there (the same way `html` works). *Type:* `+String+` diff --git a/modules/ROOT/partials/configuration/suggestededits_model.adoc b/modules/ROOT/partials/configuration/suggestededits_model.adoc index dd9b20b2af..ebb8c87dee 100644 --- a/modules/ROOT/partials/configuration/suggestededits_model.adoc +++ b/modules/ROOT/partials/configuration/suggestededits_model.adoc @@ -1,9 +1,11 @@ [[suggestededits_model]] == `suggestededits_model` -The `{plugincode}_model` option sets the initial model of the document to begin tracking changes. It takes as input an object representing the document, containing all edits made to the document up to that point. This model should be saved externally alongside the document, and loaded into the editor each time the document is opened. This will ensure that both the document and the model are in sync, and that the plugin can track edits correctly. +The {pluginname} model is a JSON object representing the full document along with all unreviewed edits. The model should be kept in sync with the editor content and loaded into the editor each time the document is opened. If the model and content are out of sync, the difference between them will be applied as a suggested edit by the current user. -If the model is not provided in the editor configuration, the plugin will create a new model from the current content of the editor. This model can be retrieved from the editor at any time using the xref:#get_model[`getModel` API]. +The `{plugincode}_model` option sets the initial model for an editor load. How this model is used depends on the `{plugincode}_content` setting. + +The model can be stored using the xref:#get_model[`getModel` API]. If the model is not provided the {pluginname} plugin will create a new model from the initial content of the editor, assuming all prior changes have been accepted. *Type:* `+Object+` diff --git a/modules/ROOT/partials/events/suggestededits-events.adoc b/modules/ROOT/partials/events/suggestededits-events.adoc index 32e882c06d..ed44c9693e 100644 --- a/modules/ROOT/partials/events/suggestededits-events.adoc +++ b/modules/ROOT/partials/events/suggestededits-events.adoc @@ -3,7 +3,7 @@ The following events are provided by the xref:{plugincode}.adoc[{pluginname} plu [cols="1,1,2",options="header"] |=== |Name |Data |Description -|suggestededitsBeginReview |N/A |Fired when the Suggested Edits view opens. -|suggestededitsReviewComplete |N/A |Fired when a review in the Suggested Edits view is completed. -|suggestededitsReviewCancelled |N/A |Fired when a review in the Suggested Edits view is cancelled. +|suggestededitsBeginReview. |N/A |The Suggested Edits view has opened. +|suggestededitsReviewComplete |N/A |A review in the Suggested Edits view has been completed. +|suggestededitsReviewCancelled |N/A |A review in the Suggested Edits view was cancelled. |=== \ No newline at end of file diff --git a/modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc b/modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc index c0998d5564..84ec9a1165 100644 --- a/modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc +++ b/modules/ROOT/partials/plugin-apis/suggestededits-apis.adoc @@ -2,10 +2,10 @@ |=== |Name |Arguments |Description -|getModel |N/A |Return an object representing the document model used to store data of the suggested edits. +|getModel |N/A |Returns a JSON object representing the document model and all suggested edits. |setModel | `+Object+` | Set the current model of the document. //|resetModel |N/A |Reset the document to its original state. -|hasChanges |N/A |Return a boolean value indicating whether the document contains edits to be reviewed. +|hasChanges |N/A |Return a boolean value indicating whether the document contains suggested edits. |=== .Examples diff --git a/modules/ROOT/partials/toolbar-button-ids/suggestededits-toolbar-buttons.adoc b/modules/ROOT/partials/toolbar-button-ids/suggestededits-toolbar-buttons.adoc index 13ee6351ea..9ff47724f1 100644 --- a/modules/ROOT/partials/toolbar-button-ids/suggestededits-toolbar-buttons.adoc +++ b/modules/ROOT/partials/toolbar-button-ids/suggestededits-toolbar-buttons.adoc @@ -3,5 +3,5 @@ |Toolbar button identifier |Description |`+suggestededits+` |Open the Review edits view. -|`+suggestededits-label+` |Opens the Review edits view. +|`+suggestededits-label+` |Opens the Review edits view (this button uses text instead of an icon). |=== \ No newline at end of file From b4185ecabe98e3087d4757a13dfc301e52fc3f7d Mon Sep 17 00:00:00 2001 From: kimwoodfield Date: Wed, 16 Jul 2025 10:38:27 +1000 Subject: [PATCH 54/68] DOC-3246: Use lookup over `find` in `fetch_users` --- .../live-demos/comments-embedded-with-mentions/index.js | 2 +- modules/ROOT/examples/live-demos/revisionhistory/index.js | 2 +- modules/ROOT/pages/comments-embedded-mode.adoc | 2 +- modules/ROOT/pages/userlookup.adoc | 2 +- modules/ROOT/partials/configuration/fetch_users.adoc | 2 +- .../partials/configuration/tinycomments_mentions_enabled.adoc | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) 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 index eed950f3ef..6b10792fd3 100644 --- a/modules/ROOT/examples/live-demos/comments-embedded-with-mentions/index.js +++ b/modules/ROOT/examples/live-demos/comments-embedded-with-mentions/index.js @@ -158,7 +158,7 @@ import ('https://cdn.jsdelivr.net/npm/@faker-js/faker@9/dist/index.min.js').then user_id: currentUser.id, fetch_users: (userIds) => { const results = userIds.map((id) => { - const user = Object.values(userDb).find((user) => user.id === id); + const user = userDb[id]; if (user) { return user; } else { diff --git a/modules/ROOT/examples/live-demos/revisionhistory/index.js b/modules/ROOT/examples/live-demos/revisionhistory/index.js index 4b80d64bfc..e640f4b086 100644 --- a/modules/ROOT/examples/live-demos/revisionhistory/index.js +++ b/modules/ROOT/examples/live-demos/revisionhistory/index.js @@ -213,7 +213,7 @@ tinymce.init({ user_id: 'john.doe', fetch_users: (userIds) => { const results = userIds.map((id) => { - const user = Object.values(userDirectory).find((user) => user.id === id); + const user = userDirectory[id]; if (user) { return user; } else { diff --git a/modules/ROOT/pages/comments-embedded-mode.adoc b/modules/ROOT/pages/comments-embedded-mode.adoc index 33ec7af23b..811dbb31b8 100644 --- a/modules/ROOT/pages/comments-embedded-mode.adoc +++ b/modules/ROOT/pages/comments-embedded-mode.adoc @@ -26,7 +26,7 @@ tinymce.init({ user_id: 'author', fetch_users: (userIds) => { const results = userIds.map((id) => { - const user = Object.values(userDirectory).find((user) => user.id === id); + const user = userDirectory[id]; if (user) { return user; } else { diff --git a/modules/ROOT/pages/userlookup.adoc b/modules/ROOT/pages/userlookup.adoc index 7f18e7a3e3..5223e49f3c 100644 --- a/modules/ROOT/pages/userlookup.adoc +++ b/modules/ROOT/pages/userlookup.adoc @@ -46,7 +46,7 @@ tinymce.init({ user_id: 'alextaylor', fetch_users: (userIds) => { const results = userIds.map((id) => { - const user = Object.values(userDirectory).find((user) => user.id === id); + const user = userDirectory[id]; if (user) { return user; } else { diff --git a/modules/ROOT/partials/configuration/fetch_users.adoc b/modules/ROOT/partials/configuration/fetch_users.adoc index bc86db7fb6..db50c5dcc4 100644 --- a/modules/ROOT/partials/configuration/fetch_users.adoc +++ b/modules/ROOT/partials/configuration/fetch_users.adoc @@ -26,7 +26,7 @@ tinymce.init({ user_id: 'alextaylor', fetch_users: (userIds) => { const results = userIds.map((id) => { - const user = Object.values(userDirectory).find((user) => user.id === id); + const user = userDirectory[id]; if (user) { return user; } else { diff --git a/modules/ROOT/partials/configuration/tinycomments_mentions_enabled.adoc b/modules/ROOT/partials/configuration/tinycomments_mentions_enabled.adoc index 26169dcb1a..aed2abce63 100644 --- a/modules/ROOT/partials/configuration/tinycomments_mentions_enabled.adoc +++ b/modules/ROOT/partials/configuration/tinycomments_mentions_enabled.adoc @@ -26,7 +26,7 @@ tinymce.init({ user_id: 'johnsmith', fetch_users: (userIds) => { const results = userIds.map((id) => { - const user = Object.values(userDirectory).find((user) => user.id === id); + const user = userDirectory[id]; if (user) { return user; } else { From 212d65a70e7dcad8f921ec1551fdb4299c9b5c93 Mon Sep 17 00:00:00 2001 From: kimwoodfield Date: Wed, 16 Jul 2025 18:08:45 +1000 Subject: [PATCH 55/68] DOC-3246: Updates to `fetch_users` partial --- .../partials/configuration/fetch_users.adoc | 54 ++++++++++++------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/modules/ROOT/partials/configuration/fetch_users.adoc b/modules/ROOT/partials/configuration/fetch_users.adoc index db50c5dcc4..7b1dd63c68 100644 --- a/modules/ROOT/partials/configuration/fetch_users.adoc +++ b/modules/ROOT/partials/configuration/fetch_users.adoc @@ -1,7 +1,7 @@ [[fetch_users]] == `fetch_users` -A **required callback function** that fetches user data. This function is called with an array of user IDs and should return a `Promise` that resolves to an array of user objects. The callback is used by the xref:userlookup.adoc[`UserLookup`] API. +A **required callback function** that fetches user data. This function is called with an array of user IDs and should return a `Promise` that resolves to an array of user objects. The callback is used by the xref:userlookup.adoc[`UserLookup`] API. If the returned array does not include all requested user IDs, promises for the missing users will be rejected with a "User {id} not found" error. *Type:* `Function` @@ -15,25 +15,43 @@ A **required callback function** that fetches user data. This function is called [source,javascript] ---- -const userDirectory = { - 'janedoe': { id: 'janedoe', name: 'Jane Doe', avatar: 'https://example.com/avatar/jane.png' }, - 'johnsmith': { id: 'johnsmith', name: 'John Smith' }, - 'alextaylor': { id: 'alextaylor', name: 'Alex Taylor', avatar: 'https://example.com/avatar/alex.png' } -}; - tinymce.init({ selector: '#editor', user_id: 'alextaylor', - fetch_users: (userIds) => { - const results = userIds.map((id) => { - const user = userDirectory[id]; - if (user) { - return user; - } else { - throw new Error(`User ${id} not found`); - } - }); - return Promise.resolve(results); - } + fetch_users: (userIds) => Promise.all(userIds + .map((userId) => + fetch(`/users/${userId}`) // Fetch user data from the server + .then((response) => response.json()) + .catch(() => ({ id: userId })) // Still return a valid user object even if the fetch fails + )), +}); +---- + +=== Example: returning user array with validation + +[source,javascript] +---- +tinymce.init({ + selector: '#editor', + user_id: 'alextaylor', + fetch_users: async (userIds) => { + const users = await fetch('/users', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ userIds }) + }) + .then((response) => response.json()) + .catch(() => + userIds.map((userId) => + ({ id: userId }) // Still returns valid users even if the fetch fails + ) + ); + + return userIds.map( + (userId) => + users.find((user) => user.id === userId) + || ({ id: userId }) // Still returns a valid user even if it wasn't returned from the server + ) + } }); ---- \ No newline at end of file From 767d81fcb2f156f1770797fd90282548e83ed021 Mon Sep 17 00:00:00 2001 From: MitchCTiny Date: Wed, 16 Jul 2025 20:51:46 +1000 Subject: [PATCH 56/68] DOC-3246: Improve examples and access option --- .../suggestededits-access-feedback/index.html | 44 ++ .../suggestededits-access-feedback/index.js | 437 ++++++++++++++++++ .../suggestededits-access-read/index.html | 44 ++ .../suggestededits-access-read/index.js | 437 ++++++++++++++++++ .../suggestededits-access/index.html | 34 -- .../live-demos/suggestededits-access/index.js | 46 -- .../suggestededits-suggestions/index.html | 34 -- .../suggestededits-suggestions/index.js | 46 -- .../live-demos/suggestededits/example.js | 36 +- .../live-demos/suggestededits/index.html | 2 +- .../live-demos/suggestededits/index.js | 2 +- .../configuration/suggestededits_access.adoc | 40 +- 12 files changed, 996 insertions(+), 206 deletions(-) create mode 100644 modules/ROOT/examples/live-demos/suggestededits-access-feedback/index.html create mode 100644 modules/ROOT/examples/live-demos/suggestededits-access-feedback/index.js create mode 100644 modules/ROOT/examples/live-demos/suggestededits-access-read/index.html create mode 100644 modules/ROOT/examples/live-demos/suggestededits-access-read/index.js delete mode 100644 modules/ROOT/examples/live-demos/suggestededits-access/index.html delete mode 100644 modules/ROOT/examples/live-demos/suggestededits-access/index.js delete mode 100644 modules/ROOT/examples/live-demos/suggestededits-suggestions/index.html delete mode 100644 modules/ROOT/examples/live-demos/suggestededits-suggestions/index.js diff --git a/modules/ROOT/examples/live-demos/suggestededits-access-feedback/index.html b/modules/ROOT/examples/live-demos/suggestededits-access-feedback/index.html new file mode 100644 index 0000000000..b410001410 --- /dev/null +++ b/modules/ROOT/examples/live-demos/suggestededits-access-feedback/index.html @@ -0,0 +1,44 @@ + diff --git a/modules/ROOT/examples/live-demos/suggestededits-access-feedback/index.js b/modules/ROOT/examples/live-demos/suggestededits-access-feedback/index.js new file mode 100644 index 0000000000..cd94d11ab1 --- /dev/null +++ b/modules/ROOT/examples/live-demos/suggestededits-access-feedback/index.js @@ -0,0 +1,437 @@ +/** Fake user database */ +const userDb = { + adamhayes: { + id: 'adamhayes', + name: 'Adam Hayes', + avatar: `https://randomuser.me/api/portraits/men/4.jpg`, + }, + martincook: { + id: 'martincook', + name: 'Martin Cook', + avatar: `https://randomuser.me/api/portraits/men/5.jpg`, + }, + kalebwilson: { + id: 'kalebwilson', + name: 'Kaleb Wilson', + avatar: `https://randomuser.me/api/portraits/men/6.jpg`, + }, + sarahjones: { + id: 'sarahjones', + name: 'Sarah Jones', + avatar: `https://randomuser.me/api/portraits/women/1.jpg`, + } +}; + +const model = { + "history": { + "2": [ + { + "id": 1, + "uid": "sarahjones", + "timestamp": 1752576936000, + "feedback": "Nice improvement!" + } + ] + }, + "version": 1, + "contents": [ + { + "type": "p", + "children": [ + { + "type": "img", + "attrs": { + "style": "display: block; margin-left: auto; margin-right: auto;", + "title": "Tiny Logo", + "src": "https://www.tiny.cloud/docs/images/logos/android-chrome-256x256.png", + "alt": "TinyMCE Logo", + "width": "128", + "height": "128" + } + } + ] + }, + { + "type": "h2", + "attrs": { + "style": "text-align: center;" + }, + "children": [ + { + "text": "Welcome to the TinyMCE Suggested Edits " + }, + { + "text": "interactive ", + "opData": { + "id": 1, + "type": "insert", + "uid": "adamhayes", + "timestamp": 1752015064000 + } + }, + { + "text": "demo!" + } + ] + }, + { + "type": "p", + "attrs": { + "style": "text-align: center;" + }, + "children": [ + { + "text": "Try out the Suggested Edits feature" + }, + { + "text": ": type in the editor, apply formatting or delete some content. T", + "opData": { + "id": 2, + "type": "insert", + "uid": "adamhayes", + "timestamp": 1752415064000 + } + }, + { + "text": " by typing in the editor and t", + "opData": { + "id": 2, + "type": "remove", + "uid": "adamhayes", + "timestamp": 1752415064000 + } + }, + { + "text": "hen" + }, + { + "text": ",", + "opData": { + "id": 3, + "type": "insert", + "uid": "adamhayes", + "timestamp": 1752515064000 + } + }, + { + "text": " click" + }, + { + "text": "ing", + "opData": { + "id": 4, + "type": "remove", + "uid": "adamhayes", + "timestamp": 1752515064000 + } + }, + { + "text": " the Review Changes button in the toolbar" + }, + { + "text": " to see your changes", + "opData": { + "id": 5, + "type": "insert", + "uid": "kalebwilson", + "timestamp": 1752615064000 + } + }, + { + "text": "." + } + ] + }, + { + "type": "p", + "attrs": { + "style": "text-align: center;" + }, + "children": [ + { + "text": "And visit the " + }, + { + "text": "pricing page", + "opData": { + "id": 6, + "type": "modify", + "uid": "kalebwilson", + "timestamp": 1752615064000 + }, + "format": [ + { + "type": "a", + "attrs": { + "href": "https://www.tiny.cloud/pricing" + } + } + ], + "oldFormat": [ + { + "type": "a", + "attrs": { + "href": "https://www.tiny.cloud/pricing" + } + }, + "em" + ] + }, + { + "text": " to learn more about our Premium plugins." + } + ] + }, + { + "type": "h2", + "children": [ + { + "text": "A simple table to play with" + } + ] + }, + { + "type": "table", + "attrs": { + "style": "border-collapse: collapse; width: 100%;", + "border": "1" + }, + "children": [ + { + "type": "thead", + "children": [ + { + "type": "tr", + "attrs": { + "style": "text-align: left;" + }, + "children": [ + { + "type": "th", + "children": [ + { + "text": "Product" + } + ] + }, + { + "type": "th", + "children": [ + { + "text": "Cost" + } + ] + }, + { + "type": "th", + "children": [ + { + "text": "Really?" + } + ] + } + ] + } + ] + }, + { + "type": "tbody", + "children": [ + { + "type": "tr", + "children": [ + { + "type": "td", + "children": [ + { + "text": "TinyMCE Cloud" + } + ] + }, + { + "type": "td", + "children": [ + { + "text": "Get started for free" + } + ] + }, + { + "type": "td", + "children": [ + { + "text": "Yes!", + "format": [ + "strong" + ] + } + ] + } + ] + }, + { + "type": "tr", + "children": [ + { + "type": "td", + "children": [ + { + "text": "Plupload" + } + ] + }, + { + "type": "td", + "children": [ + { + "text": "Free" + } + ] + }, + { + "type": "td", + "children": [ + { + "text": "Yes!", + "format": [ + "strong" + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "h2", + "opData": { + "id": 7, + "type": "insert", + "uid": "martincook", + "timestamp": 1752576331000 + }, + "children": [ + { + "text": "Found a bug?" + } + ] + }, + { + "type": "p", + "children": [ + { + "text": " ", + "opData": { + "id": 7, + "type": "remove", + "uid": "martincook", + "timestamp": 1752576331000 + } + }, + { + "text": "If you believe you have found a bug please create an issue on the ", + "opData": { + "id": 7, + "type": "insert", + "uid": "martincook", + "timestamp": 1752576331000 + } + }, + { + "text": "GitHub repo", + "opData": { + "id": 7, + "type": "insert", + "uid": "martincook", + "timestamp": 1752576331000 + }, + "format": [ + { + "type": "a", + "attrs": { + "href": "https://github.com/tinymce/tinymce/issues" + } + } + ] + }, + { + "text": " to report it to the developers.", + "opData": { + "id": 7, + "type": "insert", + "uid": "martincook", + "timestamp": 1752576331000 + } + } + ] + }, + { + "type": "h2", + "children": [ + { + "text": "Finally…" + } + ] + }, + { + "type": "p", + "children": [ + { + "text": "Don’t forget to check out " + }, + { + "text": "Plupload", + "format": [ + { + "type": "a", + "attrs": { + "href": "http://www.plupload.com", + "target": "_blank", + "rel": "noopener" + } + } + ] + }, + { + "text": ", the upload solution featuring HTML5 upload support." + } + ] + }, + { + "type": "p", + "children": [ + { + "text": "Thanks for supporting TinyMCE. We hope it helps you and your users create great content." + } + ] + }, + { + "type": "p", + "children": [ + { + "text": "All the best from the TinyMCE team." + } + ] + } + ] +}; + +tinymce.init({ + selector: 'textarea#suggestededits-access-feedback', + height: 500, + plugins: 'suggestededits advlist anchor autolink code charmap emoticons fullscreen help image link lists media preview searchreplace table', + toolbar: 'undo redo | suggestededits | styles fontsizeinput | bold italic | align bullist numlist | table link image | code', + user_id: 'kalebwilson', + fetch_users: (userIds) => Promise.all(userIds + .map((userId) => new Promise((resolve) => + resolve(userDb[userId] || { id: userId })) + )), + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', + suggestededits_model: model, + suggestededits_content: 'html', + suggestededits_access: 'feedback', // Change this value to set the user's permission to the Suggested Edits view + readonly: false, // Set to true to restrict a user's editing permission +}); \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/suggestededits-access-read/index.html b/modules/ROOT/examples/live-demos/suggestededits-access-read/index.html new file mode 100644 index 0000000000..d0487689c2 --- /dev/null +++ b/modules/ROOT/examples/live-demos/suggestededits-access-read/index.html @@ -0,0 +1,44 @@ + diff --git a/modules/ROOT/examples/live-demos/suggestededits-access-read/index.js b/modules/ROOT/examples/live-demos/suggestededits-access-read/index.js new file mode 100644 index 0000000000..5ca712723f --- /dev/null +++ b/modules/ROOT/examples/live-demos/suggestededits-access-read/index.js @@ -0,0 +1,437 @@ +/** Fake user database */ +const userDb = { + adamhayes: { + id: 'adamhayes', + name: 'Adam Hayes', + avatar: `https://randomuser.me/api/portraits/men/4.jpg`, + }, + martincook: { + id: 'martincook', + name: 'Martin Cook', + avatar: `https://randomuser.me/api/portraits/men/5.jpg`, + }, + kalebwilson: { + id: 'kalebwilson', + name: 'Kaleb Wilson', + avatar: `https://randomuser.me/api/portraits/men/6.jpg`, + }, + sarahjones: { + id: 'sarahjones', + name: 'Sarah Jones', + avatar: `https://randomuser.me/api/portraits/women/1.jpg`, + } +}; + +const model = { + "history": { + "2": [ + { + "id": 1, + "uid": "sarahjones", + "timestamp": 1752576936000, + "feedback": "Nice improvement!" + } + ] + }, + "version": 1, + "contents": [ + { + "type": "p", + "children": [ + { + "type": "img", + "attrs": { + "style": "display: block; margin-left: auto; margin-right: auto;", + "title": "Tiny Logo", + "src": "https://www.tiny.cloud/docs/images/logos/android-chrome-256x256.png", + "alt": "TinyMCE Logo", + "width": "128", + "height": "128" + } + } + ] + }, + { + "type": "h2", + "attrs": { + "style": "text-align: center;" + }, + "children": [ + { + "text": "Welcome to the TinyMCE Suggested Edits " + }, + { + "text": "interactive ", + "opData": { + "id": 1, + "type": "insert", + "uid": "adamhayes", + "timestamp": 1752015064000 + } + }, + { + "text": "demo!" + } + ] + }, + { + "type": "p", + "attrs": { + "style": "text-align: center;" + }, + "children": [ + { + "text": "Try out the Suggested Edits feature" + }, + { + "text": ": type in the editor, apply formatting or delete some content. T", + "opData": { + "id": 2, + "type": "insert", + "uid": "adamhayes", + "timestamp": 1752415064000 + } + }, + { + "text": " by typing in the editor and t", + "opData": { + "id": 2, + "type": "remove", + "uid": "adamhayes", + "timestamp": 1752415064000 + } + }, + { + "text": "hen" + }, + { + "text": ",", + "opData": { + "id": 3, + "type": "insert", + "uid": "adamhayes", + "timestamp": 1752515064000 + } + }, + { + "text": " click" + }, + { + "text": "ing", + "opData": { + "id": 4, + "type": "remove", + "uid": "adamhayes", + "timestamp": 1752515064000 + } + }, + { + "text": " the Review Changes button in the toolbar" + }, + { + "text": " to see your changes", + "opData": { + "id": 5, + "type": "insert", + "uid": "kalebwilson", + "timestamp": 1752615064000 + } + }, + { + "text": "." + } + ] + }, + { + "type": "p", + "attrs": { + "style": "text-align: center;" + }, + "children": [ + { + "text": "And visit the " + }, + { + "text": "pricing page", + "opData": { + "id": 6, + "type": "modify", + "uid": "kalebwilson", + "timestamp": 1752615064000 + }, + "format": [ + { + "type": "a", + "attrs": { + "href": "https://www.tiny.cloud/pricing" + } + } + ], + "oldFormat": [ + { + "type": "a", + "attrs": { + "href": "https://www.tiny.cloud/pricing" + } + }, + "em" + ] + }, + { + "text": " to learn more about our Premium plugins." + } + ] + }, + { + "type": "h2", + "children": [ + { + "text": "A simple table to play with" + } + ] + }, + { + "type": "table", + "attrs": { + "style": "border-collapse: collapse; width: 100%;", + "border": "1" + }, + "children": [ + { + "type": "thead", + "children": [ + { + "type": "tr", + "attrs": { + "style": "text-align: left;" + }, + "children": [ + { + "type": "th", + "children": [ + { + "text": "Product" + } + ] + }, + { + "type": "th", + "children": [ + { + "text": "Cost" + } + ] + }, + { + "type": "th", + "children": [ + { + "text": "Really?" + } + ] + } + ] + } + ] + }, + { + "type": "tbody", + "children": [ + { + "type": "tr", + "children": [ + { + "type": "td", + "children": [ + { + "text": "TinyMCE Cloud" + } + ] + }, + { + "type": "td", + "children": [ + { + "text": "Get started for free" + } + ] + }, + { + "type": "td", + "children": [ + { + "text": "Yes!", + "format": [ + "strong" + ] + } + ] + } + ] + }, + { + "type": "tr", + "children": [ + { + "type": "td", + "children": [ + { + "text": "Plupload" + } + ] + }, + { + "type": "td", + "children": [ + { + "text": "Free" + } + ] + }, + { + "type": "td", + "children": [ + { + "text": "Yes!", + "format": [ + "strong" + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "h2", + "opData": { + "id": 7, + "type": "insert", + "uid": "martincook", + "timestamp": 1752576331000 + }, + "children": [ + { + "text": "Found a bug?" + } + ] + }, + { + "type": "p", + "children": [ + { + "text": " ", + "opData": { + "id": 7, + "type": "remove", + "uid": "martincook", + "timestamp": 1752576331000 + } + }, + { + "text": "If you believe you have found a bug please create an issue on the ", + "opData": { + "id": 7, + "type": "insert", + "uid": "martincook", + "timestamp": 1752576331000 + } + }, + { + "text": "GitHub repo", + "opData": { + "id": 7, + "type": "insert", + "uid": "martincook", + "timestamp": 1752576331000 + }, + "format": [ + { + "type": "a", + "attrs": { + "href": "https://github.com/tinymce/tinymce/issues" + } + } + ] + }, + { + "text": " to report it to the developers.", + "opData": { + "id": 7, + "type": "insert", + "uid": "martincook", + "timestamp": 1752576331000 + } + } + ] + }, + { + "type": "h2", + "children": [ + { + "text": "Finally…" + } + ] + }, + { + "type": "p", + "children": [ + { + "text": "Don’t forget to check out " + }, + { + "text": "Plupload", + "format": [ + { + "type": "a", + "attrs": { + "href": "http://www.plupload.com", + "target": "_blank", + "rel": "noopener" + } + } + ] + }, + { + "text": ", the upload solution featuring HTML5 upload support." + } + ] + }, + { + "type": "p", + "children": [ + { + "text": "Thanks for supporting TinyMCE. We hope it helps you and your users create great content." + } + ] + }, + { + "type": "p", + "children": [ + { + "text": "All the best from the TinyMCE team." + } + ] + } + ] +}; + +tinymce.init({ + selector: 'textarea#suggestededits-access-read', + height: 500, + plugins: 'suggestededits advlist anchor autolink code charmap emoticons fullscreen help image link lists media preview searchreplace table', + toolbar: 'undo redo | suggestededits | styles fontsizeinput | bold italic | align bullist numlist | table link image | code', + user_id: 'kalebwilson', + fetch_users: (userIds) => Promise.all(userIds + .map((userId) => new Promise((resolve) => + resolve(userDb[userId] || { id: userId })) + )), + content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', + suggestededits_model: model, + suggestededits_content: 'html', + suggestededits_access: 'read', // Change this value to set the user's permission to the Suggested Edits view + readonly: false, // Set to true to restrict a user's editing permission +}); \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/suggestededits-access/index.html b/modules/ROOT/examples/live-demos/suggestededits-access/index.html deleted file mode 100644 index 53d3f50664..0000000000 --- a/modules/ROOT/examples/live-demos/suggestededits-access/index.html +++ /dev/null @@ -1,34 +0,0 @@ - diff --git a/modules/ROOT/examples/live-demos/suggestededits-access/index.js b/modules/ROOT/examples/live-demos/suggestededits-access/index.js deleted file mode 100644 index 6c8dd32358..0000000000 --- a/modules/ROOT/examples/live-demos/suggestededits-access/index.js +++ /dev/null @@ -1,46 +0,0 @@ -/** Fake user database */ -const userinfos = { - adamhenderson: { - id: 'adamhenderson', - name: 'Adam Henderson', - avatar: `https://randomuser.me/api/portraits/men/1.jpg`, - }, - michaelcook: { - id: 'michaelcook', - name: 'Michael Cook', - avatar: `https://randomuser.me/api/portraits/men/2.jpg`, - }, - kalebwilson: { - id: 'kalebwilson', - name: 'Kaleb Wilson', - avatar: `https://randomuser.me/api/portraits/men/3.jpg`, - }, - kyleeinstein: { - id: 'kyleeinstein', - name: 'Kyle Einstein', - avatar: `https://randomuser.me/api/portraits/men/4.jpg`, - }, -}; - -const fetch_users = (ids) => { - return new Promise((resolve, reject) => { - const users = ids.map(id => userinfos[id]); - if (users.length > 0) { - resolve(users); - } else { - reject(new Error('No users found')); - } - }); -} - -tinymce.init({ - selector: 'textarea#suggested_edits_access', - height: 500, - plugins: 'suggestededits', - toolbar: 'suggestededits', - content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', - user_id: 'adamhenderson', - fetch_users, - suggestededits_access: 'read', //Change this value to set the user's permission to the Suggested Edits view - readonly: false, //Set to true to restrict a user's editing permission -}); \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/suggestededits-suggestions/index.html b/modules/ROOT/examples/live-demos/suggestededits-suggestions/index.html deleted file mode 100644 index f5fdeedcd9..0000000000 --- a/modules/ROOT/examples/live-demos/suggestededits-suggestions/index.html +++ /dev/null @@ -1,34 +0,0 @@ - diff --git a/modules/ROOT/examples/live-demos/suggestededits-suggestions/index.js b/modules/ROOT/examples/live-demos/suggestededits-suggestions/index.js deleted file mode 100644 index a95f462a59..0000000000 --- a/modules/ROOT/examples/live-demos/suggestededits-suggestions/index.js +++ /dev/null @@ -1,46 +0,0 @@ -/** Fake user database */ -const userinfos = { - adamhenderson: { - id: 'adamhenderson', - name: 'Adam Henderson', - avatar: `https://randomuser.me/api/portraits/men/1.jpg`, - }, - michaelcook: { - id: 'michaelcook', - name: 'Michael Cook', - avatar: `https://randomuser.me/api/portraits/men/2.jpg`, - }, - kalebwilson: { - id: 'kalebwilson', - name: 'Kaleb Wilson', - avatar: `https://randomuser.me/api/portraits/men/3.jpg`, - }, - kyleeinstein: { - id: 'kyleeinstein', - name: 'Kyle Einstein', - avatar: `https://randomuser.me/api/portraits/men/4.jpg`, - }, -}; - -const fetch_users = (ids) => { - return new Promise((resolve, reject) => { - const users = ids.map(id => userinfos[id]); - if (users.length > 0) { - resolve(users); - } else { - reject(new Error('No users found')); - } - }); -} - -tinymce.init({ - selector: 'textarea#suggestededits_suggestions', - height: 500, - plugins: 'suggestededits', - toolbar: 'suggestededits', - content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', - user_id: 'adamhenderson', - suggestededits_access: 'feedback', //change this value to set permission to the Suggested Edits view - readonly: false, //set to true to restrict a user's editing permission - fetch_users -}); \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/suggestededits/example.js b/modules/ROOT/examples/live-demos/suggestededits/example.js index c29f73160f..345c68ebc5 100644 --- a/modules/ROOT/examples/live-demos/suggestededits/example.js +++ b/modules/ROOT/examples/live-demos/suggestededits/example.js @@ -1,4 +1,7 @@ -const config = { +const tinymceElement = document.querySelector('textarea#suggested-edits'); +const model = tinymceElement.getAttribute('suggestededits-model'); + +tinymce.init({ selector: 'textarea#suggested-edits', height: 500, plugins: 'suggestededits advlist anchor autolink code charmap emoticons fullscreen help image link lists media preview searchreplace table', @@ -11,30 +14,7 @@ const config = { .catch(() => ({ id: userId })) // Still return a valid user object even if the fetch fails )), content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }', -} - -const loadTinymce = async () => { - const documentPromise = fetch(`/documents/${documentId}`); // Fetch the document from the server - const modelPromise = fetch(`/models/${documentId}`); // Fetch the model from the same server - - await documentPromise - .then((response) => response.text()) - .then(async (doc) => { - const tinymceElement = document.querySelector('div#tinymce'); - tinymceElement.innerHTML = doc; - - await modelPromise - .then((response) => response.json()) - .then((model) => { - tinymce.init({ - ...config, - suggestededits_model: model, - }); - }) - .catch(() => { - tinymce.init(config); // Initialize without a model if the model fetch fails - }); - }); -}; - -loadTinymce(); + suggestededits_model: model, + suggestededits_access: 'full', + suggestededits_content: 'html' +}); \ No newline at end of file diff --git a/modules/ROOT/examples/live-demos/suggestededits/index.html b/modules/ROOT/examples/live-demos/suggestededits/index.html index b4199ee062..22a924a1b2 100644 --- a/modules/ROOT/examples/live-demos/suggestededits/index.html +++ b/modules/ROOT/examples/live-demos/suggestededits/index.html @@ -1,4 +1,4 @@ -