(function () { 'use strict'; /** * @copyright (C) 2019 Open Source Matters, Inc. * @license GNU General Public License version 2 or later; see LICENSE.txt */ /* eslint class-methods-use-this: ["error", { "exceptMethods": ["rgbToHex", "hslToRgb"] }] */ (function (document) { /** * Regex for hex values e.g. #FF3929 * @type {RegExp} */ var hexRegex = /^#([a-z0-9]{1,2})([a-z0-9]{1,2})([a-z0-9]{1,2})$/i; /** * Regex for rgb values e.g. rgba(255, 0, 24, 0.5); * @type {RegExp} */ var rgbRegex = /^rgba?\(([0-9]+)[\D]+([0-9]+)[\D]+([0-9]+)(?:[\D]+([0-9](?:.\d+)?))?\)$/i; /** * Regex for hsl values e.g. hsl(255,0,24); * @type {RegExp} */ var hslRegex = /^hsla?\(([0-9]+)[\D]+([0-9]+)[\D]+([0-9]+)[\D]+([0-9](?:.\d+)?)?\)$/i; /** * Regex for saturation and lightness of hsl - only accepts 1 or 0 or 0.4 or 40 * @type {RegExp} */ var hslNumberRegex = /^(([0-1])|(0\\.[0-9]+)|([0-9]{1,2})|(100))$/; /** * Regex for hue values - one to three numbers * @type {RegExp} */ var hueRegex = /^[0-9]{1,3}$/; /** * Creates a slider for the color values hue, saturation and light. * * @since 4.0.0 */ var JoomlaFieldColorSlider = /*#__PURE__*/function () { /** * @param {HTMLElement} element */ function JoomlaFieldColorSlider(element) { var _this = this; // Elements this.messageSpan = element.querySelector('.form-control-feedback'); this.mainInput = element.querySelector('.color-input'); this.input = element.querySelector('#slider-input'); this.sliders = element.querySelectorAll('.color-slider'); this.hueSlider = element.querySelector('#hue-slider'); this.saturationSlider = element.querySelector('#saturation-slider'); this.lightSlider = element.querySelector('#light-slider'); this.alphaSlider = element.querySelector('#alpha-slider'); // Attributes this.color = element.dataset.color || ''; this.default = element.dataset.default || ''; this.format = this.input.dataset.format || 'hex'; this.saveFormat = this.mainInput.dataset.format || 'hex'; this.preview = element.dataset.preview === 'true'; this.setAlpha = this.format === 'hsla' || this.format === 'rgba'; this.hue = 360; this.saturation = 1; this.light = 1; this.alpha = 1; this.defaultHsl = [this.hue, this.saturation, this.light, this.alpha]; this.setInitValue(); this.setBackground(); // Hide preview field, when selected value should not be visible if (!this.preview) { this.input.classList.add('hidden'); } else { this.setInputPattern(); } // Always hide main input field (value saved in database) this.mainInput.classList.add('hidden'); Array.prototype.forEach.call(this.sliders, function (slider) { slider.addEventListener('change', function () { return _this.updateValue(slider); }); }); this.input.addEventListener('change', function () { return _this.changeInput(_this.input); }); } /** * Set selected value into input field and set it as its background-color. */ var _proto = JoomlaFieldColorSlider.prototype; _proto.updateValue = function updateValue(slider) { this.showError(''); var hsl = this.getSliderValueAsHsl(slider.value, slider.dataset.type); var rgb = this.hslToRgb(hsl); this.hue = hsl[0]; this.saturation = hsl[1]; this.light = hsl[2]; this.alpha = hsl[3]; this.input.style.border = "2px solid " + this.getRgbString(rgb); this.setSliderValues(hsl, slider.dataset.type); this.setInputValue(hsl); this.setBackground(slider); } /** * React on user changing input value * * @param {HTMLElement} inputField */ ; _proto.changeInput = function changeInput(inputField) { var hsl = [this.hue, this.saturation, this.light, this.alpha]; if (!inputField.value) { this.mainInput.value = ''; this.showError(''); return; } if (!this.checkValue(inputField.value)) { this.showError('JFIELD_COLOR_ERROR_WRONG_FORMAT'); this.setInputValue(this.defaultHsl); } else { this.showError(''); switch (this.format) { case 'hue': hsl[0] = inputField.value; this.hue = inputField.value; break; case 'saturation': hsl[1] = inputField.value; this.saturation = inputField.value; break; case 'light': hsl[2] = inputField.value; this.light = inputField.value; break; case 'alpha': hsl[3] = inputField.value; this.alpha = inputField.value; break; default: hsl = this.getHsl(inputField.value); } this.setSliderValues(hsl); this.setInputValue(hsl, true); } } /** * Check validity of value * * @param {number|string} value to check * @param {string=false} format for which the value gets tested * @returns {boolean} */ ; _proto.checkValue = function checkValue(value, format) { var test = format || this.format; switch (test) { case 'hue': return value <= 360 && hueRegex.test(value); case 'saturation': case 'light': case 'alpha': return hslNumberRegex.test(value); case 'hsl': case 'hsla': return hslRegex.test(value); case 'hex': return hexRegex.test(value); case 'rgb': case 'rgba': return rgbRegex.test(value); default: return false; } } /** * Set validation pattern on input field */ ; _proto.setInputPattern = function setInputPattern() { var pattern; // RegExp has '/' at start and end switch (this.format) { case 'hue': pattern = hueRegex.source.slice(1, -1); break; case 'saturation': case 'light': case 'alpha': pattern = hslNumberRegex.source.slice(1, -1); break; case 'hsl': case 'hsla': pattern = hslRegex.source.slice(1, -1); break; case 'rgb': pattern = rgbRegex.source.slice(1, -1); break; case 'hex': default: pattern = hexRegex.source.slice(1, -1); } this.input.setAttribute('pattern', pattern); } /** * Set linear gradient for slider background * @param {HTMLInputElement} [exceptSlider] */ ; _proto.setBackground = function setBackground(exceptSlider) { var _this2 = this; Array.prototype.forEach.call(this.sliders, function (slider) { // Jump over changed slider if (exceptSlider === slider) { return; } var colors = []; var endValue = 100; // Longer start color so slider selection matches displayed colors colors.push(_this2.getSliderValueAsRgb(0, slider.dataset.type)); if (slider.dataset.type === 'hue') { var steps = Math.floor(360 / 20); endValue = 360; for (var i = 0; i <= 360; i += steps) { colors.push(_this2.getSliderValueAsRgb(i, slider.dataset.type)); } } else { for (var _i = 0; _i <= 100; _i += 10) { colors.push(_this2.getSliderValueAsRgb(_i, slider.dataset.type)); } } // Longer end color so slider selection matches displayed colors colors.push(_this2.getSliderValueAsRgb(endValue, slider.dataset.type)); colors = colors.map(function (value) { return _this2.getRgbString(value); }); slider.style.background = "linear-gradient(90deg, " + colors.join(',') + ")"; slider.style.webkitAppearance = 'none'; }); } /** * Convert given color into hue, saturation and light */ ; _proto.setInitValue = function setInitValue() { // The initial value can be also a color defined in css var cssValue = window.getComputedStyle(this.input).getPropertyValue(this.default); this.default = cssValue || this.default; if (this.color === '' || typeof this.color === 'undefined') { // Unable to get hsl with empty value this.input.value = ''; this.mainInput.value = ''; return; } var value = this.checkValue(this.color, this.saveFormat) ? this.color : this.default; if (!value) { this.showError('JFIELD_COLOR_ERROR_NO_COLOUR'); return; } var hsl = []; // When given value is a number, use it as defined format and get rest from default value if (/^[0-9]+$/.test(value)) { hsl = this.default && this.getHsl(this.default); if (this.format === 'hue') { hsl[0] = value; } if (this.format === 'saturation') { hsl[1] = value > 1 ? value / 100 : value; } if (this.format === 'light') { hsl[2] = value > 1 ? value / 100 : value; } if (this.format === 'alpha') { hsl[3] = value > 1 ? value / 100 : value; } } else { hsl = this.getHsl(value); } var _hsl = hsl; this.hue = _hsl[0]; this.saturation = _hsl[1]; this.light = _hsl[2]; this.alpha = hsl[4] || this.alpha; this.defaultHsl = this.default ? this.getHsl(this.default) : hsl; this.setSliderValues(hsl); this.setInputValue(hsl); this.input.style.border = "2px solid " + this.getRgbString(this.hslToRgb(hsl)); } /** * Insert message into error message span * Message gets handled with Joomla.Text or as empty string * * @param {string} msg */ ; _proto.showError = function showError(msg) { this.messageSpan.innerText = msg ? Joomla.Text._(msg) : ''; } /** * Convert value into HSLa e.g. #003E7C => [210, 100, 24] * @param {array|number|string} value * @returns {array} */ ; _proto.getHsl = function getHsl(value) { var hsl = []; if (Array.isArray(value)) { hsl = value; } else if (hexRegex.test(value)) { hsl = this.hexToHsl(value); } else if (rgbRegex.test(value)) { hsl = this.rgbToHsl(value); } else if (hslRegex.test(value)) { var matches = value.match(hslRegex); hsl = [matches[1], matches[2], matches[3], matches[4]]; } else { this.showError('JFIELD_COLOR_ERROR_CONVERT_HSL'); return this.defaultHsl; } // Convert saturation etc. values from e.g. 40 to 0.4 var i; for (i = 1; i < hsl.length; i += 1) { hsl[i] = hsl[i] > 1 ? hsl[i] / 100 : hsl[i]; } return hsl; } /** * Returns HSL value from color slider value * @params {int} value convert this value * @params {string} type type of value: hue, saturation, light or alpha * @returns array */ ; _proto.getSliderValueAsHsl = function getSliderValueAsHsl(value, type) { var h = this.hue; var s = this.saturation; var l = this.light; var a = this.alpha; switch (type) { case 'alpha': a = value; break; case 'saturation': s = value; break; case 'light': l = value; break; case 'hue': default: h = value; } // Percentage light and saturation if (l > 1) { l /= 100; } if (s > 1) { s /= 100; } if (a > 1) { a /= 100; } return [h, s, l, a]; } /** * Calculates RGB value from color slider value * @params {int} value convert this value * @params {string} type type of value: hue, saturation, light or alpha * @returns array */ ; _proto.getSliderValueAsRgb = function getSliderValueAsRgb(value, type) { return this.hslToRgb(this.getSliderValueAsHsl(value, type)); } /** * Set value in all sliders * @param {array} [hsla] * @param {string} [except] */ ; _proto.setSliderValues = function setSliderValues(_ref, except) { var h = _ref[0], s = _ref[1], l = _ref[2], a = _ref[3]; if (this.hueSlider && except !== 'hue') { this.hueSlider.value = Math.round(h); } if (this.saturationSlider && except !== 'saturation') { this.saturationSlider.value = Math.round(s * 100); } if (this.lightSlider && except !== 'light') { this.lightSlider.value = Math.round(l * 100); } if (a && this.alphaSlider && except !== 'alpha') { this.alphaSlider.value = Math.round(a * 100); } } /** * Set value in text input fields depending on their format * @param {array} hsl * @param {boolean=false} onlyMain indicates to change mainInput only */ ; _proto.setInputValue = function setInputValue(hsl, onlyMain) { var _this3 = this; var inputs = [this.mainInput]; if (!onlyMain) { inputs.push(this.input); } inputs.forEach(function (input) { var value; switch (input.dataset.format) { case 'hsl': value = _this3.getHslString(hsl); break; case 'hsla': value = _this3.getHslString(hsl, true); break; case 'rgb': value = _this3.getRgbString(_this3.hslToRgb(hsl)); break; case 'rgba': value = _this3.getRgbString(_this3.hslToRgb(hsl), true); break; case 'hex': value = _this3.rgbToHex(_this3.hslToRgb(hsl)); break; case 'alpha': value = Math.round(hsl[3] * 100); break; case 'saturation': value = Math.round(hsl[1] * 100); break; case 'light': value = Math.round(hsl[2] * 100); break; case 'hue': default: value = Math.round(hsl[0]); break; } input.value = value; }); } /** * Put RGB values into a string like 'rgb(, , )' * @params {array} rgba * @params {boolean=false} withAlpha * @return {string} */ ; _proto.getRgbString = function getRgbString(_ref2, withAlpha) { var r = _ref2[0], g = _ref2[1], b = _ref2[2], a = _ref2[3]; if (withAlpha || this.setAlpha) { var alpha = typeof a === 'undefined' ? this.alpha : a; return "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"; } return "rgb(" + r + ", " + g + ", " + b + ")"; } /** * Put HSL values into a string like 'hsl(, %, %, )' * @params {array} values * @params {boolean=false} withAlpha * @return {string} */ ; _proto.getHslString = function getHslString(values, withAlpha) { var h = values[0], s = values[1], l = values[2], a = values[3]; s *= 100; l *= 100; var _map = [h, s, l].map(function (value) { return Math.round(value); }); h = _map[0]; s = _map[1]; l = _map[2]; if (withAlpha || this.setAlpha) { a = a || this.alpha; return "hsla(" + h + ", " + s + "%, " + l + "%, " + a + ")"; } return "hsl(" + h + ", " + s + "%, " + l + "%)"; } /** * Returns hsl values out of hex * @param {array} rgb * @return {string} */ ; _proto.rgbToHex = function rgbToHex(rgb) { var r = rgb[0].toString(16).toUpperCase(); var g = rgb[1].toString(16).toUpperCase(); var b = rgb[2].toString(16).toUpperCase(); // Double value for hex with '#' and 6 chars r = r.length === 1 ? "" + r + r : r; g = g.length === 1 ? "" + g + g : g; b = b.length === 1 ? "" + b + b : b; return "#" + r + g + b; } /** * Returns hsl values out of rgb * @param {string|array} values * @return {array} */ ; _proto.rgbToHsl = function rgbToHsl(values) { var rgb = values; if (typeof values === 'string') { var parts = values.match(rgbRegex); rgb = [parts[1], parts[2], parts[3], parts[4]]; } var _rgb$map = rgb.map(function (value) { return value > 1 ? value / 255 : value; }), r = _rgb$map[0], g = _rgb$map[1], b = _rgb$map[2]; var max = Math.max(r, g, b); var min = Math.min(r, g, b); var l = (max + min) / 2; var d = max - min; var h = 0; var s = 0; var a = rgb[3] || values[3] || this.alpha; if (max !== min) { if (max === 0) { s = max; } else if (min === 1) { s = min; } else { s = (max - l) / Math.min(l, 1 - l); } switch (max) { case r: h = 60 * (g - b) / d; break; case g: h = 60 * (2 + (b - r) / d); break; case b: default: h = 60 * (4 + (r - g) / d); break; } } h = h < 0 ? h + 360 : h; a = a > 1 ? a / 100 : a; return [h, s, l, a]; } /** * Returns hsl values out of hex * @param {string} hex * @return {array} */ ; _proto.hexToHsl = function hexToHsl(hex) { var parts = hex.match(hexRegex); var r = parts[1]; var g = parts[2]; var b = parts[3]; var rgb = [parseInt(r, 16), parseInt(g, 16), parseInt(b, 16)]; return this.rgbToHsl(rgb); } /** * Convert HSLa values into RGBa * @param {array} hsla * @returns {number[]} */ ; _proto.hslToRgb = function hslToRgb(_ref3) { var h = _ref3[0], sat = _ref3[1], light = _ref3[2], alpha = _ref3[3]; var r = 1; var g = 1; var b = 1; // Saturation and light were calculated as 0.24 instead of 24% var s = sat > 1 ? sat / 100 : sat; var l = light > 1 ? light / 100 : light; var a = alpha > 1 ? alpha / 100 : alpha; if (h < 0 || h > 360 || s < 0 || s > 1 || l < 0 || l > 1) { this.showError('JFIELD_COLOR_ERROR_CONVERT_HSL'); return this.hslToRgb(this.defaultHsl); } var c = (1 - Math.abs(2 * l - 1)) * s; var hi = h / 60; var x = c * (1 - Math.abs(hi % 2 - 1)); var m = l - c / 2; if (h >= 0 && h < 60) { r = c; g = x; b = 0; } else if (h >= 60 && h < 120) { r = x; g = c; b = 0; } else if (h >= 120 && h < 180) { r = 0; g = c; b = x; } else if (h >= 180 && h < 240) { r = 0; g = x; b = c; } else if (h >= 240 && h < 300) { r = x; g = 0; b = c; } else if (h >= 300 && h <= 360) { r = c; g = 0; b = x; } else { this.showError('JFIELD_COLOR_ERROR_CONVERT_HUE'); return this.hslToRgb(this.defaultHsl); } var rgb = [r, g, b].map(function (value) { return Math.round((value + m) * 255); }); rgb.push(a); return rgb; }; return JoomlaFieldColorSlider; }(); document.addEventListener('DOMContentLoaded', function () { var fields = document.querySelectorAll('.color-slider-wrapper'); if (fields) { Array.prototype.forEach.call(fields, function (slider) { // eslint-disable-next-line no-new new JoomlaFieldColorSlider(slider); }); } }); })(document); })();