diff --git a/package.json b/package.json index 7a13c5bf0..364a166a2 100644 --- a/package.json +++ b/package.json @@ -40,8 +40,8 @@ "js-cookie": "^3.0.5", "select2": "git+https://github.com/ivaynberg/select2.git#3.5.4", "sortablejs": "^1.15.0", - "tinymce": "^5.10.7", - "tinymce-i18n": "^22.12.27", + "tinymce": "^6.7.0", + "tinymce-i18n": "^23.10.9", "underscore": "^1.13.6" }, "devDependencies": { diff --git a/src/pat/tinymce/js/links.js b/src/pat/tinymce/js/links.js index 93ab85317..6fbe92779 100644 --- a/src/pat/tinymce/js/links.js +++ b/src/pat/tinymce/js/links.js @@ -4,7 +4,6 @@ import Base from "@patternslib/patternslib/src/core/base"; import events from "@patternslib/patternslib/src/core/events"; import registry from "@patternslib/patternslib/src/core/registry"; -import tinymce from "tinymce/tinymce"; import LinkTemplate from "../templates/link.xml"; import ImageTemplate from "../templates/image.xml"; import RelatedItems from "../../relateditems/relateditems"; @@ -344,61 +343,6 @@ var AnchorLink = LinkType.extend({ }, }); -tinymce.PluginManager.add("ploneimage", function (editor) { - editor.ui.registry.addButton("ploneimage", { - icon: "image", - text: "Insert image", - tooltip: "Insert/edit image", - onAction: editor.settings.addImageClicked, - // stateSelector: "img:not([data-mce-object])", - }); - editor.ui.registry.addMenuItem("ploneimage", { - icon: "image", - text: "Insert image", - onAction: editor.settings.addImageClicked, - // stateSelector: "img:not([data-mce-object])", - }); -}); - -/* register the tinymce plugin */ -tinymce.PluginManager.add("plonelink", function (editor) { - editor.ui.registry.addButton("plonelink", { - icon: "link", - tooltip: "Insert/edit link", - shortcut: "Ctrl+K", - onAction: editor.settings.addLinkClicked, - stateSelector: "a[href]", - }); - editor.ui.registry.addMenuItem("plonelink", { - icon: "link", - text: "Insert link", - shortcut: "Ctrl+K", - onAction: editor.settings.addLinkClicked, - stateSelector: "a[href]", - }); - - editor.ui.registry.addButton("unlink", { - icon: "unlink", - tooltip: "Remove link", - onAction: function () { - editor.execCommand("unlink"); - }, - stateSelector: "a[href]", - }); - - // editor.ui.registry.addButton("Ctrl+K", "", editor.settings.addLinkClicked); - - // editor.ui.registry.addButton("plonelink", { - // icon: "link", - // text: "Insert link", - // shortcut: "Ctrl+K", - // onAction: editor.settings.addLinkClicked, - // stateSelector: "a[href]", - // context: "insert", - // prependToContext: true, - // }); -}); - export default Base.extend({ name: "linkmodal", trigger: ".pat-linkmodal", @@ -861,8 +805,8 @@ export default Base.extend({ if (self.anchorElm) { self.data.target = self.tiny.dom.getAttrib(self.anchorElm, "target"); - } else if (self.tiny.settings.default_link_target) { - self.data.target = self.tiny.settings.default_link_target; + } else if (self.tiny.options.get('link_default_target')) { + self.data.target = self.tiny.options.get('link_default_target'); } if ((value = self.tiny.dom.getAttrib(self.anchorElm, "rel"))) { diff --git a/src/pat/tinymce/tinymce--implementation.js b/src/pat/tinymce/tinymce--implementation.js index d8487660b..a5126a02c 100644 --- a/src/pat/tinymce/tinymce--implementation.js +++ b/src/pat/tinymce/tinymce--implementation.js @@ -149,6 +149,8 @@ export default class TinyMCE { import (`tinymce/skins/ui/${css}/skin.css`); const tinymce = (await import("tinymce/tinymce")).default; + await import("tinymce/models/dom"); + let valid_plugins = []; // tinyMCE Plugins for (const plugin of this.options.tiny.plugins) { @@ -186,18 +188,74 @@ export default class TinyMCE { var tinyOptions = self.options.tiny; if (self.options.inline === true) { self.options.tiny.inline = true; + self.options.tiny.toolbar_mode = "scrolling"; } self.tinyId = self.options.inline ? id + "-editable" : id; // when displaying TinyMCE inline, a separate div is created. tinyOptions.selector = "#" + self.tinyId; - tinyOptions.addLinkClicked = function () { - self.addLinkClicked.apply(self, []); - }; - tinyOptions.addImageClicked = function (file) { - self.addImageClicked.apply(self, [file]); - }; // XXX: disabled skin means it wont load css files which we already // include in widgets.min.css tinyOptions.skin = false; + // do not show the "upgrade" button for plugins + tinyOptions.promotion = false; + + // image plugin + // eslint-disable-next-line no-unused-vars + tinymce.PluginManager.add("ploneimage", (editor, url) => { + editor.ui.registry.addButton("ploneimage", { + icon: "image", + text: "Insert image", + tooltip: "Insert/edit image", + // eslint-disable-next-line no-unused-vars + onAction: (api) => { + self.addImageClicked(); + }, + // stateSelector: "img:not([data-mce-object])", + }); + editor.ui.registry.addMenuItem("ploneimage", { + icon: "image", + text: "Insert image", + // eslint-disable-next-line no-unused-vars + onAction: (api) => { + self.addImageClicked(); + }, + // stateSelector: "img:not([data-mce-object])", + }); + }); + + // link plugin + // eslint-disable-next-line no-unused-vars + tinymce.PluginManager.add("plonelink", function (editor, url) { + editor.ui.registry.addButton("plonelink", { + icon: "link", + tooltip: "Insert/edit link", + shortcut: "Ctrl+K", + // eslint-disable-next-line no-unused-vars + onAction: (api) => { + self.addLinkClicked(); + }, + stateSelector: "a[href]", + }); + editor.ui.registry.addMenuItem("plonelink", { + icon: "link", + text: "Insert link", + shortcut: "Ctrl+K", + // eslint-disable-next-line no-unused-vars + onAction: (api) => { + self.addLinkClicked(); + }, + stateSelector: "a[href]", + }); + + editor.ui.registry.addButton("unlink", { + icon: "unlink", + tooltip: "Remove link", + // eslint-disable-next-line no-unused-vars + onAction: (api) => { + editor.execCommand("unlink"); + }, + stateSelector: "a[href]", + }); + }); tinyOptions.init_instance_callback = function (editor) { if (self.tiny === undefined || self.tiny === null) { @@ -291,13 +349,24 @@ export default class TinyMCE { return url; } // otherwise default tiny behavior - if (self.tiny.settings.relative_urls) { + if (self.tiny.options.get('relative_urls')) { return self.tiny.documentBaseURI.toRelative(url); } - url = self.tiny.documentBaseURI.toAbsolute(url, self.tiny.settings.remove_script_host); + url = self.tiny.documentBaseURI.toAbsolute(url, self.tiny.options.get('remove_script_host')); return url; } + // BBB: TinyMCE 6 has renamed toolbar and menuitem plugins. + // map them here until they are updated in Plone's configuration: + // menu: "formats" -> "styles" + if(tinyOptions?.menu?.format) { + tinyOptions.menu.format.items = tinyOptions.menu.format.items.replace('formats', 'styles'); + } + // toolbar: "styleselect" -> "styles" + if(tinyOptions?.toolbar) { + tinyOptions.toolbar = tinyOptions.toolbar.replace('styleselect', 'styles'); + } + tinymce.init(tinyOptions); self.tiny = tinymce.get(self.tinyId); diff --git a/src/pat/tinymce/tinymce.scss b/src/pat/tinymce/tinymce.scss index 00ed1c659..8d6e22be7 100644 --- a/src/pat/tinymce/tinymce.scss +++ b/src/pat/tinymce/tinymce.scss @@ -113,7 +113,8 @@ div.linkModal { min-width: 0.6em; // enforce a min-width while editing for tables with visual aid turned on } -div.mce-content-body[contenteditable="true"] { +div.mce-content-body[contenteditable="true"], +.tox-tinymce { border: 1px solid var(--bs-border-color); border-radius: var(--bs-border-radius); } diff --git a/src/pat/tinymce/tinymce.test.js b/src/pat/tinymce/tinymce.test.js index c139e8ad4..8b9ca40aa 100644 --- a/src/pat/tinymce/tinymce.test.js +++ b/src/pat/tinymce/tinymce.test.js @@ -130,7 +130,6 @@ describe("TinyMCE", function () { ).appendTo("body"); registry.scan($el); await utils.timeout(10); - console.log(tinymce.get(0).getContent()); expect(tinymce.get(0).getContent()).toEqual("

foobar

"); tinymce.get(0).remove(); }); @@ -141,8 +140,10 @@ describe("TinyMCE", function () { ).appendTo("body"); registry.scan($el); await utils.timeout(10); - expect(tinymce.get(0).settings.plugins).toContain("plonelink ploneimage"); - expect(tinymce.get(0).settings.toolbar).toContain("plonelink ploneimage"); + expect(tinymce.get(0).options.get('plugins')).toContain("ploneimage"); + expect(tinymce.get(0).options.get('plugins')).toContain("plonelink"); + expect(tinymce.get(0).options.get('toolbar')).toContain("plonelink"); + expect(tinymce.get(0).options.get('toolbar')).toContain("ploneimage"); tinymce.get(0).remove(); }); diff --git a/yarn.lock b/yarn.lock index 1013cb28c..2d30ee681 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9787,15 +9787,15 @@ timezone-mock@^1.3.6: resolved "https://registry.yarnpkg.com/timezone-mock/-/timezone-mock-1.3.6.tgz#44e4c5aeb57e6c07ae630a05c528fc4d9aab86f4" integrity sha512-YcloWmZfLD9Li5m2VcobkCDNVaLMx8ohAb/97l/wYS3m+0TIEK5PFNMZZfRcusc6sFjIfxu8qcJT0CNnOdpqmg== -tinymce-i18n@^22.12.27: - version "22.12.27" - resolved "https://registry.yarnpkg.com/tinymce-i18n/-/tinymce-i18n-22.12.27.tgz#9f36a999699bcb2e5fc078d96989aef9952013a7" - integrity sha512-vRanI30NxPKL3igTikx0YTvgflp4R2HbToeiTFvZiNbUtabnUJECKR0ZaJKbFt+6bcscrUPFpiZbwV2sHM2nYA== - -tinymce@^5.10.7: - version "5.10.7" - resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-5.10.7.tgz#d89d446f1962f2a1df6b2b70018ce475ec7ffb80" - integrity sha512-9UUjaO0R7FxcFo0oxnd1lMs7H+D0Eh+dDVo5hKbVe1a+VB0nit97vOqlinj+YwgoBDt6/DSCUoWqAYlLI8BLYA== +tinymce-i18n@^23.10.9: + version "23.10.9" + resolved "https://registry.yarnpkg.com/tinymce-i18n/-/tinymce-i18n-23.10.9.tgz#1b686f6235e7053d8bc235a1f5a74be7c4998a87" + integrity sha512-CwO5pbfhO+GzFXMkTxzV1G8JSSY9mu8lkXQ53nuGBB57m5YqN+jLDz2NZZiFIZ76OZauGf4hjrcIxyZlggpuZg== + +tinymce@^6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-6.7.0.tgz#0ec245502cdefbfa0ff9042b423ac9a01e781423" + integrity sha512-Wf2RSobIXQ7XNw3/v4z1lPGiH3Pjsmc/6/7fG28aIS6uVWj/7IhvOPuwfJJDeOx0o0D3nSnoLHgR2KU8JAdE+w== tippy.js@^6.3.7: version "6.3.7"