diff --git a/administrator/language/en-GB/en-GB.plg_editors_tinymce.ini b/administrator/language/en-GB/en-GB.plg_editors_tinymce.ini
index 462f8f47a8352..c09e78cba8ba5 100644
--- a/administrator/language/en-GB/en-GB.plg_editors_tinymce.ini
+++ b/administrator/language/en-GB/en-GB.plg_editors_tinymce.ini
@@ -38,8 +38,8 @@ PLG_TINY_FIELD_RESIZE_HORIZONTAL_LABEL="Horizontal Resizing"
PLG_TINY_FIELD_RESIZING_LABEL="Resizing"
PLG_TINY_FIELD_SETACCESS_LABEL="Assign this Set to"
PLG_TINY_FIELD_SKIN_ADMIN_LABEL="Administrator Skin"
-PLG_TINY_FIELD_SKIN_INFO_DESC="Copy your new skins to: /media/editors/tinymce/skins."
-PLG_TINY_FIELD_SKIN_INFO_LABEL="For customised skins go to: Skin Creator"
+PLG_TINY_FIELD_SKIN_INFO_DESC="Copy your new skins to: /media/editors/tinymce/skins/ui."
+PLG_TINY_FIELD_SKIN_INFO_LABEL="For customised skins go to: Skin Creator"
PLG_TINY_FIELD_SKIN_LABEL="Site Skin"
PLG_TINY_FIELD_URLS_LABEL="URLs"
PLG_TINY_FIELD_VALIDELEMENTS_DESC="Defines which elements will stay in the edited text when the editor saves (the default rule set for this option is a mixture of the full HTML5 and HTML4 specification)."
diff --git a/build/build-modules-js/init.es6.js b/build/build-modules-js/init.es6.js
index b34e259d9e467..11cb068c5ff1d 100644
--- a/build/build-modules-js/init.es6.js
+++ b/build/build-modules-js/init.es6.js
@@ -226,9 +226,9 @@ const copyFiles = (options) => {
Fs.writeFileSync(`${RootPath}/plugins/editors/tinymce/tinymce.xml`, tinyXml, { encoding: 'UTF-8' });
// Remove that sourcemap...
- let tinyWrongMap = Fs.readFileSync(`${RootPath}/media/vendor/tinymce/skins/lightgray/skin.min.css`, { encoding: 'UTF-8' });
+ let tinyWrongMap = Fs.readFileSync(`${RootPath}/media/vendor/tinymce/skins/ui/oxide/skin.min.css`, { encoding: 'UTF-8' });
tinyWrongMap = tinyWrongMap.replace('/*# sourceMappingURL=skin.min.css.map */', '');
- Fs.writeFileSync(`${RootPath}/media/vendor/tinymce/skins/lightgray/skin.min.css`, tinyWrongMap, { encoding: 'UTF-8' });
+ Fs.writeFileSync(`${RootPath}/media/vendor/tinymce/skins/ui/oxide/skin.min.css`, tinyWrongMap, { encoding: 'UTF-8' });
} else {
['js', 'css', 'filesExtra'].forEach((type) => {
if (!vendor[type]) return;
diff --git a/build/media_source/plg_editors_tinymce/css/tinymce-builder.css b/build/media_source/plg_editors_tinymce/css/tinymce-builder.css
deleted file mode 100644
index a9ad10dabdf8c..0000000000000
--- a/build/media_source/plg_editors_tinymce/css/tinymce-builder.css
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved.
- * @license GNU General Public License version 2 or later; see LICENSE.txt
- */
-
-#joomla-tinymce-builder {
- margin-left: -220px;
-}
-.mce-menubar,
-.mce-panel {
- min-height: 18px;
- border-bottom: 1px solid rgba(217,217,217,.52);
- white-space: normal;
-}
-.mce-tinymce {
- margin-bottom: 20px;
- clear: both;
-}
-.mce-panel .drop-area-highlight {
- background-color: #d0d0d0;
-}
-.mce-panel .mce-btn.ui-state-highlight {
- height: 28px;
- width: 40px;
- background-color: #409740;
- border: 1px solid #f0f0f0;
-}
-.timymce-builder-toolbar .mce-btn.ui-state-highlight {
- height: 22px;
-}
diff --git a/build/media_source/plg_editors_tinymce/js/tinymce-builder.es5.js b/build/media_source/plg_editors_tinymce/js/tinymce-builder.es5.js
deleted file mode 100644
index 6a1fd023ed33d..0000000000000
--- a/build/media_source/plg_editors_tinymce/js/tinymce-builder.es5.js
+++ /dev/null
@@ -1,316 +0,0 @@
-/**
- * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved.
- * @license GNU General Public License version 2 or later; see LICENSE.txt
- */
-
-;(function($) {
- "use strict";
-
- /**
- * Fake TinyMCE object to allow to use TinyMCE translation for the button labels
- *
- * @since 3.7.0
- */
- window.tinymce = {
- langCode: 'en',
- langStrings: {},
- addI18n: function (code, strings){
- this.langCode = code;
- this.langStrings = strings || {};
- },
- translate: function (string){
- return this.langStrings[string] ? this.langStrings[string] : string;
- }
- };
-
- /**
- * Joomla TinyMCE Builder
- *
- * @param {HTMLElement} container
- * @param {Object} options
- * @constructor
- *
- * @since 3.7.0
- */
- var JoomlaTinyMCEBuilder = function(container, options) {
- this.$container = $(container);
- this.options = options;
-
- // Find source containers
- this.$sourceMenu = this.$container.find('.timymce-builder-menu.source');
- this.$sourceToolbar = this.$container.find('.timymce-builder-toolbar.source');
-
- // Find target containers
- this.$targetMenu = this.$container.find('.timymce-builder-menu.target');
- this.$targetToolbar = this.$container.find('.timymce-builder-toolbar.target');
-
- // Render Source elements
- this.$sourceMenu.each(function(i, element){
- this.renderBar(element, 'menu');
- }.bind(this));
- this.$sourceToolbar.each(function(i, element){
- this.renderBar(element, 'toolbar');
- }.bind(this));
-
- // Render Target elements
- this.$targetMenu.each(function(i, element){
- this.renderBar(element, 'menu', null, true);
- }.bind(this));
- this.$targetToolbar.each(function(i, element){
- this.renderBar(element, 'toolbar', null, true);
- }.bind(this));
-
- // Set up "drag&drop" stuff
- var $copyHelper = null, removeIntent = false, self = this;
- this.$sourceMenu.sortable({
- connectWith: this.$targetMenu,
- items: '.mce-btn',
- cancel: '',
- placeholder: 'mce-btn ui-state-highlight',
- start: function(event, ui) {
- self.$targetMenu.addClass('drop-area-highlight');
- },
- helper: function(event, el) {
- $copyHelper = el.clone().insertAfter(el);
- return el;
- },
- stop: function() {
- $copyHelper && $copyHelper.remove();
- self.$targetMenu.removeClass('drop-area-highlight');
- }
- });
-
- this.$sourceToolbar.sortable({
- connectWith: this.$targetToolbar,
- items: '.mce-btn',
- cancel: '',
- placeholder: 'mce-btn ui-state-highlight',
- start: function(event, ui) {
- self.$targetToolbar.addClass('drop-area-highlight');
- },
- helper: function(event, el) {
- $copyHelper = el.clone().insertAfter(el);
- return el;
- },
- stop: function() {
- $copyHelper && $copyHelper.remove();
- self.$targetToolbar.removeClass('drop-area-highlight');
- }
- });
-
- $().add(this.$targetMenu).add(this.$targetToolbar).sortable({
- items: '.mce-btn',
- cancel: '',
- placeholder: 'mce-btn ui-state-highlight',
- receive: function(event, ui) {
- $copyHelper = null;
- var $el = ui.item, $cont = $(this);
- self.appendInput($el, $cont.data('group'), $cont.data('set'))
- },
- over: function (event, ui) {
- removeIntent = false;
- },
- out: function (event, ui) {
- removeIntent = true;
- },
- beforeStop: function (event, ui) {
- if(removeIntent){
- ui.item.remove();
- }
- }
- });
-
- // Bind actions buttons
- this.$container.on('click', '.button-action', function(event){
- var $btn = $(event.target), action = $btn.data('action'), options = $btn.data();
-
- if (this[action]) {
- this[action].call(this, options);
- } else {
- throw new Error('Unsupported action ' + action);
- }
- }.bind(this));
-
- };
-
- /**
- * Render the toolbar/menubar
- *
- * @param {HTMLElement} container The toolbar container
- * @param {String} type The type toolbar or menu
- * @param {Array|null} value The value
- * @param {Boolean} withInput Whether append input
- *
- * @since 3.7.0
- */
- JoomlaTinyMCEBuilder.prototype.renderBar = function(container, type, value, withInput) {
- var $container = $(container),
- group = $container.data('group'),
- set = $container.data('set'),
- items = type === 'menu' ? this.options.menus : this.options.buttons,
- value = value ? value : ($container.data('value') || []),
- item, name, $btn;
-
- for ( var i = 0, l = value.length; i < l; i++ ) {
- name = value[i];
- item = items[name];
-
- if (!item) {
- continue;
- }
-
- $btn = this.createButton(name, item, type);
- $container.append($btn);
-
- // Enable tooltip
- if ($btn.tooltip) {
- $btn.tooltip({trigger: 'hover'});
- }
-
- // Add input
- if (withInput) {
- this.appendInput($btn, group, set);
- }
- }
- };
-
- /**
- * Create the element needed for renderBar()
- * @param {String} name
- * @param {Object} info
- * @param {String} type
- *
- * @return {jQuery}
- *
- * @since 3.7.0
- */
- JoomlaTinyMCEBuilder.prototype.createButton = function(name, info, type){
- var $element = $('
', {
- 'class': 'mce-btn',
- 'data-name': name,
- 'data-toggle': 'tooltip',
- 'title': tinymce.translate(info.label)
- });
- var $btn = $('', {
- 'type': 'button'
- });
- $element.append($btn);
-
- if (type === 'menu') {
- $btn.html('' + tinymce.translate(info.label) + ' ');
- } else {
- $element.addClass('mce-btn-small');
- $btn.html(info.text ? tinymce.translate(info.text) : '');
- }
-
- return $element;
- };
-
- /**
- * Append input to the button item
- * @param {HTMLElement} element
- * @param {String} group
- * @param {String} set
- *
- * @since 3.7.0
- */
- JoomlaTinyMCEBuilder.prototype.appendInput = function (element, group, set) {
- var $el = $(element),
- name = this.options.formControl + '[' + set + '][' + group + '][]',
- $input = $('', {
- type: 'hidden',
- name: name,
- value: $el.data('name')
- });
-
- $el.append($input);
- };
-
- /**
- * Set Selected preset to specific set
- * @param {Object} options Options {set: 1, preset: 'presetName'}
- */
- JoomlaTinyMCEBuilder.prototype.setPreset = function (options) {
- var set = options.set, preset = this.options.toolbarPreset[options.preset] || null;
-
- if (!preset) {
- throw new Error('Unknown Preset "' + options.preset + '"');
- }
-
- var $container, type;
- for (var group in preset) {
- if (!preset.hasOwnProperty(group)) {
- continue;
- }
-
- // Find correct container for current set
- if (group === 'menu') {
- type = 'menu';
- $container = this.$targetMenu.filter('[data-group="' + group + '"][data-set="' + set + '"]');
- } else {
- type = 'toolbar'
- $container = this.$targetToolbar.filter('[data-group="' + group + '"][data-set="' + set + '"]');
- }
-
- // Reset existing values
- $container.empty();
-
- // Set new
- this.renderBar($container, type, preset[group], true);
- }
- };
-
- /**
- * Clear the pane for specific set
- * @param {Object} options Options {set: 1}
- */
- JoomlaTinyMCEBuilder.prototype.clearPane = function (options) {
- var set = options.set;
-
- this.$targetMenu.filter('[data-set="' + set + '"]').empty();
- this.$targetToolbar.filter('[data-set="' + set + '"]').empty();
- };
-
-
- // Init the builder
- $(document).ready(function(){
- var options = Joomla.getOptions ? Joomla.getOptions('plg_editors_tinymce_builder', {})
- : (Joomla.optionsStorage.plg_editors_tinymce_builder || {});
-
- new JoomlaTinyMCEBuilder($('#joomla-tinymce-builder'), options);
-
- $("#set-tabs a").on('click', function (event) {
- event.preventDefault();
- $(this).tab("show");
- });
-
- // Allow to select the group only once per the set
- var $accessSelects = $('#joomla-tinymce-builder').find('.access-select');
- toggleAvailableOption();
- $accessSelects.on('change', function () {
- toggleAvailableOption();
- });
-
- function toggleAvailableOption () {
- $accessSelects.find('option[disabled]').removeAttr('disabled');
-
- // Disable already selected options
- $accessSelects.each(function () {
- var $select = $(this), val = $select.val() || [], query = [],
- $options = $accessSelects.not(this).find('option');
-
- for (var i = 0, l = val.length; i < l; i++ ) {
- if (!val[i]) continue;
- query.push('[value="' + val[i] + '"]');
- }
-
- if (query.length) {
- $options.filter(query.join(',')).attr('disabled', 'disabled');
- }
- });
-
- // Update Chosen
- $accessSelects.trigger('chosen:updated');
- }
- });
-}(jQuery));
diff --git a/build/media_source/plg_editors_tinymce/js/tinymce-builder.es6.js b/build/media_source/plg_editors_tinymce/js/tinymce-builder.es6.js
new file mode 100644
index 0000000000000..6f0120d50d18a
--- /dev/null
+++ b/build/media_source/plg_editors_tinymce/js/tinymce-builder.es6.js
@@ -0,0 +1,482 @@
+/**
+ * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ */
+
+Joomla = window.Joomla || {};
+
+((Joomla, window) => {
+ 'use strict';
+
+ /**
+ * Fake TinyMCE object to allow to use TinyMCE translation for the button labels
+ *
+ * @since 3.7.0
+ */
+ const tinymce = {
+ langCode: 'en',
+ langStrings: {},
+ icons: {
+ 'accessibility-check': '',
+ 'align-center': '',
+ 'align-justify': '',
+ 'align-left': '',
+ 'align-none': '',
+ 'align-right': '',
+ 'arrow-left': '',
+ 'arrow-right': '',
+ bold: '',
+ bookmark: '',
+ 'border-width': '',
+ brightness: '',
+ browse: '',
+ cancel: '',
+ 'change-case': '',
+ 'character-count': '',
+ checklist: '',
+ checkmark: '',
+ 'chevron-down': '',
+ 'chevron-left': '',
+ 'chevron-right': '',
+ 'chevron-up': '',
+ close: '',
+ 'code-sample': '',
+ 'color-levels': '',
+ 'color-picker': '',
+ 'color-swatch-remove-color': '',
+ 'color-swatch': '',
+ comment: '',
+ contrast: '',
+ copy: '',
+ crop: '',
+ cut: '',
+ 'document-properties': '',
+ drag: '',
+ duplicate: '',
+ 'edit-image': '',
+ 'embed-page': '',
+ embed: '',
+ emoji: '',
+ fill: '',
+ 'flip-horizontally': '',
+ 'flip-vertically': '',
+ 'format-painter': '',
+ fullscreen: '',
+ gamma: '',
+ help: '',
+ 'highlight-bg-color': '',
+ home: '',
+ 'horizontal-rule': '',
+ 'image-options': '',
+ image: '',
+ indent: '',
+ indeterminate: '',
+ info: '',
+ 'insert-character': '',
+ 'insert-time': '',
+ invert: '',
+ italic: '',
+ line: '',
+ link: '',
+ 'list-bull-circle': '',
+ 'list-bull-default': '',
+ 'list-bull-square': '',
+ 'list-num-default': '',
+ 'list-num-lower-alpha': '',
+ 'list-num-lower-greek': '',
+ 'list-num-lower-roman': '',
+ 'list-num-upper-alpha': '',
+ 'list-num-upper-roman': '',
+ lock: '',
+ ltr: '',
+ 'more-drawer': '',
+ 'new-document': '',
+ 'new-tab': '',
+ 'non-breaking': '',
+ notice: '',
+ 'ordered-list': '',
+ orientation: '',
+ outdent: '',
+ 'page-break': '',
+ paragraph: '',
+ 'paste-text': '',
+ paste: '',
+ 'permanent-pen': '',
+ plus: '',
+ preferences: '',
+ preview: '',
+ print: '',
+ quote: '',
+ redo: '',
+ reload: '',
+ 'remove-formatting': '',
+ remove: '',
+ 'resize-handle': '',
+ resize: '',
+ 'restore-draft': '',
+ 'rotate-left': '',
+ 'rotate-right': '',
+ rtl: '',
+ save: '',
+ search: '',
+ 'select-all': '',
+ selected: '',
+ settings: '',
+ sharpen: '',
+ sourcecode: '',
+ 'spell-check': '',
+ 'strike-through': '',
+ subscript: '',
+ superscript: '',
+ 'table-cell-properties': '',
+ 'table-cell-select-all': '',
+ 'table-cell-select-inner': '',
+ 'table-delete-column': '',
+ 'table-delete-row': '',
+ 'table-delete-table': '',
+ 'table-insert-column-after': '',
+ 'table-insert-column-before': '',
+ 'table-insert-row-above': '',
+ 'table-insert-row-after': '',
+ 'table-left-header': '',
+ 'table-merge-cells': '',
+ 'table-row-properties': '',
+ 'table-split-cells': '',
+ 'table-top-header': '',
+ table: '',
+ template: '',
+ 'temporary-placeholder': '',
+ 'text-color': '',
+ toc: '',
+ translate: '',
+ underline: '',
+ undo: '',
+ unlink: '',
+ unlock: '',
+ 'unordered-list': '',
+ unselected: '',
+ upload: '',
+ user: '',
+ warning: '',
+ 'zoom-in': '',
+ 'zoom-out': '',
+ },
+ iconsmap: {
+ aligncenter: 'align-center',
+ alignjustify: 'align-justify',
+ alignleft: 'align-left',
+ alignright: 'align-right',
+ anchor: 'bookmark',
+ blockquote: 'quote',
+ bullist: 'unordered-list',
+ charmap: 'insert-character',
+ code: 'sourcecode',
+ codesample: 'code-sample',
+ emoticons: 'emoji',
+ hr: 'horizontal-rule',
+ insertdatetime: 'insert-time',
+ media: 'embed',
+ nonbreaking: 'non-breaking',
+ numlist: 'ordered-list',
+ pagebreak: 'page-break',
+ pastetext: 'paste-text',
+ removeformat: 'remove-formatting',
+ searchreplace: 'search',
+ strikethrough: 'strike-through',
+ visualblocks: 'paragraph',
+ visualchars: 'paragraph',
+ },
+ addI18n: (code, strings) => {
+ tinymce.langCode = code;
+ tinymce.langStrings = strings || {};
+ },
+ translate: string => (tinymce.langStrings[string] || string),
+ showIcon: (name) => {
+ const iconname = tinymce.iconsmap[name] || name;
+ return tinymce.icons[iconname] || tinymce.icons[name] || name;
+ },
+ };
+
+ window.tinymce = tinymce;
+
+ const TinyMCEBuilder = (container, options) => {
+ const $sourceMenu = container.querySelector('.timymce-builder-menu.source');
+ const $sourceToolbar = container.querySelector('.timymce-builder-toolbar.source');
+
+ const $targetMenu = container.querySelectorAll('.timymce-builder-menu.target');
+ const $targetToolbar = container.querySelectorAll('.timymce-builder-toolbar.target');
+
+ /**
+ * Append input to the button item
+ * @param {HTMLElement} element
+ * @param {String} group
+ * @param {String} set
+ *
+ * @since 3.7.0
+ */
+ const appendInput = (element, group, set) => {
+ const name = `${options.formControl}[${set}][${group}][]`;
+ const value = element.getAttribute('data-name');
+
+ const input = ``;
+
+ element.innerHTML += input;
+ };
+
+ /**
+ * Create the element needed for renderBar()
+ * @param {String} name
+ * @param {Object} info
+ * @param {String} type
+ *
+ * @return {jQuery}
+ *
+ * @since 3.7.0
+ */
+ const createButton = (name, info, type) => {
+ const title = tinymce.translate(info.label);
+
+ let content = '';
+ let bclass = 'tox-mbtn';
+
+ if (type === 'menu') {
+ content = title;
+ } else if (info.text) {
+ const text = tinymce.translate(info.text);
+
+ bclass += ' tox-tbtn--bespoke';
+
+ const chevron = tinymce.showIcon('chevron-down');
+
+ content = info.text !== '|' ? `${text}${chevron}
` : text;
+ } else {
+ content = tinymce.showIcon(name);
+ }
+
+ const $btn = ``;
+
+ return $btn;
+ };
+
+ /**
+ * Render the toolbar/menubar
+ *
+ * @param {HTMLElement} box The toolbar container
+ * @param {String} type The type toolbar or menu
+ * @param {Array|null} value The value
+ * @param {Boolean} withInput Whether append input
+ *
+ * @since 3.7.0
+ */
+ const renderBar = (box, type, val, withInput) => {
+ const group = box.getAttribute('data-group');
+ const set = box.getAttribute('data-set');
+ const items = type === 'menu' ? options.menus : options.buttons;
+ const value = val || JSON.parse(box.getAttribute('data-value')) || [];
+ let item;
+ let name;
+ let $btn;
+
+ for (let i = 0, l = value.length; i < l; i += 1) {
+ name = value[i];
+ item = items[name];
+
+ if (item) {
+ $btn = createButton(name, item, type);
+ box.innerHTML += $btn;
+
+ const newbutton = box.querySelector('.tox-mbtn:last-child');
+
+ // Enable tooltip
+ if (newbutton.tooltip) {
+ newbutton.tooltip({ trigger: 'hover' });
+ }
+
+ // Add input
+ if (withInput) {
+ appendInput(newbutton, group, set);
+ }
+ }
+ }
+ };
+
+ /**
+ * Clear the pane for specific set
+ * @param {Object} sets Options {set: 1}
+ */
+ const clearPane = (sets) => {
+ const { set: item } = sets;
+
+ $targetMenu.forEach((elem) => {
+ if (elem.getAttribute('data-set') === item) {
+ elem.innerHTML = '';
+ }
+ });
+
+ $targetToolbar.forEach((elem) => {
+ if (elem.getAttribute('data-set') === item) {
+ elem.innerHTML = '';
+ }
+ });
+ };
+
+ /**
+ * Set Selected preset to specific set
+ * @param {Object} attrib Options {set: 1, preset: 'presetName'}
+ */
+ const setPreset = (attrib) => {
+ const { set: item } = attrib;
+ const preset = options.toolbarPreset[attrib.preset] || null;
+
+ if (!preset) {
+ throw new Error(`Unknown Preset "${attrib.preset}"`);
+ }
+
+ clearPane(attrib);
+
+ Object.keys(preset).forEach((group) => {
+ const type = group === 'menu' ? 'menu' : 'toolbar';
+
+ // Find correct container for current set
+ if (group === 'menu') {
+ $targetMenu.forEach((target) => {
+ if (target.getAttribute('data-group') === group && target.getAttribute('data-set') === item) {
+ renderBar(target, type, preset[group], true);
+ }
+ });
+ } else {
+ $targetToolbar.forEach((target) => {
+ if (target.getAttribute('data-group') === group && target.getAttribute('data-set') === item) {
+ renderBar(target, type, preset[group], true);
+ }
+ });
+ }
+ });
+ };
+
+ // Build menu + toolbar
+ renderBar($sourceMenu, 'menu');
+ renderBar($sourceToolbar, 'toolbar');
+
+ // Initialize drag & drop
+ /* global dragula */
+ const drakeMenu = dragula([$sourceMenu], {
+ copy: (el, source) => source === $sourceMenu,
+ accepts: (el, target) => target !== $sourceMenu,
+ removeOnSpill: true,
+ }).on('drag', () => {
+ $targetMenu.forEach((target) => { target.classList.add('drop-area-highlight'); });
+ }).on('dragend', () => {
+ $targetMenu.forEach((target) => { target.classList.remove('drop-area-highlight'); });
+ }).on('drop', (el, target) => {
+ if (target !== $sourceMenu) {
+ appendInput(el, target.getAttribute('data-group'), target.getAttribute('data-set'));
+ }
+ });
+
+ $targetMenu.forEach((target) => {
+ renderBar(target, 'menu', null, true);
+ drakeMenu.containers.push(target);
+ });
+
+ const drakeToolbar = dragula([$sourceToolbar], {
+ copy: (el, source) => source === $sourceToolbar,
+ accepts: (el, target) => target !== $sourceToolbar,
+ removeOnSpill: true,
+ }).on('drag', () => {
+ $targetToolbar.forEach((target) => {
+ target.classList.add('drop-area-highlight');
+ });
+ }).on('dragend', () => {
+ $targetToolbar.forEach((target) => {
+ target.classList.remove('drop-area-highlight');
+ });
+ }).on('drop', (el, target) => {
+ if (target !== $sourceToolbar) {
+ appendInput(el, target.getAttribute('data-group'), target.getAttribute('data-set'));
+ }
+ });
+
+ $targetToolbar.forEach((target) => {
+ renderBar(target, 'toolbar', null, true);
+ drakeToolbar.containers.push(target);
+ });
+
+ // Bind actions buttons
+ const actionButtons = container.querySelectorAll('.button-action');
+
+ actionButtons.forEach((elem) => {
+ elem.addEventListener('click', (event) => {
+ const action = event.target.getAttribute('data-action');
+
+ const actionoptions = {};
+
+ [].forEach.call(event.target.attributes, (attrib) => {
+ if (/^data-/.test(attrib.name)) {
+ const key = attrib.name.substr(5);
+
+ actionoptions[key] = attrib.value;
+ }
+ });
+
+ // Don't allow wild function calling
+ switch (action) {
+ case 'clearPane':
+ clearPane(actionoptions);
+ break;
+
+ case 'setPreset':
+ setPreset(actionoptions);
+ break;
+
+ default:
+ throw new Error(`Unsupported action: ${action}`);
+ }
+ });
+ });
+ };
+
+ Joomla.TinyMCEBuilder = TinyMCEBuilder;
+})(Joomla, window);
+
+document.addEventListener('DOMContentLoaded', () => {
+ const options = Joomla.getOptions ? Joomla.getOptions('plg_editors_tinymce_builder', {})
+ : (Joomla.optionsStorage.plg_editors_tinymce_builder || {});
+
+ const builder = document.getElementById('joomla-tinymce-builder');
+
+ Joomla.TinyMCEBuilder(builder, options);
+
+ const selects = builder.querySelectorAll('.access-select');
+
+ // Allow to select the group only once per the set
+ const toggleAvailableOption = () => {
+ selects.forEach((select) => {
+ select.enableAllOptions();
+ });
+
+ // Disable already selected options in the other selects
+ selects.forEach((select) => {
+ const values = select.value;
+
+ selects.forEach((select1) => {
+ if (select === select1) {
+ return;
+ }
+
+ values.forEach((value) => {
+ select1.disableByValue(value);
+ });
+ });
+ });
+ };
+
+ window.addEventListener('load', () => toggleAvailableOption());
+
+ // Allow to select the group only once per the set
+ selects.forEach((select) => {
+ select.addEventListener('change', () => {
+ toggleAvailableOption();
+ });
+ });
+});
diff --git a/build/media_source/plg_editors_tinymce/js/tinymce.es6.js b/build/media_source/plg_editors_tinymce/js/tinymce.es6.js
index 428159fceed17..68f5b36575689 100644
--- a/build/media_source/plg_editors_tinymce/js/tinymce.es6.js
+++ b/build/media_source/plg_editors_tinymce/js/tinymce.es6.js
@@ -63,17 +63,26 @@
const arr = Object.keys(options.joomlaExtButtons.names)
.map(key => options.joomlaExtButtons.names[key]);
+ const icons = {
+ joomla: '',
+ };
+
arr.forEach((xtdButton) => {
const tmp = {};
tmp.text = xtdButton.name;
tmp.icon = xtdButton.icon;
+ tmp.type = 'menuitem';
+
+ if (xtdButton.iconSVG) {
+ icons[tmp.icon] = xtdButton.iconSVG;
+ }
if (xtdButton.href) {
- tmp.onclick = () => {
+ tmp.onAction = () => {
document.getElementById(`${xtdButton.id}Modal`).open();
};
} else {
- tmp.onclick = () => {
+ tmp.onAction = () => {
// eslint-disable-next-line no-new-func
new Function(xtdButton.click)();
};
@@ -84,11 +93,15 @@
if (buttonValues.length) {
options.setup = (editor) => {
- editor.addButton('jxtdbuttons', {
+ Object.keys(icons).forEach((icon) => {
+ editor.ui.registry.addIcon(icon, icons[icon]);
+ });
+
+ editor.ui.registry.addSplitButton('jxtdbuttons', {
type: 'menubutton',
text: Joomla.JText._('PLG_TINY_CORE_BUTTONS'),
- icon: 'none icon-joomla',
- menu: buttonValues,
+ icon: 'joomla',
+ fetch: callback => callback(buttonValues),
});
};
}
diff --git a/build/media_source/plg_editors_tinymce/scss/tinymce-builder.scss b/build/media_source/plg_editors_tinymce/scss/tinymce-builder.scss
new file mode 100644
index 0000000000000..89ad60be81aad
--- /dev/null
+++ b/build/media_source/plg_editors_tinymce/scss/tinymce-builder.scss
@@ -0,0 +1,37 @@
+/**
+ * @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ */
+
+#joomla-tinymce-builder {
+ margin-left: -220px;
+ .drop-area-highlight {
+ background-color: #d0d0d0;
+ }
+ .tox-editor-container {
+ > .target {
+ min-height: 2.5rem;
+ }
+ }
+}
+
+// Drag & Drop Handler
+.tox-mbtn.gu-mirror {
+ align-items: center;
+ background: #dee0e2;
+ border: 0;
+ border-radius: 3px;
+ box-shadow: none;
+ display: flex;
+ flex: 0 0 auto;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: normal;
+ justify-content: center;
+ margin: 2px 0 3px 0;
+ outline: none;
+ overflow: hidden;
+ padding: 0;
+ text-transform: normal;
+
+}
diff --git a/layouts/plugins/editors/tinymce/field/tinymcebuilder.php b/layouts/plugins/editors/tinymce/field/tinymcebuilder.php
index 077257627eb25..2286035cced53 100644
--- a/layouts/plugins/editors/tinymce/field/tinymcebuilder.php
+++ b/layouts/plugins/editors/tinymce/field/tinymcebuilder.php
@@ -56,9 +56,10 @@
*/
HTMLHelper::_('behavior.core');
-HTMLHelper::_('jquery.ui', array('core', 'sortable'));
-HTMLHelper::_('stylesheet', 'media/vendor/tinymce/skins/lightgray/skin.min.css', array('version' => 'auto', 'relative' => false));
+HTMLHelper::_('stylesheet', 'media/vendor/tinymce/skins/ui/oxide/skin.min.css', array('version' => 'auto', 'relative' => false));
HTMLHelper::_('stylesheet', 'plg_editors_tinymce/tinymce-builder.css', array('version' => 'auto', 'relative' => true));
+HTMLHelper::_('stylesheet', 'vendor/dragula/dragula.css', array('version' => 'auto', 'relative' => true));
+HTMLHelper::_('script', 'vendor/dragula/dragula.js', array('version' => 'auto', 'relative' => true));
HTMLHelper::_('script', 'plg_editors_tinymce/tinymce-builder.js', array('version' => 'auto', 'relative' => true));
if ($languageFile)
@@ -80,19 +81,15 @@
-
-
+
+
-
-
-
-
+
+
+
+
-
-
diff --git a/package-lock.json b/package-lock.json
index 64e9c068ad133..0242c5f695443 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8696,9 +8696,9 @@
"dev": true
},
"tinymce": {
- "version": "4.8.3",
- "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-4.8.3.tgz",
- "integrity": "sha512-kNEsKTqUYZRG+GTZ7tcVAktUlDeApz6d3IqnNaZXNX0CP0BsK8NPC02FCJ0EVYxdNnq6fvvknWkItmbreXD9aA=="
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-5.0.1.tgz",
+ "integrity": "sha512-bAKaEEtRd4BsXu6ySYflhO83Cg844LHrplcaWalbdeZjFXwkodtv3G6H1x2r6ThaOdyE4+otJtxPYlfzwyKDdw=="
},
"tmp": {
"version": "0.0.33",
diff --git a/package.json b/package.json
index e466be30a5d79..4a01bb8e4163f 100644
--- a/package.json
+++ b/package.json
@@ -44,7 +44,7 @@
"popper.js": "^1.14.3",
"punycode": "1.4.1",
"skipto": "^2.0.3",
- "tinymce": "4.8.3"
+ "tinymce": "5.0.1"
},
"devDependencies": {
"@babel/core": "^7.4.0",
diff --git a/plugins/editors-xtd/article/article.php b/plugins/editors-xtd/article/article.php
index 504fafcc11103..21dbdf70dbdbe 100644
--- a/plugins/editors-xtd/article/article.php
+++ b/plugins/editors-xtd/article/article.php
@@ -66,6 +66,8 @@ public function onDisplay($name)
$button->link = $link;
$button->text = Text::_('PLG_ARTICLE_BUTTON_ARTICLE');
$button->name = 'file-add';
+ $button->iconSVG = '
';
$button->realName = 'PlgButtonArticle';
$button->options = [
'height' => '300px',
diff --git a/plugins/editors-xtd/contact/contact.php b/plugins/editors-xtd/contact/contact.php
index c76167c13d7a3..5c29e13eddbf2 100644
--- a/plugins/editors-xtd/contact/contact.php
+++ b/plugins/editors-xtd/contact/contact.php
@@ -56,6 +56,9 @@ public function onDisplay($name)
$button->link = $link;
$button->text = Text::_('PLG_EDITORS-XTD_CONTACT_BUTTON_CONTACT');
$button->name = 'address';
+ $button->iconSVG = '
';
$button->options = [
'height' => '300px',
'width' => '800px',
diff --git a/plugins/editors-xtd/fields/fields.php b/plugins/editors-xtd/fields/fields.php
index 89f329a3c0629..df0c0b9824ed0 100644
--- a/plugins/editors-xtd/fields/fields.php
+++ b/plugins/editors-xtd/fields/fields.php
@@ -68,6 +68,12 @@ public function onDisplay($name)
$button->link = $link;
$button->text = Text::_('PLG_EDITORS-XTD_FIELDS_BUTTON_FIELD');
$button->name = 'puzzle';
+ $button->iconSVG = '
';
$button->options = [
'height' => '300px',
'width' => '800px',
diff --git a/plugins/editors-xtd/image/image.php b/plugins/editors-xtd/image/image.php
index 9cb2671636274..7e1b9d556c71c 100644
--- a/plugins/editors-xtd/image/image.php
+++ b/plugins/editors-xtd/image/image.php
@@ -69,6 +69,9 @@ public function onDisplay($name, $asset, $author)
$button->link = $link;
$button->text = Text::_('PLG_IMAGE_BUTTON_IMAGE');
$button->name = 'pictures';
+ $button->iconSVG = '
';
$button->options = [
'height' => '400px',
'width' => '800px',
diff --git a/plugins/editors-xtd/menu/menu.php b/plugins/editors-xtd/menu/menu.php
index 9844440a9a89c..8162b94a3b9a8 100644
--- a/plugins/editors-xtd/menu/menu.php
+++ b/plugins/editors-xtd/menu/menu.php
@@ -57,6 +57,9 @@ public function onDisplay($name)
$button->link = $link;
$button->text = Text::_('PLG_EDITORS-XTD_MENU_BUTTON_MENU');
$button->name = 'share-alt';
+ $button->iconSVG = '
';
$button->options = [
'height' => '300px',
'width' => '800px',
diff --git a/plugins/editors-xtd/module/module.php b/plugins/editors-xtd/module/module.php
index beacaca0dee6d..cc00b2447f9db 100644
--- a/plugins/editors-xtd/module/module.php
+++ b/plugins/editors-xtd/module/module.php
@@ -58,6 +58,8 @@ public function onDisplay($name)
$button->link = $link;
$button->text = Text::_('PLG_MODULE_BUTTON_MODULE');
$button->name = 'file-add';
+ $button->iconSVG = '
';
$button->options = [
'height' => '300px',
'width' => '800px',
diff --git a/plugins/editors-xtd/pagebreak/pagebreak.php b/plugins/editors-xtd/pagebreak/pagebreak.php
index dd03d8709b5d8..72c824f89ac39 100644
--- a/plugins/editors-xtd/pagebreak/pagebreak.php
+++ b/plugins/editors-xtd/pagebreak/pagebreak.php
@@ -65,6 +65,9 @@ public function onDisplay($name)
$button->link = $link;
$button->text = Text::_('PLG_EDITORSXTD_PAGEBREAK_BUTTON_PAGEBREAK');
$button->name = 'copy';
+ $button->iconSVG = '
';
$button->options = [
'height' => '200px',
'width' => '400px',
diff --git a/plugins/editors-xtd/readmore/readmore.php b/plugins/editors-xtd/readmore/readmore.php
index 681e241f9bc62..1be15a05b5044 100644
--- a/plugins/editors-xtd/readmore/readmore.php
+++ b/plugins/editors-xtd/readmore/readmore.php
@@ -66,6 +66,7 @@ public function onDisplay($name)
$button->onclick = 'insertReadmore(\'' . $name . '\');return false;';
$button->text = Text::_('PLG_READMORE_BUTTON_READMORE');
$button->name = 'arrow-down';
+ $button->iconSVG = '
';
$button->link = '#';
return $button;
diff --git a/plugins/editors/tinymce/field/skins.php b/plugins/editors/tinymce/field/skins.php
index fa13462dfbcf4..95f967768ee50 100644
--- a/plugins/editors/tinymce/field/skins.php
+++ b/plugins/editors/tinymce/field/skins.php
@@ -34,7 +34,7 @@ public function getOptions()
{
$options = array();
- $directories = glob(JPATH_ROOT . '/media/vendor/tinymce/skins' . '/*', GLOB_ONLYDIR);
+ $directories = glob(JPATH_ROOT . '/media/vendor/tinymce/skins/ui' . '/*', GLOB_ONLYDIR);
for ($i = 0, $iMax = count($directories); $i < $iMax; ++$i)
{
diff --git a/plugins/editors/tinymce/form/setoptions.xml b/plugins/editors/tinymce/form/setoptions.xml
index 2ac61b6f17937..2f5e52bf6579f 100644
--- a/plugins/editors/tinymce/form/setoptions.xml
+++ b/plugins/editors/tinymce/form/setoptions.xml
@@ -7,6 +7,7 @@
multiple="true"
class="access-select"
labelclass="badge badge-success"
+ layout="joomla.form.field.list-fancy-select"
/>
getAuthorisedGroups(), $user->getAuthorisedGroups());
// Prepare the parameters
@@ -192,10 +192,10 @@ public function onDisplay(
$levelParams->loadObject($extraOptions);
// List the skins
- $skindirs = glob(JPATH_ROOT . '/media/vendor/tinymce/skins' . '/*', GLOB_ONLYDIR);
+ $skindirs = glob(JPATH_ROOT . '/media/vendor/tinymce/skins/ui' . '/*', GLOB_ONLYDIR);
// Set the selected skin
- $skin = 'lightgray';
+ $skin = 'oxide';
$side = $app->isClient('administrator') ? 'skin_admin' : 'skin';
if ((int) $levelParams->get($side, 0) < count($skindirs))
@@ -344,6 +344,16 @@ public function onDisplay(
$html_width = '';
}
+ if (is_numeric($html_width))
+ {
+ $html_width .= 'px';
+ }
+
+ if (is_numeric($html_height))
+ {
+ $html_height .= 'px';
+ }
+
// The param is true for vertical resizing only, false or both
$resizing = (bool) $levelParams->get('resizing', true);
$resize_horizontal = (bool) $levelParams->get('resize_horizontal', true);
@@ -358,7 +368,6 @@ public function onDisplay(
'autolink',
'lists',
'save',
- 'colorpicker',
'importcss',
);
@@ -455,7 +464,7 @@ public function onDisplay(
}
// Check for extra plugins, from the setoptions form
- foreach (array('wordcount' => 1, 'advlist' => 1, 'autosave' => 1, 'contextmenu' => 1) as $pName => $def)
+ foreach (array('wordcount' => 1, 'advlist' => 1, 'autosave' => 1) as $pName => $def)
{
if ($levelParams->get($pName, $def))
{
@@ -506,6 +515,9 @@ public function onDisplay(
$scriptOptions['uploadUri'] = $uploadUrl;
}
+ // Convert pt to px in dropdown
+ $scriptOptions['fontsize_formats'] = '8px 10px 12px 14px 18px 24px 36px';
+
// User custom plugins and buttons
$custom_plugin = trim($levelParams->get('custom_plugin', ''));
$custom_button = trim($levelParams->get('custom_button', ''));
@@ -697,11 +709,12 @@ private function tinyButtons($name, $excluded)
$coreButton = [];
- $coreButton['name'] = $btnName;
- $coreButton['href'] = $href;
- $coreButton['id'] = $modalId;
- $coreButton['icon'] = 'none icon-' . $icon;
- $coreButton['click'] = $onclick;
+ $coreButton['name'] = $btnName;
+ $coreButton['href'] = $href;
+ $coreButton['id'] = $modalId;
+ $coreButton['icon'] = $icon;
+ $coreButton['click'] = $onclick;
+ $coreButton['iconSVG'] = $button->get('iconSVG');
// The array with the toolbar buttons
$btnsNames[] = $coreButton;
@@ -945,8 +958,6 @@ public static function getKnownButtons()
'removeformat' => array('label' => 'Clear formatting'),
// Buttons from the plugins
- 'forecolor' => array('label' => 'Text color', 'plugin' => 'textcolor'),
- 'backcolor' => array('label' => 'Background color', 'plugin' => 'textcolor'),
'anchor' => array('label' => 'Anchor', 'plugin' => 'anchor'),
'hr' => array('label' => 'Horizontal line', 'plugin' => 'hr'),
'ltr' => array('label' => 'Left to right', 'plugin' => 'directionality'),
diff --git a/plugins/editors/tinymce/tinymce.xml b/plugins/editors/tinymce/tinymce.xml
index 8e6ebc5e55fa8..1ffeed6a8ed26 100644
--- a/plugins/editors/tinymce/tinymce.xml
+++ b/plugins/editors/tinymce/tinymce.xml
@@ -1,7 +1,7 @@
plg_editors_tinymce
- 4.8.3
+ 5.0.1
2005-2017
Ephox Corporation
N/A
@@ -24,10 +24,10 @@