diff --git a/administrator/language/en-GB/en-GB.ini b/administrator/language/en-GB/en-GB.ini index 02657af53e1d0..8843e2cd6e946 100644 --- a/administrator/language/en-GB/en-GB.ini +++ b/administrator/language/en-GB/en-GB.ini @@ -194,6 +194,9 @@ JFIELD_BASIS_LOGOUT_DESCRIPTION_LABEL="Logout Description Text" JFIELD_BASIS_LOGOUT_DESCRIPTION_SHOW_DESC="Show or hide logout description." JFIELD_BASIS_LOGOUT_DESCRIPTION_SHOW_LABEL="Logout Description" JFIELD_CATEGORY_DESC="The category that this item is assigned to. You may select an existing category or enter a new category by typing the name in the field and pressing enter." +JFIELD_COLOR_SELECT="Select a colour" +JFIELD_COLOR_TRANSPARENT="No colour, transparent" +JFIELD_COLOR_VALUE="Colour with hexadecimal value of" JFIELD_ENABLED_DESC="The enabled status of this item." JFIELD_FIELDS_CATEGORY_DESC="Select the category that this field is assigned to." JFIELD_KEY_REFERENCE_DESC="Used to store information referring to an external resource." diff --git a/build/webcomponents/js/field-simple-color/field-simple-color.js b/build/webcomponents/js/field-simple-color/field-simple-color.js new file mode 100644 index 0000000000000..cd7e40861f263 --- /dev/null +++ b/build/webcomponents/js/field-simple-color/field-simple-color.js @@ -0,0 +1,397 @@ +/** + * Based on: + * Very simple jQuery Color Picker + * Copyright (C) 2012 Tanguy Krotoff + * Licensed under the MIT license + * + * ADAPTED BY: Dimitris Grammatikogiannis + * + */ +((customElements) => { + const KEYCODE = { + TAB: 9, + ESC: 27, + }; + + const colorNames = { + aliceblue: '#f0f8ff', + antiquewhite: '#faebd7', + aqua: '#00ffff', + aquamarine: '#7fffd4', + azure: '#f0ffff', + beige: '#f5f5dc', + bisque: '#ffe4c4', + black: '#000000', + blanchedalmond: '#ffebcd', + blue: '#0000ff', + blueviolet: '#8a2be2', + brown: '#a52a2a', + burlywood: '#deb887', + cadetblue: '#5f9ea0', + chartreuse: '#7fff00', + chocolate: '#d2691e', + coral: '#ff7f50', + cornflowerblue: '#6495ed', + cornsilk: '#fff8dc', + crimson: '#dc143c', + cyan: '#00ffff', + darkblue: '#00008b', + darkcyan: '#008b8b', + darkgoldenrod: '#b8860b', + darkgray: '#a9a9a9', + darkgreen: '#006400', + darkgrey: '#a9a9a9', + darkkhaki: '#bdb76b', + darkmagenta: '#8b008b', + darkolivegreen: '#556b2f', + darkorange: '#ff8c00', + darkorchid: '#9932cc', + darkred: '#8b0000', + darksalmon: '#e9967a', + darkseagreen: '#8fbc8f', + darkslateblue: '#483d8b', + darkslategray: '#2f4f4f', + darkslategrey: '#2f4f4f', + darkturquoise: '#00ced1', + darkviolet: '#9400d3', + deeppink: '#ff1493', + deepskyblue: '#00bfff', + dimgray: '#696969', + dimgrey: '#696969', + dodgerblue: '#1e90ff', + firebrick: '#b22222', + floralwhite: '#fffaf0', + forestgreen: '#228b22', + fuchsia: '#ff00ff', + gainsboro: '#dcdcdc', + ghostwhite: '#f8f8ff', + gold: '#ffd700', + goldenrod: '#daa520', + gray: '#808080', + green: '#008000', + greenyellow: '#adff2f', + grey: '#808080', + honeydew: '#f0fff0', + hotpink: '#ff69b4', + indianred: '#cd5c5c', + indigo: '#4b0082', + ivory: '#fffff0', + khaki: '#f0e68c', + lavender: '#e6e6fa', + lavenderblush: '#fff0f5', + lawngreen: '#7cfc00', + lemonchiffon: '#fffacd', + lightblue: '#add8e6', + lightcoral: '#f08080', + lightcyan: '#e0ffff', + lightgoldenrodyellow: '#fafad2', + lightgray: '#d3d3d3', + lightgreen: '#90ee90', + lightgrey: '#d3d3d3', + lightpink: '#ffb6c1', + lightsalmon: '#ffa07a', + lightseagreen: '#20b2aa', + lightskyblue: '#87cefa', + lightslategray: '#778899', + lightslategrey: '#778899', + lightsteelblue: '#b0c4de', + lightyellow: '#ffffe0', + lime: '#00ff00', + limegreen: '#32cd32', + linen: '#faf0e6', + magenta: '#ff00ff', + maroon: '#800000', + mediumaquamarine: '#66cdaa', + mediumblue: '#0000cd', + mediumorchid: '#ba55d3', + mediumpurple: '#9370db', + mediumseagreen: '#3cb371', + mediumslateblue: '#7b68ee', + mediumspringgreen: '#00fa9a', + mediumturquoise: '#48d1cc', + mediumvioletred: '#c71585', + midnightblue: '#191970', + mintcream: '#f5fffa', + mistyrose: '#ffe4e1', + moccasin: '#ffe4b5', + navajowhite: '#ffdead', + navy: '#000080', + oldlace: '#fdf5e6', + olive: '#808000', + olivedrab: '#6b8e23', + orange: '#ffa500', + orangered: '#ff4500', + orchid: '#da70d6', + palegoldenrod: '#eee8aa', + palegreen: '#98fb98', + paleturquoise: '#afeeee', + palevioletred: '#db7093', + papayawhip: '#ffefd5', + peachpuff: '#ffdab9', + peru: '#cd853f', + pink: '#ffc0cb', + plum: '#dda0dd', + powderblue: '#b0e0e6', + purple: '#800080', + red: '#ff0000', + rosybrown: '#bc8f8f', + royalblue: '#4169e1', + saddlebrown: '#8b4513', + salmon: '#fa8072', + sandybrown: '#f4a460', + seagreen: '#2e8b57', + seashell: '#fff5ee', + sienna: '#a0522d', + silver: '#c0c0c0', + skyblue: '#87ceeb', + slateblue: '#6a5acd', + slategray: '#708090', + slategrey: '#708090', + snow: '#fffafa', + springgreen: '#00ff7f', + steelblue: '#4682b4', + tan: '#d2b48c', + teal: '#008080', + thistle: '#d8bfd8', + tomato: '#ff6347', + turquoise: '#40e0d0', + violet: '#ee82ee', + wheat: '#f5deb3', + white: '#ffffff', + whitesmoke: '#f5f5f5', + yellow: '#ffff00', + yellowgreen: '#9acd32', + }; + + class JoomlaFieldSimpleColor extends HTMLElement { + constructor() { + super(); + + // Define some variables + this.select = ''; + this.options = []; + this.icon = ''; + this.panel = ''; + this.buttons = []; + this.focusableElements = null; + this.focusableSelectors = ['a[href]', 'area[href]', 'input:not([disabled])', 'select:not([disabled])', 'textarea:not([disabled])', 'button:not([disabled])', 'iframe', 'object', 'embed', '[contenteditable]', '[tabindex]:not([tabindex^="-"])']; + } + + connectedCallback() { + this.select = this.querySelector('select'); + + if (!this.select) { + throw new Error('Simple color field requires a select element') + } + + this.options = [].slice.call(this.select.querySelectorAll('option')); + + this.select.classList.add('hidden'); + + // Build the pop up + this.options.forEach((option) => { + let color = option.value; + let clss = 'swatch'; + + if (color === 'none') { + clss += ' nocolor'; + color = 'transparent'; + } + if (option.selected) { + clss += ' active'; + } + + const el = document.createElement('button'); + el.setAttribute('class', clss); + el.style.backgroundColor = color; + el.setAttribute('type', 'button'); + const a11yColor = color === 'transparent' ? this.textTransp : this.getColorName(color); + el.innerHTML = `${a11yColor}`; + + this.buttons.push(el) + }); + + // Add a close button + const close = document.createElement('button'); + close.setAttribute('class', 'btn-close'); + close.setAttribute('type', 'button'); + close.innerHTML = this.textClose; + + this.buttons.push(close); + + let color = this.select.value; + let clss = ''; + + if (color === 'none') { + clss += ' nocolor'; + color = 'transparent'; + } + + this.icon = document.createElement('button'); + + if (clss) { + this.icon.setAttribute('class', clss); + } + + const uniqueId = `simple-color-${Math.random().toString(36).substr(2, 10)}`; + this.icon.setAttribute('type', 'button'); + this.icon.setAttribute('tabindex', '0'); + this.icon.style.backgroundColor = color + this.icon.innerHTML = '' + this.textSelect + ''; + this.icon.id = uniqueId; + this.select.insertAdjacentElement('beforebegin', this.icon); + this.icon.addEventListener('click', this.show.bind(this)); + + this.panel = document.createElement('div'); + this.panel.classList.add('simplecolors-panel'); + this.panel.setAttribute('aria-labelledby', uniqueId); + + this.buttons.forEach((el) => { + if (el.classList.contains('btn-close')) { + el.addEventListener('click', this.hide.bind(this)); + } else { + el.addEventListener('click', this.colorSelect.bind(this)); + } + + this.panel.insertAdjacentElement('beforeend', el); + }); + + this.appendChild(this.panel); + + this.focusableElements = [].slice.call(this.panel.querySelectorAll(this.focusableSelectors.join())); + + this.keys = this.keys .bind(this); + this.hide = this.hide.bind(this); + this.mousedown = this.mousedown.bind(this); + } + + disconnectedCallback() { + + } + + static get observedAttributes() { + return ['text-select', 'text-color', 'text-close', 'text-transparent']; + } + + get textSelect() { return this.getAttribute('text-select'); } + get textColor() { return this.getAttribute('text-color'); } + get textClose() { return this.getAttribute('text-close'); } + get textTransp() { return this.getAttribute('text-transparent'); } + + // Show the panel + show() { + document.addEventListener('mousedown', this.hide); + this.addEventListener('keydown', this.keys); + this.panel.addEventListener('mousedown', this.mousedown); + this.panel.setAttribute('data-open', ''); + + const focused = this.panel.querySelector('button'); + + if (focused) { + focused.focus(); + } + } + + // Hide panel + hide() { + document.removeEventListener('mousedown', this.hide, false); + this.removeEventListener('keydown', this.keys); + + if (this.panel.hasAttribute('data-open')) { + this.panel.removeAttribute('data-open'); + } + + this.icon.focus(); + } + + colorSelect(e) { + let color = ''; + let bgcolor = ''; + let clss = ''; + + if (e.target.classList.contains('nocolor')) { + color = 'none'; + bgcolor = 'transparent'; + clss = 'nocolor'; + } else { + color = e.target.style.backgroundColor; + bgcolor = color; + } + + // Reset the active class + this.buttons.forEach((el) => { + if (el.classList.contains('active')) { + el.classList.remove('active') + } + }); + + // Add the active class to the selected button + e.target.classList.add('active'); + + this.icon.classList.remove('nocolor'); + this.icon.setAttribute('class', clss); + this.icon.style.backgroundColor = bgcolor; + + // Hide the panel + this.hide(); + + // Change select value + this.options.forEach((el) => { + if (el.selected) { + el.removeAttribute('selected'); + } + + if (el.value === bgcolor) { + el.setAttribute('selected', ''); + } + }); + } + + keys(e) { + if (e.keyCode === KEYCODE.ESC) { + this.hide(); + } + + if (e.keyCode === KEYCODE.TAB) { + // Get the index of the current active element + const focusedIndex = this.focusableElements.indexOf(document.activeElement); + + // If first element is focused and shiftkey is in use, focus last item within modal + if (e.shiftKey && (focusedIndex === 0 || focusedIndex === -1)) { + this.focusableElements[this.focusableElements.length - 1].focus(); + e.preventDefault(); + } + // If last element is focused and shiftkey is not in use, focus first item within modal + if (!e.shiftKey && focusedIndex === this.focusableElements.length - 1) { + this.focusableElements[0].focus(); + e.preventDefault(); + } + } + } + + // Prevents the mousedown event from "eating" the click event. + mousedown(e) { + e.stopPropagation(); + e.preventDefault(); + } + + getColorName(value) { + // Expand any short code + let newValue = value; + if (value.length === 4) { + const tmpValue = value.split(''); + newValue = tmpValue[0] + tmpValue[1] + tmpValue[1] + tmpValue[2] + tmpValue[2] + tmpValue[3] + tmpValue[3]; + } + + for (const color in colorNames) { + if (colorNames.hasOwnProperty(color) && newValue.toLowerCase() === colorNames[color]) { + return color; + } + } + + return this.textColor + ' ' + value.replace('#', '').split('').join(', ') + } + } + + customElements.define('joomla-field-simple-color', JoomlaFieldSimpleColor); +})(customElements); diff --git a/build/webcomponents/scss/field-simple-color/field-simple-color.scss b/build/webcomponents/scss/field-simple-color/field-simple-color.scss new file mode 100644 index 0000000000000..106312a738b14 --- /dev/null +++ b/build/webcomponents/scss/field-simple-color/field-simple-color.scss @@ -0,0 +1,70 @@ +joomla-field-simple-color { + display: block; + + .hidden { + display: none; + } + + .sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0,0,0,0); + border: 0; + } + + button { + width: 20px; + height: 20px; + border: solid 1px #ccc; + vertical-align: middle; + border-radius: 3px; + overflow: hidden; + background: none; + -webkit-appearence: none; + } + + .btn-close { + width: auto; + padding: 0 6px; + margin-top: -4px; + font-size: 1rem; + line-height: 1.5; + text-align: center; + vertical-align: middle; + } + + .nocolor { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3ggRDQENU0dyawAAACZJREFUGNNjPHXqDAMSMDY2ROYyMeAFNJVm/Pv3LzL/7Nnzg8VpAKebCGpIIxHBAAAAAElFTkSuQmCC') !important; + } + .simplecolors-panel .swatch { + margin: 0 4px 4px 0; + } + + .swatch:hover, + .swatch.active { + border-color: rgba(82, 168, 236, .8); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82, 168, 236, .6); + } + + .simplecolors-panel[data-open=""] { + display: block; + } + .simplecolors-panel { + position: absolute; + z-index: 12; + display: none; + float: left; + padding: 6px 2px 2px 6px; + margin: 1px 0 0; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #ddd; + border-radius: 5px; + box-shadow: 0 5px 10px rgba(0, 0, 0, .2); + } +} + diff --git a/language/en-GB/en-GB.ini b/language/en-GB/en-GB.ini index 42b7db9a2d477..dbadd1f29361d 100644 --- a/language/en-GB/en-GB.ini +++ b/language/en-GB/en-GB.ini @@ -150,6 +150,9 @@ JFIELD_ALIAS_LABEL="Alias" JFIELD_ALIAS_PLACEHOLDER="Auto-generate from title" JFIELD_ALT_PAGE_TITLE_LABEL="Alternative Page Title" JFIELD_CATEGORY_DESC="Category" +JFIELD_COLOR_SELECT="Select a colour" +JFIELD_COLOR_TRANSPARENT="No colour, transparent" +JFIELD_COLOR_VALUE="Colour with hexadecimal value of" JFIELD_FIELDS_CATEGORY_DESC="Select the category that this field is assigned to." JFIELD_LANGUAGE_DESC="Assign a language to this article." JFIELD_LANGUAGE_LABEL="Language" diff --git a/layouts/joomla/form/field/color/simple.php b/layouts/joomla/form/field/color/simple.php index fa7e5ed9da106..89f687d3dc760 100644 --- a/layouts/joomla/form/field/color/simple.php +++ b/layouts/joomla/form/field/color/simple.php @@ -10,8 +10,9 @@ defined('JPATH_BASE') or die; use Joomla\CMS\HTML\HTMLHelper; +use Joomla\CMS\Language\Text; -extract($displayData); +extract($displayData, null); /** * Layout variables @@ -45,25 +46,21 @@ * @var array $checked Is this field checked? * @var array $position Is this field checked? * @var array $control Is this field checked? + * @var array $colors The specified colors */ -$class = ' class="custom-select ' . trim('simplecolors chzn-done ' . $class) . '"'; +$class = ' class="custom-select ' . trim($class) . '"'; $disabled = $disabled ? ' disabled' : ''; $readonly = $readonly ? ' readonly' : ''; -// Include jQuery -HTMLHelper::_('jquery.framework'); -HTMLHelper::_('script', 'system/fields/simplecolors.min.js', array('version' => 'auto', 'relative' => true)); -HTMLHelper::_('stylesheet', 'system/simplecolors.css', array('version' => 'auto', 'relative' => true)); -HTMLHelper::_('script', 'system/fields/color-field-init.min.js', array('version' => 'auto', 'relative' => true)); +HTMLHelper::_('webcomponent', 'system/webcomponents/joomla-field-simple-color.min.js', ['version' => 'auto', 'relative' => true]); ?> - + + + diff --git a/media/system/css/simplecolors.css b/media/system/css/simplecolors.css deleted file mode 100644 index 2d69d2042236e..0000000000000 --- a/media/system/css/simplecolors.css +++ /dev/null @@ -1,80 +0,0 @@ -/** - * LOOSELY BASED ON: - * Very simple jQuery Color Picker - * Copyright (C) 2012 Tanguy Krotoff - * Licensed under the MIT license - * - * ADAPTED BY: - * Copyright (C) 2013 Peter van Westen - */ - -.simplecolors-swatch { - cursor: pointer; - position: relative; - width: 20px; - height: 20px; - background: url(../images/jquery.minicolors.png) -80px 0; - border: solid 1px #CCC; - vertical-align: middle; - display: inline-block; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - overflow: hidden; -} - -.simplecolors-swatch span { - position: absolute; - width: 100%; - height: 100%; - background: none; - -webkit-box-shadow: inset 0 9px 0 rgba(255, 255, 255, .1); - -moz-box-shadow: inset 0 9px 0 rgba(255, 255, 255, .1); - box-shadow: inset 0 9px 0 rgba(255, 255, 255, .1); - display: inline-block; -} - -.simplecolors-panel .simplecolors-swatch { - margin: 0 4px 4px 0; -} - -.simplecolors-swatch.active, -.simplecolors-swatch:hover, -.simplecolors-swatch:focus, -.simplecolors-swatch span:focus { - outline: 0; - outline: thin dotted \9; /* IE6-9 */ -} - -.simplecolors-swatch:hover, -.simplecolors-swatch.active { - border-color: rgba(82, 168, 236, 0.8); - -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6); - -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6); - box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6); -} - -.simplecolors-panel { - position: absolute; - top: 100%; - left: 0; - z-index: 12; - display: none; - float: left; - padding: 6px 2px 2px 6px; - margin: 1px 0 0; - list-style: none; - background-color: #ffffff; - border: 1px solid #dddddd; - *border-right-width: 2px; - *border-bottom-width: 2px; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; - -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - -webkit-background-clip: padding-box; - -moz-background-clip: padding-box; - background-clip: padding-box; -} diff --git a/media/system/js/fields/color-field-init.js b/media/system/js/fields/color-field-init.js deleted file mode 100644 index f50be0da98051..0000000000000 --- a/media/system/js/fields/color-field-init.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @copyright Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved. - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ - -!(function(document, $) { - "use strict"; - - function initSimpleColorField (event) { - $(event.target).find('select.simplecolors').simplecolors(); - } - - /** - * Initialize at an initial page load - */ - document.addEventListener("DOMContentLoaded", initSimpleColorField); - - /** - * Initialize when a part of the page was updated - */ - document.addEventListener("joomla:updated", initSimpleColorField); - -})(document, jQuery); diff --git a/media/system/js/fields/color-field-init.min.js b/media/system/js/fields/color-field-init.min.js deleted file mode 100644 index 32af48b72ab36..0000000000000 --- a/media/system/js/fields/color-field-init.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e,t){"use strict";function n(e){t(e.target).find("select.simplecolors").simplecolors()}e.addEventListener("DOMContentLoaded",n),e.addEventListener("joomla:updated",n)}(document,jQuery); \ No newline at end of file diff --git a/media/system/js/fields/simplecolors.js b/media/system/js/fields/simplecolors.js deleted file mode 100644 index 8b0ff37387742..0000000000000 --- a/media/system/js/fields/simplecolors.js +++ /dev/null @@ -1,193 +0,0 @@ -/** - * LOOSELY BASED ON: - * Very simple jQuery Color Picker - * Copyright (C) 2012 Tanguy Krotoff - * Licensed under the MIT license - * - * ADAPTED BY: - * Copyright (C) 2013 Peter van Westen - */ - -(function($) { - var SimpleColorPicker = function(element, options) { - this.select = $(element); - this.options = $.extend({}, $.fn.simplecolors.defaults, options); - - this.select.hide(); - - // Build the list of colors - var list = ''; - $('option', this.select).each(function() { - var option = $(this); - var color = option.val(); - if (option.text() == '-') { - list += '
'; - } else { - var clss = 'simplecolors-swatch'; - if (color == 'none') { - clss += ' nocolor'; - color = 'transparent'; - } - if (option.attr('selected')) { - clss += ' active'; - } - list += ''; - } - }); - - var color = this.select.val(); - var clss = 'simplecolors-swatch'; - if (color == 'none') { - clss += ' nocolor'; - color = 'transparent'; - } - this.icon = $('').insertAfter(this.select); - this.icon.on('click', $.proxy(this.show, this)); - - this.panel = $('').appendTo(document.body); - this.panel.html(list); - this.panel.on('click', $.proxy(this.click, this)); - - // Hide panel when clicking outside - $(document).on('mousedown', $.proxy(this.hide, this)); - this.panel.on('mousedown', $.proxy(this.mousedown, this)); - - }; - - /** - * SimpleColorPicker class - */ - SimpleColorPicker.prototype = { - constructor: SimpleColorPicker, - - show: function() { - var panelpadding = 7; // Empirical value - var pos = this.icon.offset(); - switch (this.select.attr('data-position')) { - case 'top': - this.panel.css({ - left: pos.left - panelpadding, - top: pos.top - this.panel.outerHeight() - 1 - }); - break; - case 'bottom': - this.panel.css({ - left: pos.left - panelpadding, - top: pos.top + this.icon.outerHeight() - }); - break; - case 'left': - this.panel.css({ - left: pos.left - this.panel.outerWidth(), - top: pos.top - ( (this.panel.outerHeight() - this.icon.outerHeight() ) / 2 ) - 1 - }); - break; - case 'right': - default: - this.panel.css({ - left: pos.left + this.icon.outerWidth(), - top: pos.top - ( (this.panel.outerHeight() - this.icon.outerHeight() ) / 2 ) - 1 - }); - break; - } - - this.panel.show(this.options.delay); - }, - - hide: function() { - if (this.panel.css('display') != 'none') { - this.panel.hide(this.options.delay); - } - }, - - click: function(e) { - var target = $(e.target); - if (target.length === 1) { - if (target[0].nodeName.toLowerCase() === 'span') { - // When you click on a color - - var color = ''; - var bgcolor = ''; - var clss = ''; - if (target.parent().hasClass('nocolor')) { - color = 'none'; - bgcolor = 'transparent'; - clss = 'nocolor'; - } else { - color = this.rgb2hex(target.css('background-color')); - bgcolor = color; - } - - // Mark this div as the selected one - target.parent().siblings().removeClass('active'); - target.parent().addClass('active'); - - this.icon.removeClass('nocolor').addClass(clss); - this.icon.find('span').css('background-color', bgcolor); - - // Hide the panel - this.hide(); - - // Change select value - this.select.val(color).change(); - } - } - }, - - /** - * Prevents the mousedown event from "eating" the click event. - */ - mousedown: function(e) { - e.stopPropagation(); - e.preventDefault(); - }, - - /** - * Converts a RGB color to its hexadecimal value. - * - * See http://stackoverflow.com/questions/1740700/get-hex-value-rather-than-rgb-value-using-$ - */ - rgb2hex: function(rgb) { - function hex(x) { - return ("0" + parseInt(x, 10).toString(16)).slice(-2); - } - - var matches = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); - if (matches === null) { - // Fix for Internet Explorer < 9 - // Variable rgb is already a hexadecimal value - return rgb; - } else { - return '#' + hex(matches[1]) + hex(matches[2]) + hex(matches[3]); - } - } - }; - - /** - * Plugin definition. - */ - $.fn.simplecolors = function(option) { - // For HTML element passed to the plugin - return this.each(function() { - var $this = $(this), - data = $this.data('simplecolors'), - options = typeof option === 'object' && option; - if (!data) { - $this.data('simplecolors', (data = new SimpleColorPicker(this, options))); - } - if (typeof option === 'string') { - data[option](); - } - }); - }; - - $.fn.simplecolors.Constructor = SimpleColorPicker; - - /** - * Default options. - */ - $.fn.simplecolors.defaults = { - // Animation delay - delay: 0 - }; -})(jQuery); diff --git a/media/system/js/fields/simplecolors.min.js b/media/system/js/fields/simplecolors.min.js deleted file mode 100644 index 8126476cfd0d8..0000000000000 --- a/media/system/js/fields/simplecolors.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(t){var s=function(s,e){this.select=t(s),this.options=t.extend({},t.fn.simplecolors.defaults,e),this.select.hide();var o="";t("option",this.select).each(function(){var s=t(this),e=s.val();if("-"==s.text())o+="
";else{var n="simplecolors-swatch";"none"==e&&(n+=" nocolor",e="transparent"),s.attr("selected")&&(n+=" active"),o+=''}});var n=this.select.val(),i="simplecolors-swatch";"none"==n&&(i+=" nocolor",n="transparent"),this.icon=t('').insertAfter(this.select),this.icon.on("click",t.proxy(this.show,this)),this.panel=t('').appendTo(document.body),this.panel.html(o),this.panel.on("click",t.proxy(this.click,this)),t(document).on("mousedown",t.proxy(this.hide,this)),this.panel.on("mousedown",t.proxy(this.mousedown,this))};s.prototype={constructor:s,show:function(){var t=this.icon.offset();switch(this.select.attr("data-position")){case"top":this.panel.css({left:t.left-7,top:t.top-this.panel.outerHeight()-1});break;case"bottom":this.panel.css({left:t.left-7,top:t.top+this.icon.outerHeight()});break;case"left":this.panel.css({left:t.left-this.panel.outerWidth(),top:t.top-(this.panel.outerHeight()-this.icon.outerHeight())/2-1});break;case"right":default:this.panel.css({left:t.left+this.icon.outerWidth(),top:t.top-(this.panel.outerHeight()-this.icon.outerHeight())/2-1})}this.panel.show(this.options.delay)},hide:function(){"none"!=this.panel.css("display")&&this.panel.hide(this.options.delay)},click:function(s){var e=t(s.target);if(1===e.length&&"span"===e[0].nodeName.toLowerCase()){var o="",n="",i="";e.parent().hasClass("nocolor")?(o="none",n="transparent",i="nocolor"):n=o=this.rgb2hex(e.css("background-color")),e.parent().siblings().removeClass("active"),e.parent().addClass("active"),this.icon.removeClass("nocolor").addClass(i),this.icon.find("span").css("background-color",n),this.hide(),this.select.val(o).change()}},mousedown:function(t){t.stopPropagation(),t.preventDefault()},rgb2hex:function(t){function s(t){return("0"+parseInt(t,10).toString(16)).slice(-2)}var e=t.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);return null===e?t:"#"+s(e[1])+s(e[2])+s(e[3])}},t.fn.simplecolors=function(e){return this.each(function(){var o=t(this),n=o.data("simplecolors"),i="object"==typeof e&&e;n||o.data("simplecolors",n=new s(this,i)),"string"==typeof e&&n[e]()})},t.fn.simplecolors.Constructor=s,t.fn.simplecolors.defaults={delay:0}}(jQuery); \ No newline at end of file diff --git a/media/system/webcomponents/css/joomla-field-simple-color.css b/media/system/webcomponents/css/joomla-field-simple-color.css new file mode 100644 index 0000000000000..3ed029baaa58e --- /dev/null +++ b/media/system/webcomponents/css/joomla-field-simple-color.css @@ -0,0 +1,54 @@ +joomla-field-simple-color { + display: block; } + joomla-field-simple-color .hidden { + display: none; } + joomla-field-simple-color .sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; } + joomla-field-simple-color button { + width: 20px; + height: 20px; + border: solid 1px #ccc; + vertical-align: middle; + border-radius: 3px; + overflow: hidden; + background: none; + -webkit-appearence: none; } + joomla-field-simple-color .btn-close { + width: auto; + padding: 0 6px; + margin-top: -4px; + font-size: 1rem; + line-height: 1.5; + text-align: center; + vertical-align: middle; } + joomla-field-simple-color .nocolor { + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3ggRDQENU0dyawAAACZJREFUGNNjPHXqDAMSMDY2ROYyMeAFNJVm/Pv3LzL/7Nnzg8VpAKebCGpIIxHBAAAAAElFTkSuQmCC") !important; } + joomla-field-simple-color .simplecolors-panel .swatch { + margin: 0 4px 4px 0; } + joomla-field-simple-color .swatch:hover, + joomla-field-simple-color .swatch.active { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); } + joomla-field-simple-color .simplecolors-panel[data-open=""] { + display: block; } + joomla-field-simple-color .simplecolors-panel { + position: absolute; + z-index: 12; + display: none; + float: left; + padding: 6px 2px 2px 6px; + margin: 1px 0 0; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #ddd; + border-radius: 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); } diff --git a/media/system/webcomponents/css/joomla-field-simple-color.min.css b/media/system/webcomponents/css/joomla-field-simple-color.min.css new file mode 100644 index 0000000000000..8acbc0fd23b9a --- /dev/null +++ b/media/system/webcomponents/css/joomla-field-simple-color.min.css @@ -0,0 +1 @@ +joomla-field-simple-color{display:block}joomla-field-simple-color .hidden{display:none}joomla-field-simple-color .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}joomla-field-simple-color button{width:20px;height:20px;border:solid 1px #ccc;vertical-align:middle;border-radius:3px;overflow:hidden;background:0;-webkit-appearence:none}joomla-field-simple-color .btn-close{width:auto;padding:0 6px;margin-top:-4px;font-size:1rem;line-height:1.5;text-align:center;vertical-align:middle}joomla-field-simple-color .nocolor{background:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3ggRDQENU0dyawAAACZJREFUGNNjPHXqDAMSMDY2ROYyMeAFNJVm/Pv3LzL/7Nnzg8VpAKebCGpIIxHBAAAAAElFTkSuQmCC") !important}joomla-field-simple-color .simplecolors-panel .swatch{margin:0 4px 4px 0}joomla-field-simple-color .swatch:hover,joomla-field-simple-color .swatch.active{border-color:rgba(82,168,236,0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}joomla-field-simple-color .simplecolors-panel[data-open=""]{display:block}joomla-field-simple-color .simplecolors-panel{position:absolute;z-index:12;display:none;float:left;padding:6px 2px 2px 6px;margin:1px 0 0;background-color:#fff;background-clip:padding-box;border:1px solid #ddd;border-radius:5px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2)} \ No newline at end of file diff --git a/media/system/webcomponents/js/joomla-field-simple-color-es5.js b/media/system/webcomponents/js/joomla-field-simple-color-es5.js new file mode 100644 index 0000000000000..7becec7c2963e --- /dev/null +++ b/media/system/webcomponents/js/joomla-field-simple-color-es5.js @@ -0,0 +1,449 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o'; + + _this2.buttons.push(el); + }); + + // Add a close button + var close = document.createElement('button'); + close.setAttribute('class', 'btn-close'); + close.setAttribute('type', 'button'); + close.innerHTML = this.textClose; + + this.buttons.push(close); + + var color = this.select.value; + var clss = ''; + + if (color === 'none') { + clss += ' nocolor'; + color = 'transparent'; + } + + this.icon = document.createElement('button'); + + if (clss) { + this.icon.setAttribute('class', clss); + } + + var uniqueId = 'simple-color-' + Math.random().toString(36).substr(2, 10); + this.icon.setAttribute('type', 'button'); + this.icon.setAttribute('tabindex', '0'); + this.icon.style.backgroundColor = color; + this.icon.innerHTML = '' + this.textSelect + ''; + this.icon.id = uniqueId; + this.select.insertAdjacentElement('beforebegin', this.icon); + this.icon.addEventListener('click', this.show.bind(this)); + + this.panel = document.createElement('div'); + this.panel.classList.add('simplecolors-panel'); + this.panel.setAttribute('aria-labelledby', uniqueId); + + this.buttons.forEach(function (el) { + if (el.classList.contains('btn-close')) { + el.addEventListener('click', _this2.hide.bind(_this2)); + } else { + el.addEventListener('click', _this2.colorSelect.bind(_this2)); + } + + _this2.panel.insertAdjacentElement('beforeend', el); + }); + + this.appendChild(this.panel); + + this.focusableElements = [].slice.call(this.panel.querySelectorAll(this.focusableSelectors.join())); + + this.keys = this.keys.bind(this); + this.hide = this.hide.bind(this); + this.mousedown = this.mousedown.bind(this); + } + }, { + key: 'disconnectedCallback', + value: function disconnectedCallback() {} + }, { + key: 'show', + + + // Show the panel + value: function show() { + document.addEventListener('mousedown', this.hide); + this.addEventListener('keydown', this.keys); + this.panel.addEventListener('mousedown', this.mousedown); + this.panel.setAttribute('data-open', ''); + + var focused = this.panel.querySelector('button'); + + if (focused) { + focused.focus(); + } + } + + // Hide panel + + }, { + key: 'hide', + value: function hide() { + document.removeEventListener('mousedown', this.hide, false); + this.removeEventListener('keydown', this.keys); + + if (this.panel.hasAttribute('data-open')) { + this.panel.removeAttribute('data-open'); + } + + this.icon.focus(); + } + }, { + key: 'colorSelect', + value: function colorSelect(e) { + var color = ''; + var bgcolor = ''; + var clss = ''; + + if (e.target.classList.contains('nocolor')) { + color = 'none'; + bgcolor = 'transparent'; + clss = 'nocolor'; + } else { + color = e.target.style.backgroundColor; + bgcolor = color; + } + + // Reset the active class + this.buttons.forEach(function (el) { + if (el.classList.contains('active')) { + el.classList.remove('active'); + } + }); + + // Add the active class to the selected button + e.target.classList.add('active'); + + this.icon.classList.remove('nocolor'); + this.icon.setAttribute('class', clss); + this.icon.style.backgroundColor = bgcolor; + + // Hide the panel + this.hide(); + + // Change select value + this.options.forEach(function (el) { + if (el.selected) { + el.removeAttribute('selected'); + } + + if (el.value === bgcolor) { + el.setAttribute('selected', ''); + } + }); + } + }, { + key: 'keys', + value: function keys(e) { + if (e.keyCode === KEYCODE.ESC) { + this.hide(); + } + + if (e.keyCode === KEYCODE.TAB) { + // Get the index of the current active element + var focusedIndex = this.focusableElements.indexOf(document.activeElement); + + // If first element is focused and shiftkey is in use, focus last item within modal + if (e.shiftKey && (focusedIndex === 0 || focusedIndex === -1)) { + this.focusableElements[this.focusableElements.length - 1].focus(); + e.preventDefault(); + } + // If last element is focused and shiftkey is not in use, focus first item within modal + if (!e.shiftKey && focusedIndex === this.focusableElements.length - 1) { + this.focusableElements[0].focus(); + e.preventDefault(); + } + } + } + + // Prevents the mousedown event from "eating" the click event. + + }, { + key: 'mousedown', + value: function mousedown(e) { + e.stopPropagation(); + e.preventDefault(); + } + }, { + key: 'getColorName', + value: function getColorName(value) { + // Expand any short code + var newValue = value; + if (value.length === 4) { + var tmpValue = value.split(''); + newValue = tmpValue[0] + tmpValue[1] + tmpValue[1] + tmpValue[2] + tmpValue[2] + tmpValue[3] + tmpValue[3]; + } + + for (var color in colorNames) { + if (colorNames.hasOwnProperty(color) && newValue.toLowerCase() === colorNames[color]) { + return color; + } + } + + return this.textColor + ' ' + value.replace('#', '').split('').join(', '); + } + }, { + key: 'textSelect', + get: function get() { + return this.getAttribute('text-select'); + } + }, { + key: 'textColor', + get: function get() { + return this.getAttribute('text-color'); + } + }, { + key: 'textClose', + get: function get() { + return this.getAttribute('text-close'); + } + }, { + key: 'textTransp', + get: function get() { + return this.getAttribute('text-transparent'); + } + }], [{ + key: 'observedAttributes', + get: function get() { + return ['text-select', 'text-color', 'text-close', 'text-transparent']; + } + }]); + + return JoomlaFieldSimpleColor; + }(HTMLElement); + + customElements.define('joomla-field-simple-color', JoomlaFieldSimpleColor); +})(customElements); + +},{}]},{},[1]); diff --git a/media/system/webcomponents/js/joomla-field-simple-color-es5.min.js b/media/system/webcomponents/js/joomla-field-simple-color-es5.min.js new file mode 100644 index 0000000000000..9ab1da8c5eefd --- /dev/null +++ b/media/system/webcomponents/js/joomla-field-simple-color-es5.min.js @@ -0,0 +1,4 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o'+f+'',a.buttons.push(e)});var b=document.createElement('button');b.setAttribute('class','btn-close'),b.setAttribute('type','button'),b.innerHTML=this.textClose,this.buttons.push(b);var c=this.select.value,d='';'none'===c&&(d+=' nocolor',c='transparent'),this.icon=document.createElement('button'),d&&this.icon.setAttribute('class',d);var e='simple-color-'+Math.random().toString(36).substr(2,10);this.icon.setAttribute('type','button'),this.icon.setAttribute('tabindex','0'),this.icon.style.backgroundColor=c,this.icon.innerHTML=''+this.textSelect+'',this.icon.id=e,this.select.insertAdjacentElement('beforebegin',this.icon),this.icon.addEventListener('click',this.show.bind(this)),this.panel=document.createElement('div'),this.panel.classList.add('simplecolors-panel'),this.panel.setAttribute('aria-labelledby',e),this.buttons.forEach(function(b){b.classList.contains('btn-close')?b.addEventListener('click',a.hide.bind(a)):b.addEventListener('click',a.colorSelect.bind(a)),a.panel.insertAdjacentElement('beforeend',b)}),this.appendChild(this.panel),this.focusableElements=[].slice.call(this.panel.querySelectorAll(this.focusableSelectors.join())),this.keys=this.keys.bind(this),this.hide=this.hide.bind(this),this.mousedown=this.mousedown.bind(this)}},{key:'disconnectedCallback',value:function disconnectedCallback(){}},{key:'show',value:function show(){document.addEventListener('mousedown',this.hide),this.addEventListener('keydown',this.keys),this.panel.addEventListener('mousedown',this.mousedown),this.panel.setAttribute('data-open','');var a=this.panel.querySelector('button');a&&a.focus()}},{key:'hide',value:function hide(){document.removeEventListener('mousedown',this.hide,!1),this.removeEventListener('keydown',this.keys),this.panel.hasAttribute('data-open')&&this.panel.removeAttribute('data-open'),this.icon.focus()}},{key:'colorSelect',value:function colorSelect(a){var b='',c='',d='';a.target.classList.contains('nocolor')?(b='none',c='transparent',d='nocolor'):(b=a.target.style.backgroundColor,c=b),this.buttons.forEach(function(a){a.classList.contains('active')&&a.classList.remove('active')}),a.target.classList.add('active'),this.icon.classList.remove('nocolor'),this.icon.setAttribute('class',d),this.icon.style.backgroundColor=c,this.hide(),this.options.forEach(function(a){a.selected&&a.removeAttribute('selected'),a.value===c&&a.setAttribute('selected','')})}},{key:'keys',value:function keys(a){if(a.keyCode===b.ESC&&this.hide(),a.keyCode===b.TAB){var c=this.focusableElements.indexOf(document.activeElement);a.shiftKey&&(0===c||-1===c)&&(this.focusableElements[this.focusableElements.length-1].focus(),a.preventDefault()),a.shiftKey||c!==this.focusableElements.length-1||(this.focusableElements[0].focus(),a.preventDefault())}}},{key:'mousedown',value:function mousedown(a){a.stopPropagation(),a.preventDefault()}},{key:'getColorName',value:function getColorName(a){var b=a;if(4===a.length){var d=a.split('');b=d[0]+d[1]+d[1]+d[2]+d[2]+d[3]+d[3]}for(var e in c)if(c.hasOwnProperty(e)&&b.toLowerCase()===c[e])return e;return this.textColor+' '+a.replace('#','').split('').join(', ')}},{key:'textSelect',get:function get(){return this.getAttribute('text-select')}},{key:'textColor',get:function get(){return this.getAttribute('text-color')}},{key:'textClose',get:function get(){return this.getAttribute('text-close')}},{key:'textTransp',get:function get(){return this.getAttribute('text-transparent')}}],[{key:'observedAttributes',get:function get(){return['text-select','text-color','text-close','text-transparent']}}]),d}(HTMLElement);a.define('joomla-field-simple-color',d)})(customElements); + +},{}]},{},[1]); diff --git a/media/system/webcomponents/js/joomla-field-simple-color.js b/media/system/webcomponents/js/joomla-field-simple-color.js new file mode 100644 index 0000000000000..cd7e40861f263 --- /dev/null +++ b/media/system/webcomponents/js/joomla-field-simple-color.js @@ -0,0 +1,397 @@ +/** + * Based on: + * Very simple jQuery Color Picker + * Copyright (C) 2012 Tanguy Krotoff + * Licensed under the MIT license + * + * ADAPTED BY: Dimitris Grammatikogiannis + * + */ +((customElements) => { + const KEYCODE = { + TAB: 9, + ESC: 27, + }; + + const colorNames = { + aliceblue: '#f0f8ff', + antiquewhite: '#faebd7', + aqua: '#00ffff', + aquamarine: '#7fffd4', + azure: '#f0ffff', + beige: '#f5f5dc', + bisque: '#ffe4c4', + black: '#000000', + blanchedalmond: '#ffebcd', + blue: '#0000ff', + blueviolet: '#8a2be2', + brown: '#a52a2a', + burlywood: '#deb887', + cadetblue: '#5f9ea0', + chartreuse: '#7fff00', + chocolate: '#d2691e', + coral: '#ff7f50', + cornflowerblue: '#6495ed', + cornsilk: '#fff8dc', + crimson: '#dc143c', + cyan: '#00ffff', + darkblue: '#00008b', + darkcyan: '#008b8b', + darkgoldenrod: '#b8860b', + darkgray: '#a9a9a9', + darkgreen: '#006400', + darkgrey: '#a9a9a9', + darkkhaki: '#bdb76b', + darkmagenta: '#8b008b', + darkolivegreen: '#556b2f', + darkorange: '#ff8c00', + darkorchid: '#9932cc', + darkred: '#8b0000', + darksalmon: '#e9967a', + darkseagreen: '#8fbc8f', + darkslateblue: '#483d8b', + darkslategray: '#2f4f4f', + darkslategrey: '#2f4f4f', + darkturquoise: '#00ced1', + darkviolet: '#9400d3', + deeppink: '#ff1493', + deepskyblue: '#00bfff', + dimgray: '#696969', + dimgrey: '#696969', + dodgerblue: '#1e90ff', + firebrick: '#b22222', + floralwhite: '#fffaf0', + forestgreen: '#228b22', + fuchsia: '#ff00ff', + gainsboro: '#dcdcdc', + ghostwhite: '#f8f8ff', + gold: '#ffd700', + goldenrod: '#daa520', + gray: '#808080', + green: '#008000', + greenyellow: '#adff2f', + grey: '#808080', + honeydew: '#f0fff0', + hotpink: '#ff69b4', + indianred: '#cd5c5c', + indigo: '#4b0082', + ivory: '#fffff0', + khaki: '#f0e68c', + lavender: '#e6e6fa', + lavenderblush: '#fff0f5', + lawngreen: '#7cfc00', + lemonchiffon: '#fffacd', + lightblue: '#add8e6', + lightcoral: '#f08080', + lightcyan: '#e0ffff', + lightgoldenrodyellow: '#fafad2', + lightgray: '#d3d3d3', + lightgreen: '#90ee90', + lightgrey: '#d3d3d3', + lightpink: '#ffb6c1', + lightsalmon: '#ffa07a', + lightseagreen: '#20b2aa', + lightskyblue: '#87cefa', + lightslategray: '#778899', + lightslategrey: '#778899', + lightsteelblue: '#b0c4de', + lightyellow: '#ffffe0', + lime: '#00ff00', + limegreen: '#32cd32', + linen: '#faf0e6', + magenta: '#ff00ff', + maroon: '#800000', + mediumaquamarine: '#66cdaa', + mediumblue: '#0000cd', + mediumorchid: '#ba55d3', + mediumpurple: '#9370db', + mediumseagreen: '#3cb371', + mediumslateblue: '#7b68ee', + mediumspringgreen: '#00fa9a', + mediumturquoise: '#48d1cc', + mediumvioletred: '#c71585', + midnightblue: '#191970', + mintcream: '#f5fffa', + mistyrose: '#ffe4e1', + moccasin: '#ffe4b5', + navajowhite: '#ffdead', + navy: '#000080', + oldlace: '#fdf5e6', + olive: '#808000', + olivedrab: '#6b8e23', + orange: '#ffa500', + orangered: '#ff4500', + orchid: '#da70d6', + palegoldenrod: '#eee8aa', + palegreen: '#98fb98', + paleturquoise: '#afeeee', + palevioletred: '#db7093', + papayawhip: '#ffefd5', + peachpuff: '#ffdab9', + peru: '#cd853f', + pink: '#ffc0cb', + plum: '#dda0dd', + powderblue: '#b0e0e6', + purple: '#800080', + red: '#ff0000', + rosybrown: '#bc8f8f', + royalblue: '#4169e1', + saddlebrown: '#8b4513', + salmon: '#fa8072', + sandybrown: '#f4a460', + seagreen: '#2e8b57', + seashell: '#fff5ee', + sienna: '#a0522d', + silver: '#c0c0c0', + skyblue: '#87ceeb', + slateblue: '#6a5acd', + slategray: '#708090', + slategrey: '#708090', + snow: '#fffafa', + springgreen: '#00ff7f', + steelblue: '#4682b4', + tan: '#d2b48c', + teal: '#008080', + thistle: '#d8bfd8', + tomato: '#ff6347', + turquoise: '#40e0d0', + violet: '#ee82ee', + wheat: '#f5deb3', + white: '#ffffff', + whitesmoke: '#f5f5f5', + yellow: '#ffff00', + yellowgreen: '#9acd32', + }; + + class JoomlaFieldSimpleColor extends HTMLElement { + constructor() { + super(); + + // Define some variables + this.select = ''; + this.options = []; + this.icon = ''; + this.panel = ''; + this.buttons = []; + this.focusableElements = null; + this.focusableSelectors = ['a[href]', 'area[href]', 'input:not([disabled])', 'select:not([disabled])', 'textarea:not([disabled])', 'button:not([disabled])', 'iframe', 'object', 'embed', '[contenteditable]', '[tabindex]:not([tabindex^="-"])']; + } + + connectedCallback() { + this.select = this.querySelector('select'); + + if (!this.select) { + throw new Error('Simple color field requires a select element') + } + + this.options = [].slice.call(this.select.querySelectorAll('option')); + + this.select.classList.add('hidden'); + + // Build the pop up + this.options.forEach((option) => { + let color = option.value; + let clss = 'swatch'; + + if (color === 'none') { + clss += ' nocolor'; + color = 'transparent'; + } + if (option.selected) { + clss += ' active'; + } + + const el = document.createElement('button'); + el.setAttribute('class', clss); + el.style.backgroundColor = color; + el.setAttribute('type', 'button'); + const a11yColor = color === 'transparent' ? this.textTransp : this.getColorName(color); + el.innerHTML = `${a11yColor}`; + + this.buttons.push(el) + }); + + // Add a close button + const close = document.createElement('button'); + close.setAttribute('class', 'btn-close'); + close.setAttribute('type', 'button'); + close.innerHTML = this.textClose; + + this.buttons.push(close); + + let color = this.select.value; + let clss = ''; + + if (color === 'none') { + clss += ' nocolor'; + color = 'transparent'; + } + + this.icon = document.createElement('button'); + + if (clss) { + this.icon.setAttribute('class', clss); + } + + const uniqueId = `simple-color-${Math.random().toString(36).substr(2, 10)}`; + this.icon.setAttribute('type', 'button'); + this.icon.setAttribute('tabindex', '0'); + this.icon.style.backgroundColor = color + this.icon.innerHTML = '' + this.textSelect + ''; + this.icon.id = uniqueId; + this.select.insertAdjacentElement('beforebegin', this.icon); + this.icon.addEventListener('click', this.show.bind(this)); + + this.panel = document.createElement('div'); + this.panel.classList.add('simplecolors-panel'); + this.panel.setAttribute('aria-labelledby', uniqueId); + + this.buttons.forEach((el) => { + if (el.classList.contains('btn-close')) { + el.addEventListener('click', this.hide.bind(this)); + } else { + el.addEventListener('click', this.colorSelect.bind(this)); + } + + this.panel.insertAdjacentElement('beforeend', el); + }); + + this.appendChild(this.panel); + + this.focusableElements = [].slice.call(this.panel.querySelectorAll(this.focusableSelectors.join())); + + this.keys = this.keys .bind(this); + this.hide = this.hide.bind(this); + this.mousedown = this.mousedown.bind(this); + } + + disconnectedCallback() { + + } + + static get observedAttributes() { + return ['text-select', 'text-color', 'text-close', 'text-transparent']; + } + + get textSelect() { return this.getAttribute('text-select'); } + get textColor() { return this.getAttribute('text-color'); } + get textClose() { return this.getAttribute('text-close'); } + get textTransp() { return this.getAttribute('text-transparent'); } + + // Show the panel + show() { + document.addEventListener('mousedown', this.hide); + this.addEventListener('keydown', this.keys); + this.panel.addEventListener('mousedown', this.mousedown); + this.panel.setAttribute('data-open', ''); + + const focused = this.panel.querySelector('button'); + + if (focused) { + focused.focus(); + } + } + + // Hide panel + hide() { + document.removeEventListener('mousedown', this.hide, false); + this.removeEventListener('keydown', this.keys); + + if (this.panel.hasAttribute('data-open')) { + this.panel.removeAttribute('data-open'); + } + + this.icon.focus(); + } + + colorSelect(e) { + let color = ''; + let bgcolor = ''; + let clss = ''; + + if (e.target.classList.contains('nocolor')) { + color = 'none'; + bgcolor = 'transparent'; + clss = 'nocolor'; + } else { + color = e.target.style.backgroundColor; + bgcolor = color; + } + + // Reset the active class + this.buttons.forEach((el) => { + if (el.classList.contains('active')) { + el.classList.remove('active') + } + }); + + // Add the active class to the selected button + e.target.classList.add('active'); + + this.icon.classList.remove('nocolor'); + this.icon.setAttribute('class', clss); + this.icon.style.backgroundColor = bgcolor; + + // Hide the panel + this.hide(); + + // Change select value + this.options.forEach((el) => { + if (el.selected) { + el.removeAttribute('selected'); + } + + if (el.value === bgcolor) { + el.setAttribute('selected', ''); + } + }); + } + + keys(e) { + if (e.keyCode === KEYCODE.ESC) { + this.hide(); + } + + if (e.keyCode === KEYCODE.TAB) { + // Get the index of the current active element + const focusedIndex = this.focusableElements.indexOf(document.activeElement); + + // If first element is focused and shiftkey is in use, focus last item within modal + if (e.shiftKey && (focusedIndex === 0 || focusedIndex === -1)) { + this.focusableElements[this.focusableElements.length - 1].focus(); + e.preventDefault(); + } + // If last element is focused and shiftkey is not in use, focus first item within modal + if (!e.shiftKey && focusedIndex === this.focusableElements.length - 1) { + this.focusableElements[0].focus(); + e.preventDefault(); + } + } + } + + // Prevents the mousedown event from "eating" the click event. + mousedown(e) { + e.stopPropagation(); + e.preventDefault(); + } + + getColorName(value) { + // Expand any short code + let newValue = value; + if (value.length === 4) { + const tmpValue = value.split(''); + newValue = tmpValue[0] + tmpValue[1] + tmpValue[1] + tmpValue[2] + tmpValue[2] + tmpValue[3] + tmpValue[3]; + } + + for (const color in colorNames) { + if (colorNames.hasOwnProperty(color) && newValue.toLowerCase() === colorNames[color]) { + return color; + } + } + + return this.textColor + ' ' + value.replace('#', '').split('').join(', ') + } + } + + customElements.define('joomla-field-simple-color', JoomlaFieldSimpleColor); +})(customElements); diff --git a/media/system/webcomponents/js/joomla-field-simple-color.min.js b/media/system/webcomponents/js/joomla-field-simple-color.min.js new file mode 100644 index 0000000000000..7939b43edbb3c --- /dev/null +++ b/media/system/webcomponents/js/joomla-field-simple-color.min.js @@ -0,0 +1 @@ +(e=>{const t={TAB:9,ESC:27},s={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"};e.define("joomla-field-simple-color",class extends HTMLElement{constructor(){super(),this.select="",this.options=[],this.icon="",this.panel="",this.buttons=[],this.focusableElements=null,this.focusableSelectors=["a[href]","area[href]","input:not([disabled])","select:not([disabled])","textarea:not([disabled])","button:not([disabled])","iframe","object","embed","[contenteditable]",'[tabindex]:not([tabindex^="-"])']}connectedCallback(){if(this.select=this.querySelector("select"),!this.select)throw new Error("Simple color field requires a select element");this.options=[].slice.call(this.select.querySelectorAll("option")),this.select.classList.add("hidden"),this.options.forEach(e=>{let t=e.value,s="swatch";"none"===t&&(s+=" nocolor",t="transparent"),e.selected&&(s+=" active");const i=document.createElement("button");i.setAttribute("class",s),i.style.backgroundColor=t,i.setAttribute("type","button");const a="transparent"===t?this.textTransp:this.getColorName(t);i.innerHTML=`${a}`,this.buttons.push(i)});const e=document.createElement("button");e.setAttribute("class","btn-close"),e.setAttribute("type","button"),e.innerHTML=this.textClose,this.buttons.push(e);let t=this.select.value,s="";"none"===t&&(s+=" nocolor",t="transparent"),this.icon=document.createElement("button"),s&&this.icon.setAttribute("class",s);const i=`simple-color-${Math.random().toString(36).substr(2,10)}`;this.icon.setAttribute("type","button"),this.icon.setAttribute("tabindex","0"),this.icon.style.backgroundColor=t,this.icon.innerHTML=''+this.textSelect+"",this.icon.id=i,this.select.insertAdjacentElement("beforebegin",this.icon),this.icon.addEventListener("click",this.show.bind(this)),this.panel=document.createElement("div"),this.panel.classList.add("simplecolors-panel"),this.panel.setAttribute("aria-labelledby",i),this.buttons.forEach(e=>{e.classList.contains("btn-close")?e.addEventListener("click",this.hide.bind(this)):e.addEventListener("click",this.colorSelect.bind(this)),this.panel.insertAdjacentElement("beforeend",e)}),this.appendChild(this.panel),this.focusableElements=[].slice.call(this.panel.querySelectorAll(this.focusableSelectors.join())),this.keys=this.keys.bind(this),this.hide=this.hide.bind(this),this.mousedown=this.mousedown.bind(this)}disconnectedCallback(){}static get observedAttributes(){return["text-select","text-color","text-close","text-transparent"]}get textSelect(){return this.getAttribute("text-select")}get textColor(){return this.getAttribute("text-color")}get textClose(){return this.getAttribute("text-close")}get textTransp(){return this.getAttribute("text-transparent")}show(){document.addEventListener("mousedown",this.hide),this.addEventListener("keydown",this.keys),this.panel.addEventListener("mousedown",this.mousedown),this.panel.setAttribute("data-open","");const e=this.panel.querySelector("button");e&&e.focus()}hide(){document.removeEventListener("mousedown",this.hide,!1),this.removeEventListener("keydown",this.keys),this.panel.hasAttribute("data-open")&&this.panel.removeAttribute("data-open"),this.icon.focus()}colorSelect(e){let t="",s="",i="";e.target.classList.contains("nocolor")?(t="none",s="transparent",i="nocolor"):(t=e.target.style.backgroundColor,s=t),this.buttons.forEach(e=>{e.classList.contains("active")&&e.classList.remove("active")}),e.target.classList.add("active"),this.icon.classList.remove("nocolor"),this.icon.setAttribute("class",i),this.icon.style.backgroundColor=s,this.hide(),this.options.forEach(e=>{e.selected&&e.removeAttribute("selected"),e.value===s&&e.setAttribute("selected","")})}keys(e){if(e.keyCode===t.ESC&&this.hide(),e.keyCode===t.TAB){const t=this.focusableElements.indexOf(document.activeElement);!e.shiftKey||0!==t&&-1!==t||(this.focusableElements[this.focusableElements.length-1].focus(),e.preventDefault()),e.shiftKey||t!==this.focusableElements.length-1||(this.focusableElements[0].focus(),e.preventDefault())}}mousedown(e){e.stopPropagation(),e.preventDefault()}getColorName(e){let t=e;if(4===e.length){const s=e.split("");t=s[0]+s[1]+s[1]+s[2]+s[2]+s[3]+s[3]}for(const e in s)if(s.hasOwnProperty(e)&&t.toLowerCase()===s[e])return e;return this.textColor+" "+e.replace("#","").split("").join(", ")}})})(customElements); \ No newline at end of file diff --git a/package.json b/package.json index 028432f1d9f27..d71abdbef3b66 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,8 @@ "field-media", "field-user", "field-switcher", - "field-send-test-mail", + "field-simple-color", + "field-send-test-mail" "hidden-mail" ], "webcomponents": { @@ -94,6 +95,7 @@ "css": "media/system/webcomponents/css", "js": "media/system/webcomponents/js" }, + "field-simple-color": { "field-send-test-mail": { "css": "media/system/webcomponents/css", "js": "media/system/webcomponents/js" diff --git a/templates/cassiopeia/templateDetails.xml b/templates/cassiopeia/templateDetails.xml index 99769751eb452..b293d4b0ed951 100644 --- a/templates/cassiopeia/templateDetails.xml +++ b/templates/cassiopeia/templateDetails.xml @@ -79,6 +79,13 @@ +