Skip to content

Commit

Permalink
feat(pat tinymce): Improve tinymce async initialization. Proper fallb…
Browse files Browse the repository at this point in the history
…ack when specific languages are not found, and avoid errors for missing or not found plugins. fixes gh-1253
  • Loading branch information
frapell authored and petschki committed Dec 9, 2022
1 parent b779409 commit a4d4e78
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 98 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
"js-cookie": "^3.0.1",
"select2": "git+https://github.com/ivaynberg/select2.git#3.5.4",
"sortablejs": "^1.15.0",
"tinymce": "^5.10.2",
"tinymce-i18n": "^22.10.18",
"tinymce": "^5.10.7",
"tinymce-i18n": "^22.12.4",
"underscore": "^1.13.6"
},
"devDependencies": {
Expand Down
182 changes: 95 additions & 87 deletions src/pat/tinymce/tinymce--implementation.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import $ from "jquery";
import I18n from "../../core/i18n";
import logger from "@patternslib/patternslib/src/core/logging";
import _t from "../../core/i18n-wrapper";
import utils from "../../core/utils";

const log = logger.getLogger("tinymce--implementation");

let LinkModal = null;

export default class TinyMCE {
Expand Down Expand Up @@ -108,31 +111,30 @@ export default class TinyMCE {
}
return url;
}
async initLanguage(call_back) {
async initLanguage() {
var self = this;
var i18n = new I18n();
var lang = i18n.currentLanguage;
if (lang !== "en" && self.options.tiny.language !== "en") {
try {
await import(`tinymce-i18n/langs5/${lang}`);
} catch (e) {
log.debug("Could not load TinyMCE language: ", lang);
try {
// expected lang not available, let's fallback to closest one
if (lang.split("_") > 1) {
if (lang.split("_").length > 1) {
lang = lang.split("_")[0];
} else if (lang.split("-") > 1) {
lang = lang.split("-")[0];
} else {
lang = lang + "_" + lang.toUpperCase();
}
log.debug("Trying with: ", lang);
await import(`tinymce-i18n/langs5/${lang}`);
} catch {
console.log("Could not load TinyMCE language:", lang);
self.options.tiny.language = lang;
} catch (e) {
log.debug("Could not load TinyMCE language. Fallback to English");
self.options.tiny.language = "en";
}
}
call_back();
} else {
call_back();
}
}
async init() {
Expand All @@ -141,14 +143,20 @@ export default class TinyMCE {
import("tinymce/skins/ui/oxide/skin.css");

const tinymce = (await import("tinymce/tinymce")).default;

let valid_plugins = [];
// tinyMCE Plugins
for (const plugin of this.options.tiny.plugins) {
if (plugin == 'plonelink' || plugin == 'ploneimage'){
continue;
}
await import("tinymce/plugins/" + plugin);
try{
await import("tinymce/plugins/" + plugin);
valid_plugins.push(plugin);
} catch (e) {
log.debug("Could not load TinyMCE plugin: ", plugin);
}
}
this.options.tiny.plugins = valid_plugins;

await import("tinymce/themes/silver");

Expand Down Expand Up @@ -212,95 +220,95 @@ export default class TinyMCE {
});
};

self.initLanguage(function () {
if (typeof self.options.folderTypes === "string") {
self.options.folderTypes = self.options.folderTypes.split(",");
}
await self.initLanguage();

if (typeof self.options.imageTypes === "string") {
self.options.imageTypes = self.options.imageTypes.split(",");
}
if (typeof self.options.folderTypes === "string") {
self.options.folderTypes = self.options.folderTypes.split(",");
}

if (self.options.inline === true) {
// create a div, which will be made content-editable by TinyMCE and
// copy contents from textarea to it. Then hide textarea.
self.$el.after(
'<div id="' + self.tinyId + '">' + self.$el.val() + "</div>"
);
self.$el.hide();
}
if (typeof self.options.imageTypes === "string") {
self.options.imageTypes = self.options.imageTypes.split(",");
}

if (self.options.inline === true) {
// create a div, which will be made content-editable by TinyMCE and
// copy contents from textarea to it. Then hide textarea.
self.$el.after(
'<div id="' + self.tinyId + '">' + self.$el.val() + "</div>"
);
self.$el.hide();
}

if (
tinyOptions.importcss_file_filter &&
typeof tinyOptions.importcss_file_filter.indexOf === "function" &&
tinyOptions.importcss_file_filter.indexOf(",") !== -1
) {
// need a custom function to check now
var files = tinyOptions.importcss_file_filter.split(",");
if (
tinyOptions.importcss_file_filter &&
typeof tinyOptions.importcss_file_filter.indexOf === "function" &&
tinyOptions.importcss_file_filter.indexOf(",") !== -1
) {
// need a custom function to check now
var files = tinyOptions.importcss_file_filter.split(",");

tinyOptions.importcss_file_filter = function (value) {
for (var i = 0; i < files.length; i++) {
if (value.indexOf(files[i]) !== -1) {
return true;
}
tinyOptions.importcss_file_filter = function (value) {
for (var i = 0; i < files.length; i++) {
if (value.indexOf(files[i]) !== -1) {
return true;
}
return false;
};
}
}
return false;
};
}

if (
tinyOptions.importcss_selector_filter &&
tinyOptions.importcss_selector_filter.length
) {
tinyOptions.importcss_selector_filter = new RegExp(
tinyOptions.importcss_selector_filter
);
}
if (
tinyOptions.importcss_selector_filter &&
tinyOptions.importcss_selector_filter.length
) {
tinyOptions.importcss_selector_filter = new RegExp(
tinyOptions.importcss_selector_filter
);
}

if (tinyOptions.importcss_groups && tinyOptions.importcss_groups.length) {
for (var i = 0; i < tinyOptions.importcss_groups.length; i++) {
if (
tinyOptions.importcss_groups[i].filter &&
tinyOptions.importcss_groups[i].filter.length
) {
tinyOptions.importcss_groups[i].filter = new RegExp(
tinyOptions.importcss_groups[i].filter
);
}
if (tinyOptions.importcss_groups && tinyOptions.importcss_groups.length) {
for (var i = 0; i < tinyOptions.importcss_groups.length; i++) {
if (
tinyOptions.importcss_groups[i].filter &&
tinyOptions.importcss_groups[i].filter.length
) {
tinyOptions.importcss_groups[i].filter = new RegExp(
tinyOptions.importcss_groups[i].filter
);
}
}
}

/* If TinyMCE is rendered inside of a modal, set an ID on
* .plone-modal-dialog and use that as the ui_container
* setting for TinyMCE to anchor it there. This ensures that
* sub-menus are displayed relative to the modal rather than
* the document body.
* Generate a random id and append it, because there might be
* more than one TinyMCE in the DOM.
*/
var modal_container = self.$el.parents(".plone-modal-dialog");
/* If TinyMCE is rendered inside of a modal, set an ID on
* .plone-modal-dialog and use that as the ui_container
* setting for TinyMCE to anchor it there. This ensures that
* sub-menus are displayed relative to the modal rather than
* the document body.
* Generate a random id and append it, because there might be
* more than one TinyMCE in the DOM.
*/
var modal_container = self.$el.parents(".plone-modal-dialog");

if (modal_container.length > 0) {
var random_id = Math.random().toString(36).substring(2, 15);
modal_container.attr("id", "tiny-ui-container-" + random_id);
tinyOptions["ui_container"] = "#tiny-ui-container-" + random_id;
}
if (modal_container.length > 0) {
var random_id = Math.random().toString(36).substring(2, 15);
modal_container.attr("id", "tiny-ui-container-" + random_id);
tinyOptions["ui_container"] = "#tiny-ui-container-" + random_id;
}

tinymce.init(tinyOptions);
self.tiny = tinymce.get(self.tinyId);
tinymce.init(tinyOptions);
self.tiny = tinymce.get(self.tinyId);

/* tiny really should be doing this by default
* but this fixes overlays not saving data */
var $form = self.$el.parents("form");
$form.on("submit", function () {
if (self.options.inline === true) {
// save back from contenteditable to textarea
self.$el.val(self.tiny.getContent());
} else {
// normal case
self.tiny.save();
}
});
/* tiny really should be doing this by default
* but this fixes overlays not saving data */
var $form = self.$el.parents("form");
$form.on("submit", function () {
if (self.options.inline === true) {
// save back from contenteditable to textarea
self.$el.val(self.tiny.getContent());
} else {
// normal case
self.tiny.save();
}
});
}
destroy() {
Expand Down
2 changes: 1 addition & 1 deletion src/pat/tinymce/tinymce.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export default Base.extend({
var lang = i18n.currentLanguage;
this.options.tiny.language = lang;
this.instance = new implementation(this.el, this.options);
this.instance.init();
await this.instance.init();
},
destroy: function () {
this.instance.destroy();
Expand Down
16 changes: 8 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9784,17 +9784,17 @@ timezone-mock@^1.3.4:
resolved "https://registry.yarnpkg.com/timezone-mock/-/timezone-mock-1.3.4.tgz#16cc40bfad10d461f8a41ed7396eeb6ea1e1b2b3"
integrity sha512-B0CGmOgMPVUZqp63eU/FGcDaL68JjHeiVnCF24K99Kj6AwCV15BHWMLCv8ZKSUq5oyVHTtg7p1ajOWfXB+0wnQ==

tinymce-i18n@^22.10.18:
version "22.10.18"
resolved "https://registry.yarnpkg.com/tinymce-i18n/-/tinymce-i18n-22.10.18.tgz#4a7a0b7c8a75f354d7ee48a4df7990414c9a614a"
integrity sha512-p1nuOxBJWIsQ4vB2s30BGgwVBtdTqzAO464htmU+AAirKoU0cZTX7QO4nXQKb+kXyednWwPSqw4gcw+Jbm8OSg==
tinymce-i18n@^22.12.4:
version "22.12.4"
resolved "https://registry.yarnpkg.com/tinymce-i18n/-/tinymce-i18n-22.12.4.tgz#c15d5263702e24c85f038a48b9d42f07b6393c97"
integrity sha512-WbyEJnFCAUhDV5gxw55y9evQFB7PGTFJ3+2Aki6DoOBDDOpYNuZggGGrNAKExmDKtlJ4tSn+FI1Mhq2QZBsNLw==
dependencies:
js-beautify "^1.14.3"

tinymce@^5.10.2:
version "5.10.6"
resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-5.10.6.tgz#ea03927e9d20c035619dfd32ec4fd471c55e32c5"
integrity sha512-bnF2LUoycDsoZZLQBNHbOijrmoJuEeR1rQdqgo4s77BedufpOVnDh00OZKbseHeTMCxhVH05wvOqxLsi6vpeZw==
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==

tippy.js@^6.3.7:
version "6.3.7"
Expand Down

0 comments on commit a4d4e78

Please sign in to comment.