From 799e765621a7cad8decacdf842706c1cd6ebff1f Mon Sep 17 00:00:00 2001 From: Agriya Dev5 Date: Thu, 21 Jan 2021 19:33:06 +0530 Subject: [PATCH 01/18] #46 Move this jQuery component to a web component for graduate and picker components --- src/editor/components/index.js | 1 + .../components/seColorGraduatePicker.js | 306 ++++++++++++++++++ src/editor/index.html | 1 + 3 files changed, 308 insertions(+) create mode 100644 src/editor/components/seColorGraduatePicker.js diff --git a/src/editor/components/index.js b/src/editor/components/index.js index 8f16e993..120e116b 100644 --- a/src/editor/components/index.js +++ b/src/editor/components/index.js @@ -10,3 +10,4 @@ import './seMenuItem.js'; import './seList.js'; import './seListItem.js'; import './seColorPicker.js'; +import './seColorGraduatePicker.js'; diff --git a/src/editor/components/seColorGraduatePicker.js b/src/editor/components/seColorGraduatePicker.js new file mode 100644 index 00000000..dcf07daf --- /dev/null +++ b/src/editor/components/seColorGraduatePicker.js @@ -0,0 +1,306 @@ +/* eslint-disable node/no-unpublished-import */ +import 'elix/define/PopupButton.js'; +import PaintBox from './PaintBox.js'; + +const template = document.createElement('template'); +template.innerHTML = ` + + +
+ + +
+
+
+ + +
+`; +/** + * @class SeColorPicker + */ +export class SeColorPicker extends HTMLElement { + /** + * @function constructor + */ + constructor () { + super(); + // create the shadowDom and insert the template + this._shadowRoot = this.attachShadow({mode: 'open'}); + this._shadowRoot.append(template.content.cloneNode(true)); + this.$logo = this._shadowRoot.getElementById('logo'); + this.$label = this._shadowRoot.getElementById('label'); + this.$block = this._shadowRoot.getElementById('block'); + this.paintBox = null; + this.$picker = this._shadowRoot.getElementById('picker'); + this.$color_picker = this._shadowRoot.getElementById('color_picker'); + this.$tabs = this._shadowRoot.querySelectorAll('.se-tabs'); + } + /** + * @function observedAttributes + * @returns {any} observed + */ + static get observedAttributes () { + return ['label', 'src', 'type']; + } + /** + * @function attributeChangedCallback + * @param {string} name + * @param {string} oldValue + * @param {string} newValue + * @returns {void} + */ + attributeChangedCallback (name, oldValue, newValue) { + if (oldValue === newValue) return; + switch (name) { + case 'src': + this.$logo.setAttribute('src', newValue); + break; + case 'label': + this.setAttribute('title', newValue); + break; + case 'type': + this.$label.setAttribute('title', `Pick a ${newValue} Paint and Opacity`); + break; + default: + // eslint-disable-next-line no-console + console.error(`unknown attribute: ${name}`); + break; + } + } + /** + * @function get + * @returns {any} + */ + get label () { + return this.$label.getAttribute('title'); + } + + /** + * @function set + * @returns {void} + */ + set label (value) { + this.setAttribute('label', value); + } + /** + * @function get + * @returns {any} + */ + get type () { + return this.getAttribute('type'); + } + + /** + * @function set + * @returns {void} + */ + set type (value) { + this.setAttribute('type', value); + } + /** + * @function get + * @returns {any} + */ + get src () { + return this.getAttribute('src'); + } + + /** + * @function set + * @returns {void} + */ + set src (value) { + this.setAttribute('src', value); + } + + /** + * @param {PlainObject} svgCanvas + * @param {PlainObject} selectedElement + * @param {bool} apply + * @returns {void} + */ + update (svgCanvas, selectedElement, apply) { + const paint = this.paintBox.update(svgCanvas, selectedElement); + if (paint && apply) { + const changeEvent = new CustomEvent('change', {detail: { + paint + }}); + this.dispatchEvent(changeEvent); + } + } + /** + * @param {PlainObject} paint + * @returns {void} + */ + setPaint (paint) { + this.paintBox.setPaint(paint); + } + + /** + * @function connectedCallback + * @returns {void} + */ + connectedCallback () { + this.paintBox = new PaintBox(this.$block, this.type); + const self = this._shadowRoot; + const onTabsClickHandler = (e) => { + e.target.parentElement.querySelectorAll('.se-tabs').forEach((ev) => { + ev.classList.remove('jGraduate_tab_current'); + self.getElementById(ev.dataset.section).style.display = 'none'; + }); + e.target.classList.add('jGraduate_tab_current'); + self.getElementById(e.target.dataset.section).style.display = 'block'; + }; + for (let i = 0; i < this.$tabs.length; i++) { + this.$tabs[i].addEventListener('click', onTabsClickHandler, false); + } + } +} + +// Register +customElements.define('se-color-graduate-picker', SeColorPicker); diff --git a/src/editor/index.html b/src/editor/index.html index 57700aaa..e55cef9d 100644 --- a/src/editor/index.html +++ b/src/editor/index.html @@ -331,6 +331,7 @@ + From 9e13a56b6ba7ddae905aae713fe052d096707445 Mon Sep 17 00:00:00 2001 From: Agriya Dev5 Date: Fri, 22 Jan 2021 18:54:39 +0530 Subject: [PATCH 02/18] #46 Move this jQuery component to a web component --- .../components/seColorGraduatePicker.js | 1696 ++++++++++++++++- 1 file changed, 1690 insertions(+), 6 deletions(-) diff --git a/src/editor/components/seColorGraduatePicker.js b/src/editor/components/seColorGraduatePicker.js index dcf07daf..74b2b0e5 100644 --- a/src/editor/components/seColorGraduatePicker.js +++ b/src/editor/components/seColorGraduatePicker.js @@ -1,3 +1,7 @@ +/* globals $ */ +/* eslint-disable unicorn/prefer-math-trunc */ +/* eslint-disable no-bitwise */ +/* eslint-disable class-methods-use-this */ /* eslint-disable node/no-unpublished-import */ import 'elix/define/PopupButton.js'; import PaintBox from './PaintBox.js'; @@ -60,7 +64,7 @@ template.innerHTML = ` Radial Gradient -
Solid Color sction
+
@@ -123,28 +127,28 @@ template.innerHTML = `
- +
- +
- +
- +
@@ -160,6 +164,621 @@ template.innerHTML = `
`; +/** + * Whether a value is `null` or `undefined`. + * @param {any} val + * @returns {boolean} + */ +const isNullish = (val) => { + return val === null || val === undefined; +}; +/** + * @class Slider + */ +class Slider { + /** + * @param {external:jQuery} bar + * @param {module:jPicker.SliderOptions} options + */ + constructor (bar, options) { + const that = this; + /** + * Fire events on the supplied `context` + * @param {module:jPicker.JPickerInit} context + * @returns {void} + */ + function fireChangeEvents (context) { + changeEvents.forEach((changeEvent) => { + changeEvent.call(that, that, context); + }); + } + + /** + * Bind the mousedown to the bar not the arrow for quick snapping to the clicked location. + * @param {external:jQuery.Event} e + * @returns {void} + */ + function mouseDown (e) { + const off = bar.offset(); + offset = {l: off.left | 0, t: off.top | 0}; + clearTimeout(timeout); + // using setTimeout for visual updates - once the style is updated the browser will re-render internally allowing the next Javascript to run + timeout = setTimeout(function () { + setValuesFromMousePosition.call(that, e); + }, 0); + // Bind mousemove and mouseup event to the document so it responds when dragged of of the bar - we will unbind these when on mouseup to save processing + $(document).bind('mousemove', mouseMove).bind('mouseup', mouseUp); + e.preventDefault(); // don't try to select anything or drag the image to the desktop + } + /** + * Set the values as the mouse moves. + * @param {external:jQuery.Event} e + * @returns {false} + */ + function mouseMove (e) { + clearTimeout(timeout); + timeout = setTimeout(function () { + setValuesFromMousePosition.call(that, e); + }, 0); + e.stopPropagation(); + e.preventDefault(); + return false; + } + /** + * Unbind the document events - they aren't needed when not dragging. + * @param {external:jQuery.Event} e + * @returns {false} + */ + function mouseUp (e) { + $(document).unbind('mouseup', mouseUp).unbind('mousemove', mouseMove); + e.stopPropagation(); + e.preventDefault(); + return false; + } + + /** + * Calculate mouse position and set value within the current range. + * @param {Event} e + * @returns {void} + */ + function setValuesFromMousePosition (e) { + const barW = bar.w, // local copies for YUI compressor + barH = bar.h; + let locX = e.pageX - offset.l, + locY = e.pageY - offset.t; + // keep the arrow within the bounds of the bar + if (locX < 0) locX = 0; + else if (locX > barW) locX = barW; + if (locY < 0) locY = 0; + else if (locY > barH) locY = barH; + val.call(that, 'xy', { + x: ((locX / barW) * rangeX) + minX, + y: ((locY / barH) * rangeY) + minY + }); + } + /** + * + * @returns {void} + */ + function draw () { + const + barW = bar.w, + barH = bar.h, + arrowW = arrow.w, + arrowH = arrow.h; + let arrowOffsetX = 0, + arrowOffsetY = 0; + setTimeout(function () { + if (rangeX > 0) { // range is greater than zero + // constrain to bounds + arrowOffsetX = (x === maxX) ? barW : (((x / rangeX) * barW) | 0); + } + if (rangeY > 0) { // range is greater than zero + // constrain to bounds + arrowOffsetY = (y === maxY) ? barH : ((y / rangeY) * barH) | 0; + } + // if arrow width is greater than bar width, center arrow and prevent horizontal dragging + if (arrowW >= barW) arrowOffsetX = (barW >> 1) - (arrowW >> 1); // number >> 1 - superfast bitwise divide by two and truncate (move bits over one bit discarding lowest) + else arrowOffsetX -= arrowW >> 1; + // if arrow height is greater than bar height, center arrow and prevent vertical dragging + if (arrowH >= barH) arrowOffsetY = (barH >> 1) - (arrowH >> 1); + else arrowOffsetY -= arrowH >> 1; + // set the arrow position based on these offsets + arrow.css({left: arrowOffsetX + 'px', top: arrowOffsetY + 'px'}); + }); + } + + /** + * Get or set a value. + * @param {?("xy"|"x"|"y")} name + * @param {module:math.XYObject} value + * @param {module:jPicker.Slider} context + * @returns {module:math.XYObject|Float|void} + */ + function val (name, value, context) { + const set = value !== undefined; + if (!set) { + if (isNullish(name)) name = 'xy'; + switch (name.toLowerCase()) { + case 'x': return x; + case 'y': return y; + case 'xy': + default: return {x, y}; + } + } + if (!isNullish(context) && context === that) return undefined; + let changed = false; + + let newX, newY; + if (isNullish(name)) name = 'xy'; + switch (name.toLowerCase()) { + case 'x': + newX = (value && ((value.x && value.x | 0) || value | 0)) || 0; + break; + case 'y': + newY = (value && ((value.y && value.y | 0) || value | 0)) || 0; + break; + case 'xy': + default: + newX = (value && value.x && value.x | 0) || 0; + newY = (value && value.y && value.y | 0) || 0; + break; + } + if (!isNullish(newX)) { + if (newX < minX) newX = minX; + else if (newX > maxX) newX = maxX; + if (x !== newX) { + x = newX; + changed = true; + } + } + if (!isNullish(newY)) { + if (newY < minY) newY = minY; + else if (newY > maxY) newY = maxY; + if (y !== newY) { + y = newY; + changed = true; + } + } + changed && fireChangeEvents.call(that, context || that); + return undefined; + } + + /** + * @typedef {PlainObject} module:jPicker.MinMaxRangeX + * @property {Float} minX + * @property {Float} maxX + * @property {Float} rangeX + */ + /** + * @typedef {PlainObject} module:jPicker.MinMaxRangeY + * @property {Float} minY + * @property {Float} maxY + * @property {Float} rangeY + */ + /** + * @typedef {module:jPicker.MinMaxRangeY|module:jPicker.MinMaxRangeX} module:jPicker.MinMaxRangeXY + */ + + /** + * + * @param {"minx"|"maxx"|"rangex"|"miny"|"maxy"|"rangey"|"all"} name + * @param {module:jPicker.MinMaxRangeXY} value + * @returns {module:jPicker.MinMaxRangeXY|module:jPicker.MinMaxRangeX|module:jPicker.MinMaxRangeY|void} + */ + function range (name, value) { + const set = value !== undefined; + if (!set) { + if (isNullish(name)) name = 'all'; + switch (name.toLowerCase()) { + case 'minx': return minX; + case 'maxx': return maxX; + case 'rangex': return {minX, maxX, rangeX}; + case 'miny': return minY; + case 'maxy': return maxY; + case 'rangey': return {minY, maxY, rangeY}; + case 'all': + default: return {minX, maxX, rangeX, minY, maxY, rangeY}; + } + } + let // changed = false, + newMinX, + newMaxX, + newMinY, + newMaxY; + if (isNullish(name)) name = 'all'; + switch (name.toLowerCase()) { + case 'minx': + newMinX = (value && ((value.minX && value.minX | 0) || value | 0)) || 0; + break; + case 'maxx': + newMaxX = (value && ((value.maxX && value.maxX | 0) || value | 0)) || 0; + break; + case 'rangex': + newMinX = (value && value.minX && value.minX | 0) || 0; + newMaxX = (value && value.maxX && value.maxX | 0) || 0; + break; + case 'miny': + newMinY = (value && ((value.minY && value.minY | 0) || value | 0)) || 0; + break; + case 'maxy': + newMaxY = (value && ((value.maxY && value.maxY | 0) || value | 0)) || 0; + break; + case 'rangey': + newMinY = (value && value.minY && value.minY | 0) || 0; + newMaxY = (value && value.maxY && value.maxY | 0) || 0; + break; + case 'all': + default: + newMinX = (value && value.minX && value.minX | 0) || 0; + newMaxX = (value && value.maxX && value.maxX | 0) || 0; + newMinY = (value && value.minY && value.minY | 0) || 0; + newMaxY = (value && value.maxY && value.maxY | 0) || 0; + break; + } + + if (!isNullish(newMinX) && minX !== newMinX) { + minX = newMinX; + rangeX = maxX - minX; + } + if (!isNullish(newMaxX) && maxX !== newMaxX) { + maxX = newMaxX; + rangeX = maxX - minX; + } + if (!isNullish(newMinY) && minY !== newMinY) { + minY = newMinY; + rangeY = maxY - minY; + } + if (!isNullish(newMaxY) && maxY !== newMaxY) { + maxY = newMaxY; + rangeY = maxY - minY; + } + return undefined; + } + /** + * @param {GenericCallback} callback + * @returns {void} + */ + function bind (callback) { // eslint-disable-line promise/prefer-await-to-callbacks + if (typeof callback === 'function') changeEvents.push(callback); + } + /** + * @param {GenericCallback} callback + * @returns {void} + */ + function unbind (callback) { // eslint-disable-line promise/prefer-await-to-callbacks + if (typeof callback !== 'function') return; + let i; + while ((i = changeEvents.includes(callback))) changeEvents.splice(i, 1); + } + /** + * + * @returns {void} + */ + function destroy () { + // unbind all possible events and null objects + $(document).unbind('mouseup', mouseUp).unbind('mousemove', mouseMove); + bar.unbind('mousedown', mouseDown); + bar = null; + arrow = null; + changeEvents = null; + } + let offset, + timeout, + x = 0, + y = 0, + minX = 0, + maxX = 100, + rangeX = 100, + minY = 0, + maxY = 100, + rangeY = 100, + arrow = bar.querySelector('img'), // bar.find('img:first'), // the arrow image to drag + changeEvents = []; + $.extend( + true, + // public properties, methods, and event bindings - these we need + // to access from other controls + that, + { + val, + range, + bind, + unbind, + destroy + } + ); + // initialize this control + arrow.src = options.arrow && options.arrow.image; + arrow.w = (options.arrow && options.arrow.width) || arrow.width(); + arrow.h = (options.arrow && options.arrow.height) || arrow.height(); + bar.w = (options.map && options.map.width) || bar.width(); + bar.h = (options.map && options.map.height) || bar.height(); + // bind mousedown event + // bar.bind('mousedown', mouseDown); + bind.call(that, draw); + } +} + +/** + * Controls for all the input elements for the typing in color values. + */ +class ColorValuePicker { + /** + * @param {external:jQuery} picker + * @param {external:jQuery.jPicker.Color} color + * @param {external:jQuery.fn.$.fn.jPicker} bindedHex + * @param {Float} alphaPrecision + */ + constructor (picker, color, bindedHex, alphaPrecision) { + const that = this; // private properties and methods + const inputs = picker.find('td.Text input'); + // input box key down - use arrows to alter color + /** + * + * @param {Event} e + * @returns {Event|false|void} + */ + function keyDown (e) { + if (e.target.value === '' && e.target !== hex.get(0) && ((!isNullish(bindedHex) && e.target !== bindedHex.get(0)) || isNullish(bindedHex))) return undefined; + if (!validateKey(e)) return e; + switch (e.target) { + case red.get(0): + switch (e.keyCode) { + case 38: + red.val(setValueInRange.call(that, (red.val() << 0) + 1, 0, 255)); + color.val('r', red.val(), e.target); + return false; + case 40: + red.val(setValueInRange.call(that, (red.val() << 0) - 1, 0, 255)); + color.val('r', red.val(), e.target); + return false; + } + break; + case green.get(0): + switch (e.keyCode) { + case 38: + green.val(setValueInRange.call(that, (green.val() << 0) + 1, 0, 255)); + color.val('g', green.val(), e.target); + return false; + case 40: + green.val(setValueInRange.call(that, (green.val() << 0) - 1, 0, 255)); + color.val('g', green.val(), e.target); + return false; + } + break; + case blue.get(0): + switch (e.keyCode) { + case 38: + blue.val(setValueInRange.call(that, (blue.val() << 0) + 1, 0, 255)); + color.val('b', blue.val(), e.target); + return false; + case 40: + blue.val(setValueInRange.call(that, (blue.val() << 0) - 1, 0, 255)); + color.val('b', blue.val(), e.target); + return false; + } + break; + case alpha && alpha.get(0): + switch (e.keyCode) { + case 38: + alpha.val(setValueInRange.call(that, Number.parseFloat(alpha.val()) + 1, 0, 100)); + color.val('a', toFixedNumeric((alpha.val() * 255) / 100, alphaPrecision), e.target); + return false; + case 40: + alpha.val(setValueInRange.call(that, Number.parseFloat(alpha.val()) - 1, 0, 100)); + color.val('a', toFixedNumeric((alpha.val() * 255) / 100, alphaPrecision), e.target); + return false; + } + break; + case hue.get(0): + switch (e.keyCode) { + case 38: + hue.val(setValueInRange.call(that, (hue.val() << 0) + 1, 0, 360)); + color.val('h', hue.val(), e.target); + return false; + case 40: + hue.val(setValueInRange.call(that, (hue.val() << 0) - 1, 0, 360)); + color.val('h', hue.val(), e.target); + return false; + } + break; + case saturation.get(0): + switch (e.keyCode) { + case 38: + saturation.val(setValueInRange.call(that, (saturation.val() << 0) + 1, 0, 100)); + color.val('s', saturation.val(), e.target); + return false; + case 40: + saturation.val(setValueInRange.call(that, (saturation.val() << 0) - 1, 0, 100)); + color.val('s', saturation.val(), e.target); + return false; + } + break; + case value.get(0): + switch (e.keyCode) { + case 38: + value.val(setValueInRange.call(that, (value.val() << 0) + 1, 0, 100)); + color.val('v', value.val(), e.target); + return false; + case 40: + value.val(setValueInRange.call(that, (value.val() << 0) - 1, 0, 100)); + color.val('v', value.val(), e.target); + return false; + } + break; + } + return undefined; + } + // input box key up - validate value and set color + /** + * @param {Event} e + * @returns {Event|void} + * @todo Why is this returning an event? + */ + function keyUp (e) { + if (e.target.value === '' && e.target !== hex.get(0) && + ((!isNullish(bindedHex) && e.target !== bindedHex.get(0)) || + isNullish(bindedHex))) return undefined; + if (!validateKey(e)) return e; + switch (e.target) { + case red.get(0): + red.val(setValueInRange.call(that, red.val(), 0, 255)); + color.val('r', red.val(), e.target); + break; + case green.get(0): + green.val(setValueInRange.call(that, green.val(), 0, 255)); + color.val('g', green.val(), e.target); + break; + case blue.get(0): + blue.val(setValueInRange.call(that, blue.val(), 0, 255)); + color.val('b', blue.val(), e.target); + break; + case alpha && alpha.get(0): + alpha.val(setValueInRange.call(that, alpha.val(), 0, 100)); + color.val('a', toFixedNumeric((alpha.val() * 255) / 100, alphaPrecision), e.target); + break; + case hue.get(0): + hue.val(setValueInRange.call(that, hue.val(), 0, 360)); + color.val('h', hue.val(), e.target); + break; + case saturation.get(0): + saturation.val(setValueInRange.call(that, saturation.val(), 0, 100)); + color.val('s', saturation.val(), e.target); + break; + case value.get(0): + value.val(setValueInRange.call(that, value.val(), 0, 100)); + color.val('v', value.val(), e.target); + break; + case hex.get(0): + hex.val(hex.val().replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 6)); + bindedHex && bindedHex.val(hex.val()); + color.val('hex', hex.val() !== '' ? hex.val() : null, e.target); + break; + case bindedHex && bindedHex.get(0): + bindedHex.val(bindedHex.val().replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 6)); + hex.val(bindedHex.val()); + color.val('hex', bindedHex.val() !== '' ? bindedHex.val() : null, e.target); + break; + case ahex && ahex.get(0): + ahex.val(ahex.val().replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 2)); + color.val('a', !isNullish(ahex.val()) ? Number.parseInt(ahex.val(), 16) : null, e.target); + break; + } + return undefined; + } + // input box blur - reset to original if value empty + /** + * @param {Event} e + * @returns {void} + */ + function blur (e) { + if (!isNullish(color.val())) { + switch (e.target) { + case red.get(0): red.val(color.val('r')); break; + case green.get(0): green.val(color.val('g')); break; + case blue.get(0): blue.val(color.val('b')); break; + case alpha && alpha.get(0): alpha.val(toFixedNumeric((color.val('a') * 100) / 255, alphaPrecision)); break; + case hue.get(0): hue.val(color.val('h')); break; + case saturation.get(0): saturation.val(color.val('s')); break; + case value.get(0): value.val(color.val('v')); break; + case hex.get(0): + case bindedHex && bindedHex.get(0): + hex.val(color.val('hex')); + bindedHex && bindedHex.val(color.val('hex')); + break; + case ahex && ahex.get(0): ahex.val(color.val('ahex').substring(6)); break; + } + } + } + /** + * @param {Event} e + * @returns {boolean} + */ + function validateKey (e) { + switch (e.keyCode) { + case 9: + case 16: + case 29: + case 37: + case 39: + return false; + case 'c'.charCodeAt(): + case 'v'.charCodeAt(): + if (e.ctrlKey) return false; + } + return true; + } + + /** + * Constrain value within range. + * @param {Float|string} value + * @param {Float} min + * @param {Float} max + * @returns {Float|string} Returns a number or numeric string + */ + function setValueInRange (value, min, max) { + if (value === '' || isNaN(value)) return min; + if (value > max) return max; + if (value < min) return min; + return value; + } + /** + * @param {external:jQuery} ui + * @param {Element} context + * @returns {void} + */ + function colorChanged (ui, context) { + const all = ui.val('all'); + if (context !== red.get(0)) red.val(!isNullish(all) ? all.r : ''); + if (context !== green.get(0)) green.val(!isNullish(all) ? all.g : ''); + if (context !== blue.get(0)) blue.val(!isNullish(all) ? all.b : ''); + if (alpha && context !== alpha.get(0)) alpha.val(!isNullish(all) ? toFixedNumeric((all.a * 100) / 255, alphaPrecision) : ''); + if (context !== hue.get(0)) hue.val(!isNullish(all) ? all.h : ''); + if (context !== saturation.get(0)) saturation.val(!isNullish(all) ? all.s : ''); + if (context !== value.get(0)) value.val(!isNullish(all) ? all.v : ''); + if (context !== hex.get(0) && ((bindedHex && context !== bindedHex.get(0)) || !bindedHex)) hex.val(!isNullish(all) ? all.hex : ''); + if (bindedHex && context !== bindedHex.get(0) && context !== hex.get(0)) bindedHex.val(!isNullish(all) ? all.hex : ''); + if (ahex && context !== ahex.get(0)) ahex.val(!isNullish(all) ? all.ahex.substring(6) : ''); + } + /** + * Unbind all events and null objects. + * @returns {void} + */ + function destroy () { + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).unbind('keyup', keyUp).unbind('blur', blur); + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).unbind('keydown', keyDown); + color.unbind(colorChanged); + red = null; + green = null; + blue = null; + alpha = null; + hue = null; + saturation = null; + value = null; + hex = null; + ahex = null; + } + let + red = inputs.eq(3), + green = inputs.eq(4), + blue = inputs.eq(5), + alpha = inputs.length > 7 ? inputs.eq(6) : null, + hue = inputs.eq(0), + saturation = inputs.eq(1), + value = inputs.eq(2), + hex = inputs.eq(inputs.length > 7 ? 7 : 6), + ahex = inputs.length > 7 ? inputs.eq(8) : null; + $.extend(true, that, { + // public properties and methods + destroy + }); + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).bind('keyup', keyUp).bind('blur', blur); + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).bind('keydown', keyDown); + color.bind(colorChanged); + } +} + /** * @class SeColorPicker */ @@ -180,6 +799,1070 @@ export class SeColorPicker extends HTMLElement { this.$color_picker = this._shadowRoot.getElementById('color_picker'); this.$tabs = this._shadowRoot.querySelectorAll('.se-tabs'); } + /** + * @function initPicker + * @returns {void} + */ + initPicker () { + const that = this; + this.currentTab = 'solidColor'; + this.SLIDERW = '145px'; + this.MAX = 256; + this.MARGINX = 0; + this.MARGINY = 0; + this.ns = { + svg: 'http://www.w3.org/2000/svg', + xlink: 'http://www.w3.org/1999/xlink' + }; + this.isGecko = navigator.userAgent.includes('Gecko/'); + // paintbox init + this.paintBox = new PaintBox(this.$block, this.type); + // ------------------------------------------------------------- + + this.jPicker = { + Color: function (init) { // eslint-disable-line object-shorthand + const that = this; + /** + * + * @param {module:jPicker.Slider} context + * @returns {void} + */ + function fireChangeEvents (context) { + for (let i = 0; i < changeEvents.length; i++) changeEvents[i].call(that, that, context); + } + + /** + * @param {string|"ahex"|"hex"|"all"|""|null|void} name String composed of letters "r", "g", "b", "a", "h", "s", and/or "v" + * @param {module:jPicker.RGBA|module:jPicker.JPickerInit|string} [value] + * @param {external:jQuery.jPicker.Color} context + * @returns {module:jPicker.JPickerInit|string|null|void} + */ + function val (name, value, context) { + // Kind of ugly + const set = Boolean(value); + if (set && value.ahex === '') value.ahex = '00000000'; + if (!set) { + let ret; + if (isNullish(name) || name === '') name = 'all'; + if (isNullish(r)) return null; + switch (name.toLowerCase()) { + case 'ahex': return ColorMethods.rgbaToHex({r, g, b, a}); + case 'hex': return val('ahex').substring(0, 6); + case 'all': return { + r, g, b, a, h, s, v, + hex: val.call(that, 'hex'), + ahex: val.call(that, 'ahex') + }; + default: { + ret = {}; + const nameLength = name.length; + [...name].forEach((ch) => { + switch (ch) { + case 'r': + if (nameLength === 1) ret = r; + else ret.r = r; + break; + case 'g': + if (nameLength === 1) ret = g; + else ret.g = g; + break; + case 'b': + if (nameLength === 1) ret = b; + else ret.b = b; + break; + case 'a': + if (nameLength === 1) ret = a; + else ret.a = a; + break; + case 'h': + if (nameLength === 1) ret = h; + else ret.h = h; + break; + case 's': + if (nameLength === 1) ret = s; + else ret.s = s; + break; + case 'v': + if (nameLength === 1) ret = v; + else ret.v = v; + break; + } + }); + } + } + return typeof ret === 'object' && !Object.keys(ret).length + ? val.call(that, 'all') + : ret; + } + if (!isNullish(context) && context === that) return undefined; + if (isNullish(name)) name = ''; + + let changed = false; + if (isNullish(value)) { + if (!isNullish(r)) { + r = null; + changed = true; + } + if (!isNullish(g)) { + g = null; + changed = true; + } + if (!isNullish(b)) { + b = null; + changed = true; + } + if (!isNullish(a)) { + a = null; + changed = true; + } + if (!isNullish(h)) { + h = null; + changed = true; + } + if (!isNullish(s)) { + s = null; + changed = true; + } + if (!isNullish(v)) { + v = null; + changed = true; + } + changed && fireChangeEvents.call(that, context || that); + return undefined; + } + switch (name.toLowerCase()) { + case 'ahex': + case 'hex': { + const ret = ColorMethods.hexToRgba((value && (value.ahex || value.hex)) || value || 'none'); + val.call(that, 'rgba', { + r: ret.r, + g: ret.g, + b: ret.b, + a: name === 'ahex' + ? ret.a + : !isNullish(a) + ? a + : 255 + }, context); + break; + } default: { + if (value && (!isNullish(value.ahex) || !isNullish(value.hex))) { + val.call(that, 'ahex', value.ahex || value.hex || '00000000', context); + return undefined; + } + const newV = {}; + let rgb = false, hsv = false; + if (value.r !== undefined && !name.includes('r')) name += 'r'; + if (value.g !== undefined && !name.includes('g')) name += 'g'; + if (value.b !== undefined && !name.includes('b')) name += 'b'; + if (value.a !== undefined && !name.includes('a')) name += 'a'; + if (value.h !== undefined && !name.includes('h')) name += 'h'; + if (value.s !== undefined && !name.includes('s')) name += 's'; + if (value.v !== undefined && !name.includes('v')) name += 'v'; + [...name].forEach((ch) => { + switch (ch) { + case 'r': + if (hsv) return; + rgb = true; + newV.r = (value.r && value.r | 0) || (value | 0) || 0; + if (newV.r < 0) newV.r = 0; + else if (newV.r > 255) newV.r = 255; + if (r !== newV.r) { + ({r} = newV); + changed = true; + } + break; + case 'g': + if (hsv) return; + rgb = true; + newV.g = (value && value.g && value.g | 0) || (value && value | 0) || 0; + if (newV.g < 0) newV.g = 0; + else if (newV.g > 255) newV.g = 255; + if (g !== newV.g) { + ({g} = newV); + changed = true; + } + break; + case 'b': + if (hsv) return; + rgb = true; + newV.b = (value && value.b && value.b | 0) || (value && value | 0) || 0; + if (newV.b < 0) newV.b = 0; + else if (newV.b > 255) newV.b = 255; + if (b !== newV.b) { + ({b} = newV); + changed = true; + } + break; + case 'a': + newV.a = value && !isNullish(value.a) ? value.a | 0 : value | 0; + if (newV.a < 0) newV.a = 0; + else if (newV.a > 255) newV.a = 255; + if (a !== newV.a) { + ({a} = newV); + changed = true; + } + break; + case 'h': + if (rgb) return; + hsv = true; + newV.h = (value && value.h && value.h | 0) || (value && value | 0) || 0; + if (newV.h < 0) newV.h = 0; + else if (newV.h > 360) newV.h = 360; + if (h !== newV.h) { + ({h} = newV); + changed = true; + } + break; + case 's': + if (rgb) return; + hsv = true; + newV.s = !isNullish(value.s) ? value.s | 0 : value | 0; + if (newV.s < 0) newV.s = 0; + else if (newV.s > 100) newV.s = 100; + if (s !== newV.s) { + ({s} = newV); + changed = true; + } + break; + case 'v': + if (rgb) return; + hsv = true; + newV.v = !isNullish(value.v) ? value.v | 0 : value | 0; + if (newV.v < 0) newV.v = 0; + else if (newV.v > 100) newV.v = 100; + if (v !== newV.v) { + ({v} = newV); + changed = true; + } + break; + } + }); + if (changed) { + if (rgb) { + r = r || 0; + g = g || 0; + b = b || 0; + const ret = ColorMethods.rgbToHsv({r, g, b}); + ({h, s, v} = ret); + } else if (hsv) { + h = h || 0; + s = !isNullish(s) ? s : 100; + v = !isNullish(v) ? v : 100; + const ret = ColorMethods.hsvToRgb({h, s, v}); + ({r, g, b} = ret); + } + a = !isNullish(a) ? a : 255; + fireChangeEvents.call(that, context || that); + } + break; + } + } + return undefined; + } + /** + * @param {GenericCallback} callback + * @returns {void} + */ + function bind (callback) { // eslint-disable-line promise/prefer-await-to-callbacks + if (typeof callback === 'function') changeEvents.push(callback); + } + /** + * @param {GenericCallback} callback + * @returns {void} + */ + function unbind (callback) { // eslint-disable-line promise/prefer-await-to-callbacks + if (typeof callback !== 'function') return; + let i; + while ((i = changeEvents.includes(callback))) { + changeEvents.splice(i, 1); + } + } + /** + * Unset `changeEvents` + * @returns {void} + */ + function destroy () { + changeEvents = null; + } + let r, g, b, a, h, s, v, changeEvents = []; + + $.extend(true, that, { + // public properties and methods + val, + bind, + unbind, + destroy + }); + if (init) { + if (!isNullish(init.ahex)) { + val('ahex', init); + } else if (!isNullish(init.hex)) { + val( + (!isNullish(init.a) ? 'a' : '') + 'hex', + !isNullish(init.a) + ? {ahex: init.hex + ColorMethods.intToHex(init.a)} + : init + ); + } else if (!isNullish(init.r) && !isNullish(init.g) && !isNullish(init.b)) { + val('rgb' + (!isNullish(init.a) ? 'a' : ''), init); + } else if (!isNullish(init.h) && !isNullish(init.s) && !isNullish(init.v)) { + val('hsv' + (!isNullish(init.a) ? 'a' : ''), init); + } + } + }, + /** + * Color conversion methods - make public to give use to external scripts. + * @namespace + */ + ColorMethods: { + /** + * @typedef {PlainObject} module:jPicker.RGBA + * @property {Integer} r + * @property {Integer} g + * @property {Integer} b + * @property {Integer} a + */ + /** + * @typedef {PlainObject} module:jPicker.RGB + * @property {Integer} r + * @property {Integer} g + * @property {Integer} b + */ + /** + * @param {string} hex + * @returns {module:jPicker.RGBA} + */ + hexToRgba (hex) { + if (hex === '' || hex === 'none') return {r: null, g: null, b: null, a: null}; + hex = this.validateHex(hex); + let r = '00', g = '00', b = '00', a = '255'; + if (hex.length === 6) hex += 'ff'; + if (hex.length > 6) { + r = hex.substring(0, 2); + g = hex.substring(2, 4); + b = hex.substring(4, 6); + a = hex.substring(6, hex.length); + } else { + if (hex.length > 4) { + r = hex.substring(4, hex.length); + hex = hex.substring(0, 4); + } + if (hex.length > 2) { + g = hex.substring(2, hex.length); + hex = hex.substring(0, 2); + } + if (hex.length > 0) b = hex.substring(0, hex.length); + } + return { + r: this.hexToInt(r), g: this.hexToInt(g), b: this.hexToInt(b), a: this.hexToInt(a) + }; + }, + /** + * @param {string} hex + * @returns {string} + */ + validateHex (hex) { + // if (typeof hex === 'object') return ''; + hex = hex.toLowerCase().replace(/[^a-f\d]/g, ''); + if (hex.length > 8) hex = hex.substring(0, 8); + return hex; + }, + /** + * @param {module:jPicker.RGBA} rgba + * @returns {string} + */ + rgbaToHex (rgba) { + return this.intToHex(rgba.r) + this.intToHex(rgba.g) + this.intToHex(rgba.b) + this.intToHex(rgba.a); + }, + /** + * @param {Integer} dec + * @returns {string} + */ + intToHex (dec) { + let result = (dec | 0).toString(16); + if (result.length === 1) result = ('0' + result); + return result.toLowerCase(); + }, + /** + * @param {string} hex + * @returns {Integer} + */ + hexToInt (hex) { + return Number.parseInt(hex, 16); + }, + /** + * @typedef {PlainObject} module:jPicker.HSV + * @property {Integer} h + * @property {Integer} s + * @property {Integer} v + */ + /** + * @param {module:jPicker.RGB} rgb + * @returns {module:jPicker.HSV} + */ + rgbToHsv (rgb) { + const r = rgb.r / 255, g = rgb.g / 255, b = rgb.b / 255, hsv = {h: 0, s: 0, v: 0}; + let min = 0, max = 0; + if (r >= g && r >= b) { + max = r; + min = g > b ? b : g; + } else if (g >= b && g >= r) { + max = g; + min = r > b ? b : r; + } else { + max = b; + min = g > r ? r : g; + } + hsv.v = max; + hsv.s = max ? (max - min) / max : 0; + let delta; + if (!hsv.s) hsv.h = 0; + else { + delta = max - min; + if (r === max) hsv.h = (g - b) / delta; + else if (g === max) hsv.h = 2 + (b - r) / delta; + else hsv.h = 4 + (r - g) / delta; + hsv.h = Number.parseInt(hsv.h * 60); + if (hsv.h < 0) hsv.h += 360; + } + hsv.s = (hsv.s * 100) | 0; + hsv.v = (hsv.v * 100) | 0; + return hsv; + }, + /** + * @param {module:jPicker.HSV} hsv + * @returns {module:jPicker.RGB} + */ + hsvToRgb (hsv) { + const rgb = {r: 0, g: 0, b: 0, a: 100}; + let {h, s, v} = hsv; + if (s === 0) { + if (v === 0) rgb.r = rgb.g = rgb.b = 0; + else rgb.r = rgb.g = rgb.b = (v * 255 / 100) | 0; + } else { + if (h === 360) h = 0; + h /= 60; + s /= 100; + v /= 100; + const i = h | 0, + f = h - i, + p = v * (1 - s), + q = v * (1 - (s * f)), + t = v * (1 - (s * (1 - f))); + switch (i) { + case 0: + rgb.r = v; + rgb.g = t; + rgb.b = p; + break; + case 1: + rgb.r = q; + rgb.g = v; + rgb.b = p; + break; + case 2: + rgb.r = p; + rgb.g = v; + rgb.b = t; + break; + case 3: + rgb.r = p; + rgb.g = q; + rgb.b = v; + break; + case 4: + rgb.r = t; + rgb.g = p; + rgb.b = v; + break; + case 5: + rgb.r = v; + rgb.g = p; + rgb.b = q; + break; + } + rgb.r = (rgb.r * 255) | 0; + rgb.g = (rgb.g * 255) | 0; + rgb.b = (rgb.b * 255) | 0; + } + return rgb; + } + }, + default: { + window: { + title: null, + effects: { + type: 'slide', + speed: { + show: 'slow', + hide: 'fast' + } + }, + position: { + x: 'screenCenter', + y: 'top' + }, + expandable: false, + liveUpdate: true, + alphaSupport: false, + alphaPrecision: 0, + updateInputColor: true + }, + color: { + mode: 'h', + active: '', // new Color({ahex: '#ffcc00ff'}), + quickList: [ + /* new Color({h: 360, s: 33, v: 100}), + new Color({h: 360, s: 66, v: 100}), + new Color({h: 360, s: 100, v: 100}), + new Color({h: 360, s: 100, v: 75}), + new Color({h: 360, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 100}), + new Color({h: 30, s: 33, v: 100}), + new Color({h: 30, s: 66, v: 100}), + new Color({h: 30, s: 100, v: 100}), + new Color({h: 30, s: 100, v: 75}), + new Color({h: 30, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 90}), + new Color({h: 60, s: 33, v: 100}), + new Color({h: 60, s: 66, v: 100}), + new Color({h: 60, s: 100, v: 100}), + new Color({h: 60, s: 100, v: 75}), + new Color({h: 60, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 80}), + new Color({h: 90, s: 33, v: 100}), + new Color({h: 90, s: 66, v: 100}), + new Color({h: 90, s: 100, v: 100}), + new Color({h: 90, s: 100, v: 75}), + new Color({h: 90, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 70}), + new Color({h: 120, s: 33, v: 100}), + new Color({h: 120, s: 66, v: 100}), + new Color({h: 120, s: 100, v: 100}), + new Color({h: 120, s: 100, v: 75}), + new Color({h: 120, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 60}), + new Color({h: 150, s: 33, v: 100}), + new Color({h: 150, s: 66, v: 100}), + new Color({h: 150, s: 100, v: 100}), + new Color({h: 150, s: 100, v: 75}), + new Color({h: 150, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 50}), + new Color({h: 180, s: 33, v: 100}), + new Color({h: 180, s: 66, v: 100}), + new Color({h: 180, s: 100, v: 100}), + new Color({h: 180, s: 100, v: 75}), + new Color({h: 180, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 40}), + new Color({h: 210, s: 33, v: 100}), + new Color({h: 210, s: 66, v: 100}), + new Color({h: 210, s: 100, v: 100}), + new Color({h: 210, s: 100, v: 75}), + new Color({h: 210, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 30}), + new Color({h: 240, s: 33, v: 100}), + new Color({h: 240, s: 66, v: 100}), + new Color({h: 240, s: 100, v: 100}), + new Color({h: 240, s: 100, v: 75}), + new Color({h: 240, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 20}), + new Color({h: 270, s: 33, v: 100}), + new Color({h: 270, s: 66, v: 100}), + new Color({h: 270, s: 100, v: 100}), + new Color({h: 270, s: 100, v: 75}), + new Color({h: 270, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 10}), + new Color({h: 300, s: 33, v: 100}), + new Color({h: 300, s: 66, v: 100}), + new Color({h: 300, s: 100, v: 100}), + new Color({h: 300, s: 100, v: 75}), + new Color({h: 300, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 0}), + new Color({h: 330, s: 33, v: 100}), + new Color({h: 330, s: 66, v: 100}), + new Color({h: 330, s: 100, v: 100}), + new Color({h: 330, s: 100, v: 75}), + new Color({h: 330, s: 100, v: 50}), + new Color() */ + ] + }, + images: { + clientPath: './components/jgraduate/images/', + colorMap: { + width: 256, + height: 256, + arrow: { + file: 'mappoint.gif', + width: 15, + height: 15 + } + }, + colorBar: { + width: 20, + height: 256, + arrow: { + file: 'rangearrows.gif', + width: 20, + height: 7 + } + }, + picker: { + file: 'picker.gif', + width: 25, + height: 24 + } + }, + localization: { + text: { + title: 'Drag Markers To Pick A Color', + newColor: 'new', + currentColor: 'current', + ok: 'OK', + cancel: 'Cancel' + }, + tooltips: { + colors: { + newColor: 'New Color - Press “OK” To Commit', + currentColor: 'Click To Revert To Original Color' + }, + buttons: { + ok: 'Commit To This Color Selection', + cancel: 'Cancel And Revert To Original Color' + }, + hue: { + radio: 'Set To “Hue” Color Mode', + textbox: 'Enter A “Hue” Value (0-360°)' + }, + saturation: { + radio: 'Set To “Saturation” Color Mode', + textbox: 'Enter A “Saturation” Value (0-100%)' + }, + value: { + radio: 'Set To “Value” Color Mode', + textbox: 'Enter A “Value” Value (0-100%)' + }, + red: { + radio: 'Set To “Red” Color Mode', + textbox: 'Enter A “Red” Value (0-255)' + }, + green: { + radio: 'Set To “Green” Color Mode', + textbox: 'Enter A “Green” Value (0-255)' + }, + blue: { + radio: 'Set To “Blue” Color Mode', + textbox: 'Enter A “Blue” Value (0-255)' + }, + alpha: { + radio: 'Set To “Alpha” Color Mode', + textbox: 'Enter A “Alpha” Value (0-100)' + }, + hex: { + textbox: 'Enter A “Hex” Color Value (#000000-#ffffff)', + alpha: 'Enter A “Alpha” Value (#00-#ff)' + } + } + } + } + }; + const isLessThanIE7 = Number.parseFloat(navigator.appVersion.split('MSIE')[1]) < 7 && document.body.filters; + const settings = this.jPicker.default; + const win = settings.window; + const {Color, ColorMethods} = this.jPicker; + const {images, localization, color} = settings; // local copies for YUI compressor + const colorObj = { + active: (typeof settings.color.active).toString().toLowerCase() === 'string' + ? new Color({ahex: !win.alphaSupport && settings.color.active + ? settings.color.active.substring(0, 6) + 'ff' + : settings.color.active + }) + : new Color({ahex: !win.alphaSupport && + settings.color.active.val('ahex') + ? settings.color.active.val('ahex').substring(0, 6) + 'ff' + : settings.color.active.val('ahex') + }), + current: (typeof settings.color.active).toString().toLowerCase() === 'string' + ? new Color({ahex: !win.alphaSupport && settings.color.active + ? settings.color.active.substring(0, 6) + 'ff' + : settings.color.active}) + : new Color({ahex: !win.alphaSupport && + settings.color.active.val('ahex') + ? settings.color.active.val('ahex').substring(0, 6) + 'ff' + : settings.color.active.val('ahex') + }), + quickList: settings.color.quickList + }; + + /* if (typeof commitCallback !== 'function') { + commitCallback = null; + } + if (typeof liveCallback !== 'function') { + liveCallback = null; + } + if (typeof cancelCallback !== 'function') { + cancelCallback = null; + } */ + + /** + * @external Math + */ + /** + * @memberof external:Math + * @param {Float} value + * @param {Float} precision + * @returns {Float} + */ + function toFixedNumeric (value, precision) { + if (precision === undefined) precision = 0; + return Math.round(value * (10 ** precision)) / (10 ** precision); + } + + /** + * User has dragged the ColorMap pointer. + * @param {external:jQuery} ui + * @param {?module:jPicker.Slider} context + * @returns {void} + */ + function mapValueChanged (ui, context) { + const {active} = color; + if (context !== colorMap && isNullish(active.val())) return; + const xy = ui.val('all'); + switch (settings.color.mode) { + case 'h': + active.val('sv', {s: xy.x, v: 100 - xy.y}, context); + break; + case 's': + case 'a': + active.val('hv', {h: xy.x, v: 100 - xy.y}, context); + break; + case 'v': + active.val('hs', {h: xy.x, s: 100 - xy.y}, context); + break; + case 'r': + active.val('gb', {g: 255 - xy.y, b: xy.x}, context); + break; + case 'g': + active.val('rb', {r: 255 - xy.y, b: xy.x}, context); + break; + case 'b': + active.val('rg', {r: xy.x, g: 255 - xy.y}, context); + break; + } + } + + /** + * @param {external:jQuery} img + * @param {string} src The image source + * @returns {void} + */ + function setImg (img, src) { + if (isLessThanIE7 && (src.includes('AlphaBar.png') || src.includes('Bars.png') || src.includes('Maps.png'))) { + img.attr('pngSrc', src); + img.style.cssText = `backgroundImage: 'none', filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\', sizingMethod=\'scale\')'`; + /* img.css({backgroundImage: 'none', filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\', sizingMethod=\'scale\')'}); */ + } else { + console.log("came -->", src); + img.style.backgroundImage = `url('${src}')`; + // img.css({backgroundImage: 'url(\'' + src + '\')'}); + } + } + + + const all = null; + let elementStartX = null, // Used to record the starting css positions for dragging the control + elementStartY = null, + pageStartX = null, // Used to record the mousedown coordinates for dragging the control + pageStartY = null, + colorMapDiv = null, + colorBarDiv = null, + colorMapL1 = null, // different layers of colorMap and colorBar + colorMapL2 = null, + colorMapL3 = null, + colorBarL1 = null, + colorBarL2 = null, + colorBarL3 = null, + colorBarL4 = null, + colorBarL5 = null, + colorBarL6 = null, + colorMap = null, // color maps + colorBar = null, + colorPicker = null, + activePreview = null, // color boxes above the radio buttons + currentPreview = null, + okButton = null, + cancelButton = null, + grid = null, // preset colors grid + iconColor = null, // iconColor for popup icon + iconAlpha = null, // iconAlpha for popup icon + iconImage = null, // iconImage popup icon + moveBar = null; // drag bar + const controlHtml = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ` : ' '} + +
+

${localization.text.title}

+
+   +   +   + +
+
+
+   +   +   +   +   +   + +
+
+ ${localization.text.newColor} +
+   +   +
+ ${localization.text.currentColor} +
+ + +
+
 
+
+ + +  ° +
+ + +  % +
+ +
+
+
+  % +
+
+
+ + + +
+ + + +
+ + + +
+ ${win.alphaSupport ? `` : ' '} + + ${win.alphaSupport ? ` %` : ' '} +
+ + ${win.alphaSupport ? `
`; + this._shadowRoot.getElementById('se-color-pick').innerHTML = controlHtml; + // initialize the objects to the source code just injected + const tbody = this._shadowRoot.getElementById('solid-tbody'); + colorMapDiv = this._shadowRoot.getElementById('Map'); // tbody.find('div.Map:first'); + colorBarDiv = this._shadowRoot.getElementById('Bar'); // tbody.find('div.Bar:first'); + // const MapMaps = colorMapDiv.find('span'); + // const BarMaps = colorBarDiv.find('span'); + colorMapL1 = this._shadowRoot.getElementById('Map-Map1'); // MapMaps.filter('.Map1:first'); + colorMapL2 = this._shadowRoot.getElementById('Map-Map2'); // MapMaps.filter('.Map2:first'); + colorMapL3 = this._shadowRoot.getElementById('Map-Map3'); // MapMaps.filter('.Map3:first'); + colorBarL1 = this._shadowRoot.getElementById('Bar-Map1'); // BarMaps.filter('.Map1:first'); + colorBarL2 = this._shadowRoot.getElementById('Bar-Map2'); // BarMaps.filter('.Map2:first'); + colorBarL3 = this._shadowRoot.getElementById('Bar-Map3'); // BarMaps.filter('.Map3:first'); + colorBarL4 = this._shadowRoot.getElementById('Bar-Map4'); // BarMaps.filter('.Map4:first'); + colorBarL5 = this._shadowRoot.getElementById('Bar-Map5'); // BarMaps.filter('.Map5:first'); + colorBarL6 = this._shadowRoot.getElementById('Bar-Map6'); // BarMaps.filter('.Map6:first'); + + // create color pickers and maps + colorMap = new Slider( + colorMapDiv, + { + map: { + width: images.colorMap.width, + height: images.colorMap.height + }, + arrow: { + image: images.clientPath + images.colorMap.arrow.file, + width: images.colorMap.arrow.width, + height: images.colorMap.arrow.height + } + } + ); + colorMap.bind(mapValueChanged); + colorBar = new Slider( + colorBarDiv, + { + map: { + width: images.colorBar.width, + height: images.colorBar.height + }, + arrow: { + image: images.clientPath + images.colorBar.arrow.file, + width: images.colorBar.arrow.width, + height: images.colorBar.arrow.height + } + } + ); + const preview = tbody.querySelector('#Preview'); + // colorBar.bind(colorBarValueChanged); + /* colorPicker = new ColorValuePicker( + tbody, + color.active, + win.expandable && win.bindToInput ? win.input : null, + win.alphaPrecision + ); + const hex = !isNullish(all) ? all.hex : null, + preview = tbody.querySelector('#Preview'), // tbody.find('.Preview'), + button = tbody.querySelector('#Button'); // tbody.find('.Button'); + activePreview = preview.find('.Active:first').css({backgroundColor: (hex && '#' + hex) || 'transparent'}); + currentPreview = preview.find('.Current:first').css({backgroundColor: (hex && '#' + hex) || 'transparent'}).bind('click', currentClicked); + setAlpha.call(that, currentPreview, toFixedNumeric((color.current.val('a') * 100) / 255, 4)); + okButton = button.find('.Ok:first').bind('click', okClicked); + cancelButton = button.find('.Cancel:first').bind('click', cancelClicked); + grid = button.find('.Grid:first'); */ + setTimeout(function () { + setImg.call(that, colorMapL1, images.clientPath + 'Maps.png'); + setImg.call(that, colorMapL2, images.clientPath + 'Maps.png'); + setImg.call(that, colorMapL3, images.clientPath + 'map-opacity.png'); + setImg.call(that, colorBarL1, images.clientPath + 'Bars.png'); + setImg.call(that, colorBarL2, images.clientPath + 'Bars.png'); + setImg.call(that, colorBarL3, images.clientPath + 'Bars.png'); + setImg.call(that, colorBarL4, images.clientPath + 'Bars.png'); + setImg.call(that, colorBarL5, images.clientPath + 'bar-opacity.png'); + setImg.call(that, colorBarL6, images.clientPath + 'AlphaBar.png'); + setImg.call(that, preview.querySelector('div'), images.clientPath + 'preview-opacity.png'); + }, 0); + // preview.find('div:first') + // tbody.find('td.Radio input').bind('click', radioClicked); + + // ---------------------------------------------------------------- + + this.applyStyle('.jGraduate_SliderBar', 'width', this.SLIDERW); + const container = this._shadowRoot.getElementById('color_picker_jGraduate_GradContainer'); + const svg = this.mkElem('svg', { + id: 'color_picker_jgraduate_svg', + width: this.MAX, + height: this.MAX, + xmlns: this.ns.svg + }, container); + } + /** + * @function selectAll + * @param {string} selector + * @returns {any} + */ + selectAll (selector) { + return this._shadowRoot.querySelectorAll(selector); + } + + /** + * @function applyStyle + * @param {string} selector + * @param {string} attr + * @param {any} value + * @returns {void} + */ + applyStyle (selector, attr, value) { + const elements = this.selectAll(selector); + for (const element of elements) { + element.style[attr] = value; + } + } + /** + * @param {SVGElement} elem + * @param {module:jGraduate.Attrs} attrs + * @returns {void} + */ + setAttrs (elem, attrs) { + if (this.isGecko) { + Object.entries(attrs).forEach(([aname, val]) => { + elem.setAttribute(aname, val); + }); + } else { + Object.entries(attrs).forEach(([aname, val]) => { + const prop = elem[aname]; + if (prop && prop.constructor === 'SVGLength') { + prop.baseVal.value = val; + } else { + elem.setAttribute(aname, val); + } + }); + } + } + /** + * @function mkElem + * @param {string} name + * @param {module:jGraduate.Attrs} attrs + * @param {Element} newparent + * @returns {SVGElement} + */ + mkElem (name, attrs, newparent) { + const elem = document.createElementNS(this.ns.svg, name); + this.setAttrs(elem, attrs); + if (newparent) { + newparent.append(elem); + } + return elem; + } /** * @function observedAttributes * @returns {any} observed @@ -286,8 +1969,9 @@ export class SeColorPicker extends HTMLElement { * @returns {void} */ connectedCallback () { - this.paintBox = new PaintBox(this.$block, this.type); + this.initPicker(); const self = this._shadowRoot; + self.querySelector('#se-color-pick').style.display = 'block'; const onTabsClickHandler = (e) => { e.target.parentElement.querySelectorAll('.se-tabs').forEach((ev) => { ev.classList.remove('jGraduate_tab_current'); From ca5e885f6bb1460da60d1e5dddb6cd9dea3b3f7f Mon Sep 17 00:00:00 2001 From: Agriya Dev5 Date: Mon, 1 Feb 2021 19:56:11 +0530 Subject: [PATCH 03/18] #46 picker convert as pure javascript changes --- .../components/seColorGraduatePicker.js | 666 ++++++++++++++---- 1 file changed, 542 insertions(+), 124 deletions(-) diff --git a/src/editor/components/seColorGraduatePicker.js b/src/editor/components/seColorGraduatePicker.js index 74b2b0e5..4b23b524 100644 --- a/src/editor/components/seColorGraduatePicker.js +++ b/src/editor/components/seColorGraduatePicker.js @@ -164,6 +164,19 @@ template.innerHTML = `
`; +/** +* @external Math +*/ +/** +* @memberof external:Math +* @param {Float} value +* @param {Float} precision +* @returns {Float} +*/ +function toFixedNumeric (value, precision) { + if (precision === undefined) precision = 0; + return Math.round(value * (10 ** precision)) / (10 ** precision); +} /** * Whether a value is `null` or `undefined`. * @param {any} val @@ -512,7 +525,7 @@ class ColorValuePicker { */ constructor (picker, color, bindedHex, alphaPrecision) { const that = this; // private properties and methods - const inputs = picker.find('td.Text input'); + const inputs = picker.querySelectorAll('td.Text input'); // input box key down - use arrows to alter color /** * @@ -746,9 +759,44 @@ class ColorValuePicker { * @returns {void} */ function destroy () { - red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).unbind('keyup', keyUp).unbind('blur', blur); - red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).unbind('keydown', keyDown); - color.unbind(colorChanged); + red.removeEventListener('keyup', keyUp); + green.removeEventListener('keyup', keyUp); + blue.removeEventListener('keyup', keyUp); + hue.removeEventListener('keyup', keyUp); + saturation.removeEventListener('keyup', keyUp); + value.removeEventListener('keyup', keyUp); + hex.removeEventListener('keyup', keyUp); + + red.removeEventListener('blur', blur); + green.removeEventListener('blur', blur); + blue.removeEventListener('blur', blur); + hue.removeEventListener('blur', blur); + saturation.removeEventListener('blur', blur); + value.removeEventListener('blur', blur); + hex.removeEventListener('blur', blur); + + red.removeEventListener('keydown', keyDown); + green.removeEventListener('keydown', keyDown); + blue.removeEventListener('keydown', keyDown); + hue.removeEventListener('keydown', keyDown); + saturation.removeEventListener('keydown', keyDown); + value.removeEventListener('keydown', keyDown); + + if (alpha !== null) { + alpha.removeEventListener('keyup', keyUp); + alpha.removeEventListener('blur', blur); + alpha.removeEventListener('keydown', keyDown); + } + if (ahex !== null) { + ahex.removeEventListener('keyup', keyUp); + ahex.removeEventListener('blur', blur); + } + if (bindedHex !== null) { + bindedHex.removeEventListener('keyup', keyUp); + bindedHex.removeEventListener('blur', blur); + } + // TODO: color unbind + // color.unbind(colorChanged); red = null; green = null; blue = null; @@ -760,22 +808,57 @@ class ColorValuePicker { ahex = null; } let - red = inputs.eq(3), - green = inputs.eq(4), - blue = inputs.eq(5), - alpha = inputs.length > 7 ? inputs.eq(6) : null, - hue = inputs.eq(0), - saturation = inputs.eq(1), - value = inputs.eq(2), - hex = inputs.eq(inputs.length > 7 ? 7 : 6), - ahex = inputs.length > 7 ? inputs.eq(8) : null; + red = inputs[3], + green = inputs[4], + blue = inputs[5], + alpha = inputs.length > 7 ? inputs[6] : null, + hue = inputs[0], + saturation = inputs[1], + value = inputs[2], + hex = inputs[inputs.length > 7 ? 7 : 6], + ahex = inputs.length > 7 ? inputs[8] : null; $.extend(true, that, { // public properties and methods destroy }); - red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).bind('keyup', keyUp).bind('blur', blur); - red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).bind('keydown', keyDown); - color.bind(colorChanged); + red.addEventListener('keyup', keyUp); + green.addEventListener('keyup', keyUp); + blue.addEventListener('keyup', keyUp); + hue.addEventListener('keyup', keyUp); + saturation.addEventListener('keyup', keyUp); + value.addEventListener('keyup', keyUp); + hex.addEventListener('keyup', keyUp); + + red.addEventListener('blur', blur); + green.addEventListener('blur', blur); + blue.addEventListener('blur', blur); + hue.addEventListener('blur', blur); + saturation.addEventListener('blur', blur); + value.addEventListener('blur', blur); + hex.addEventListener('blur', blur); + + red.addEventListener('keydown', keyDown); + green.addEventListener('keydown', keyDown); + blue.addEventListener('keydown', keyDown); + hue.addEventListener('keydown', keyDown); + saturation.addEventListener('keydown', keyDown); + value.addEventListener('keydown', keyDown); + + if (alpha !== null) { + alpha.addEventListener('keyup', keyUp); + alpha.addEventListener('blur', blur); + alpha.addEventListener('keydown', keyDown); + } + if (ahex !== null) { + ahex.addEventListener('keyup', keyUp); + ahex.addEventListener('blur', blur); + } + if (bindedHex !== null) { + bindedHex.addEventListener('keyup', keyUp); + bindedHex.addEventListener('blur', blur); + } + // TODO: color + // color.bind(colorChanged); } } @@ -1312,80 +1395,7 @@ export class SeColorPicker extends HTMLElement { color: { mode: 'h', active: '', // new Color({ahex: '#ffcc00ff'}), - quickList: [ - /* new Color({h: 360, s: 33, v: 100}), - new Color({h: 360, s: 66, v: 100}), - new Color({h: 360, s: 100, v: 100}), - new Color({h: 360, s: 100, v: 75}), - new Color({h: 360, s: 100, v: 50}), - new Color({h: 180, s: 0, v: 100}), - new Color({h: 30, s: 33, v: 100}), - new Color({h: 30, s: 66, v: 100}), - new Color({h: 30, s: 100, v: 100}), - new Color({h: 30, s: 100, v: 75}), - new Color({h: 30, s: 100, v: 50}), - new Color({h: 180, s: 0, v: 90}), - new Color({h: 60, s: 33, v: 100}), - new Color({h: 60, s: 66, v: 100}), - new Color({h: 60, s: 100, v: 100}), - new Color({h: 60, s: 100, v: 75}), - new Color({h: 60, s: 100, v: 50}), - new Color({h: 180, s: 0, v: 80}), - new Color({h: 90, s: 33, v: 100}), - new Color({h: 90, s: 66, v: 100}), - new Color({h: 90, s: 100, v: 100}), - new Color({h: 90, s: 100, v: 75}), - new Color({h: 90, s: 100, v: 50}), - new Color({h: 180, s: 0, v: 70}), - new Color({h: 120, s: 33, v: 100}), - new Color({h: 120, s: 66, v: 100}), - new Color({h: 120, s: 100, v: 100}), - new Color({h: 120, s: 100, v: 75}), - new Color({h: 120, s: 100, v: 50}), - new Color({h: 180, s: 0, v: 60}), - new Color({h: 150, s: 33, v: 100}), - new Color({h: 150, s: 66, v: 100}), - new Color({h: 150, s: 100, v: 100}), - new Color({h: 150, s: 100, v: 75}), - new Color({h: 150, s: 100, v: 50}), - new Color({h: 180, s: 0, v: 50}), - new Color({h: 180, s: 33, v: 100}), - new Color({h: 180, s: 66, v: 100}), - new Color({h: 180, s: 100, v: 100}), - new Color({h: 180, s: 100, v: 75}), - new Color({h: 180, s: 100, v: 50}), - new Color({h: 180, s: 0, v: 40}), - new Color({h: 210, s: 33, v: 100}), - new Color({h: 210, s: 66, v: 100}), - new Color({h: 210, s: 100, v: 100}), - new Color({h: 210, s: 100, v: 75}), - new Color({h: 210, s: 100, v: 50}), - new Color({h: 180, s: 0, v: 30}), - new Color({h: 240, s: 33, v: 100}), - new Color({h: 240, s: 66, v: 100}), - new Color({h: 240, s: 100, v: 100}), - new Color({h: 240, s: 100, v: 75}), - new Color({h: 240, s: 100, v: 50}), - new Color({h: 180, s: 0, v: 20}), - new Color({h: 270, s: 33, v: 100}), - new Color({h: 270, s: 66, v: 100}), - new Color({h: 270, s: 100, v: 100}), - new Color({h: 270, s: 100, v: 75}), - new Color({h: 270, s: 100, v: 50}), - new Color({h: 180, s: 0, v: 10}), - new Color({h: 300, s: 33, v: 100}), - new Color({h: 300, s: 66, v: 100}), - new Color({h: 300, s: 100, v: 100}), - new Color({h: 300, s: 100, v: 75}), - new Color({h: 300, s: 100, v: 50}), - new Color({h: 180, s: 0, v: 0}), - new Color({h: 330, s: 33, v: 100}), - new Color({h: 330, s: 66, v: 100}), - new Color({h: 330, s: 100, v: 100}), - new Color({h: 330, s: 100, v: 75}), - new Color({h: 330, s: 100, v: 50}), - new Color() */ - ] + quickList: [] }, images: { clientPath: './components/jgraduate/images/', @@ -1467,10 +1477,85 @@ export class SeColorPicker extends HTMLElement { } }; const isLessThanIE7 = Number.parseFloat(navigator.appVersion.split('MSIE')[1]) < 7 && document.body.filters; - const settings = this.jPicker.default; - const win = settings.window; const {Color, ColorMethods} = this.jPicker; + this.jPicker.default.color.active = new Color({ahex: '#ffcc00ff'}); + this.jPicker.default.color.quickList = [ + new Color({h: 360, s: 33, v: 100}), + new Color({h: 360, s: 66, v: 100}), + new Color({h: 360, s: 100, v: 100}), + new Color({h: 360, s: 100, v: 75}), + new Color({h: 360, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 100}), + new Color({h: 30, s: 33, v: 100}), + new Color({h: 30, s: 66, v: 100}), + new Color({h: 30, s: 100, v: 100}), + new Color({h: 30, s: 100, v: 75}), + new Color({h: 30, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 90}), + new Color({h: 60, s: 33, v: 100}), + new Color({h: 60, s: 66, v: 100}), + new Color({h: 60, s: 100, v: 100}), + new Color({h: 60, s: 100, v: 75}), + new Color({h: 60, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 80}), + new Color({h: 90, s: 33, v: 100}), + new Color({h: 90, s: 66, v: 100}), + new Color({h: 90, s: 100, v: 100}), + new Color({h: 90, s: 100, v: 75}), + new Color({h: 90, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 70}), + new Color({h: 120, s: 33, v: 100}), + new Color({h: 120, s: 66, v: 100}), + new Color({h: 120, s: 100, v: 100}), + new Color({h: 120, s: 100, v: 75}), + new Color({h: 120, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 60}), + new Color({h: 150, s: 33, v: 100}), + new Color({h: 150, s: 66, v: 100}), + new Color({h: 150, s: 100, v: 100}), + new Color({h: 150, s: 100, v: 75}), + new Color({h: 150, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 50}), + new Color({h: 180, s: 33, v: 100}), + new Color({h: 180, s: 66, v: 100}), + new Color({h: 180, s: 100, v: 100}), + new Color({h: 180, s: 100, v: 75}), + new Color({h: 180, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 40}), + new Color({h: 210, s: 33, v: 100}), + new Color({h: 210, s: 66, v: 100}), + new Color({h: 210, s: 100, v: 100}), + new Color({h: 210, s: 100, v: 75}), + new Color({h: 210, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 30}), + new Color({h: 240, s: 33, v: 100}), + new Color({h: 240, s: 66, v: 100}), + new Color({h: 240, s: 100, v: 100}), + new Color({h: 240, s: 100, v: 75}), + new Color({h: 240, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 20}), + new Color({h: 270, s: 33, v: 100}), + new Color({h: 270, s: 66, v: 100}), + new Color({h: 270, s: 100, v: 100}), + new Color({h: 270, s: 100, v: 75}), + new Color({h: 270, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 10}), + new Color({h: 300, s: 33, v: 100}), + new Color({h: 300, s: 66, v: 100}), + new Color({h: 300, s: 100, v: 100}), + new Color({h: 300, s: 100, v: 75}), + new Color({h: 300, s: 100, v: 50}), + new Color({h: 180, s: 0, v: 0}), + new Color({h: 330, s: 33, v: 100}), + new Color({h: 330, s: 66, v: 100}), + new Color({h: 330, s: 100, v: 100}), + new Color({h: 330, s: 100, v: 75}), + new Color({h: 330, s: 100, v: 50}), + new Color() + ]; + const settings = this.jPicker.default; const {images, localization, color} = settings; // local copies for YUI compressor + const win = settings.window; const colorObj = { active: (typeof settings.color.active).toString().toLowerCase() === 'string' ? new Color({ahex: !win.alphaSupport && settings.color.active @@ -1503,21 +1588,176 @@ export class SeColorPicker extends HTMLElement { if (typeof cancelCallback !== 'function') { cancelCallback = null; } */ - /** - * @external Math - */ - /** - * @memberof external:Math - * @param {Float} value - * @param {Float} precision - * @returns {Float} - */ - function toFixedNumeric (value, precision) { - if (precision === undefined) precision = 0; - return Math.round(value * (10 ** precision)) / (10 ** precision); + * + * @param {"h"|"s"|"v"|"r"|"g"|"b"|"a"} colorMode + * @throws {Error} Invalid mode + * @returns {void} + */ + function setColorMode (colorMode) { + const {active} = color, // local copies for YUI compressor + // {clientPath} = images, + hex = active.val('hex'); + let rgbMap, rgbBar; + settings.color.mode = colorMode; + switch (colorMode) { + case 'h': + setTimeout(function () { + setBG.call(that, colorMapDiv, 'transparent'); + setImgLoc.call(that, colorMapL1, 0); + setAlpha.call(that, colorMapL1, 100); + setImgLoc.call(that, colorMapL2, 260); + setAlpha.call(that, colorMapL2, 100); + setBG.call(that, colorBarDiv, 'transparent'); + setImgLoc.call(that, colorBarL1, 0); + setAlpha.call(that, colorBarL1, 100); + setImgLoc.call(that, colorBarL2, 260); + setAlpha.call(that, colorBarL2, 100); + setImgLoc.call(that, colorBarL3, 260); + setAlpha.call(that, colorBarL3, 100); + setImgLoc.call(that, colorBarL4, 260); + setAlpha.call(that, colorBarL4, 100); + setImgLoc.call(that, colorBarL6, 260); + setAlpha.call(that, colorBarL6, 100); + }, 0); + colorMap.range('all', {minX: 0, maxX: 100, minY: 0, maxY: 100}); + colorBar.range('rangeY', {minY: 0, maxY: 360}); + if (isNullish(active.val('ahex'))) break; + colorMap.val('xy', {x: active.val('s'), y: 100 - active.val('v')}, colorMap); + colorBar.val('y', 360 - active.val('h'), colorBar); + break; + case 's': + setTimeout(function () { + setBG.call(that, colorMapDiv, 'transparent'); + setImgLoc.call(that, colorMapL1, -260); + setImgLoc.call(that, colorMapL2, -520); + setImgLoc.call(that, colorBarL1, -260); + setImgLoc.call(that, colorBarL2, -520); + setImgLoc.call(that, colorBarL6, 260); + setAlpha.call(that, colorBarL6, 100); + }, 0); + colorMap.range('all', {minX: 0, maxX: 360, minY: 0, maxY: 100}); + colorBar.range('rangeY', {minY: 0, maxY: 100}); + if (isNullish(active.val('ahex'))) break; + colorMap.val('xy', {x: active.val('h'), y: 100 - active.val('v')}, colorMap); + colorBar.val('y', 100 - active.val('s'), colorBar); + break; + case 'v': + setTimeout(function () { + setBG.call(that, colorMapDiv, '000000'); + setImgLoc.call(that, colorMapL1, -780); + setImgLoc.call(that, colorMapL2, 260); + setBG.call(that, colorBarDiv, hex); + setImgLoc.call(that, colorBarL1, -520); + setImgLoc.call(that, colorBarL2, 260); + setAlpha.call(that, colorBarL2, 100); + setImgLoc.call(that, colorBarL6, 260); + setAlpha.call(that, colorBarL6, 100); + }, 0); + colorMap.range('all', {minX: 0, maxX: 360, minY: 0, maxY: 100}); + colorBar.range('rangeY', {minY: 0, maxY: 100}); + if (isNullish(active.val('ahex'))) break; + colorMap.val('xy', {x: active.val('h'), y: 100 - active.val('s')}, colorMap); + colorBar.val('y', 100 - active.val('v'), colorBar); + break; + case 'r': + rgbMap = -1040; + rgbBar = -780; + colorMap.range('all', {minX: 0, maxX: 255, minY: 0, maxY: 255}); + colorBar.range('rangeY', {minY: 0, maxY: 255}); + if (isNullish(active.val('ahex'))) break; + colorMap.val('xy', {x: active.val('b'), y: 255 - active.val('g')}, colorMap); + colorBar.val('y', 255 - active.val('r'), colorBar); + break; + case 'g': + rgbMap = -1560; + rgbBar = -1820; + colorMap.range('all', {minX: 0, maxX: 255, minY: 0, maxY: 255}); + colorBar.range('rangeY', {minY: 0, maxY: 255}); + if (isNullish(active.val('ahex'))) break; + colorMap.val('xy', {x: active.val('b'), y: 255 - active.val('r')}, colorMap); + colorBar.val('y', 255 - active.val('g'), colorBar); + break; + case 'b': + rgbMap = -2080; + rgbBar = -2860; + colorMap.range('all', {minX: 0, maxX: 255, minY: 0, maxY: 255}); + colorBar.range('rangeY', {minY: 0, maxY: 255}); + if (isNullish(active.val('ahex'))) break; + colorMap.val('xy', {x: active.val('r'), y: 255 - active.val('g')}, colorMap); + colorBar.val('y', 255 - active.val('b'), colorBar); + break; + case 'a': + setTimeout(function () { + setBG.call(that, colorMapDiv, 'transparent'); + setImgLoc.call(that, colorMapL1, -260); + setImgLoc.call(that, colorMapL2, -520); + setImgLoc.call(that, colorBarL1, 260); + setImgLoc.call(that, colorBarL2, 260); + setAlpha.call(that, colorBarL2, 100); + setImgLoc.call(that, colorBarL6, 0); + setAlpha.call(that, colorBarL6, 100); + }, 0); + colorMap.range('all', {minX: 0, maxX: 360, minY: 0, maxY: 100}); + colorBar.range('rangeY', {minY: 0, maxY: 255}); + if (isNullish(active.val('ahex'))) break; + colorMap.val('xy', {x: active.val('h'), y: 100 - active.val('v')}, colorMap); + colorBar.val('y', 255 - active.val('a'), colorBar); + break; + default: + throw new Error('Invalid Mode'); + } + switch (colorMode) { + case 'h': + break; + case 's': + case 'v': + case 'a': + setTimeout(function () { + setAlpha.call(that, colorMapL1, 100); + setAlpha.call(that, colorBarL1, 100); + setImgLoc.call(that, colorBarL3, 260); + setAlpha.call(that, colorBarL3, 100); + setImgLoc.call(that, colorBarL4, 260); + setAlpha.call(that, colorBarL4, 100); + }, 0); + break; + case 'r': + case 'g': + case 'b': + setTimeout(function () { + setBG.call(that, colorMapDiv, 'transparent'); + setBG.call(that, colorBarDiv, 'transparent'); + setAlpha.call(that, colorBarL1, 100); + setAlpha.call(that, colorMapL1, 100); + setImgLoc.call(that, colorMapL1, rgbMap); + setImgLoc.call(that, colorMapL2, rgbMap - 260); + setImgLoc.call(that, colorBarL1, rgbBar - 780); + setImgLoc.call(that, colorBarL2, rgbBar - 520); + setImgLoc.call(that, colorBarL3, rgbBar); + setImgLoc.call(that, colorBarL4, rgbBar - 260); + setImgLoc.call(that, colorBarL6, 260); + setAlpha.call(that, colorBarL6, 100); + }, 0); + break; + } + if (isNullish(active.val('ahex'))) return; + activeColorChanged.call(that, active); + } + /** + * Update color when user changes text values. + * @param {external:jQuery} ui + * @param {?module:jPicker.Slider} context + * @returns {void} + */ + function activeColorChanged (ui, context) { + if (isNullish(context) || (context !== colorBar && context !== colorMap)) positionMapAndBarArrows.call(that, ui, context); + setTimeout(function () { + updatePreview.call(that, ui); + updateMapVisuals.call(that, ui); + updateBarVisuals.call(that, ui); + }, 0); } - /** * User has dragged the ColorMap pointer. * @param {external:jQuery} ui @@ -1551,6 +1791,150 @@ export class SeColorPicker extends HTMLElement { } } + /** + * @param {external:jQuery} el + * @param {string} [c="transparent"] + * @returns {void} + */ + function setBG (el, c) { + el.css({backgroundColor: (c && c.length === 6 && '#' + c) || 'transparent'}); + } + + /** + * @param {external:jQuery} img + * @param {string} src The image source + * @returns {void} + */ + function setImg (img, src) { + if (isLessThanIE7 && (src.includes('AlphaBar.png') || src.includes('Bars.png') || src.includes('Maps.png'))) { + img.attr('pngSrc', src); + img.css({backgroundImage: 'none', filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\', sizingMethod=\'scale\')'}); + } else img.css({backgroundImage: 'url(\'' + src + '\')'}); + } + /** + * @param {external:jQuery} img + * @param {Float} y + * @returns {void} + */ + function setImgLoc (img, y) { + img.css({top: y + 'px'}); + } + + /** + * @param {external:jQuery} obj + * @param {Float} alpha + * @returns {void} + */ + function setAlpha (obj, alpha) { + obj.style.visibility = (alpha > 0) ? 'visible' : 'hidden'; + if (alpha > 0 && alpha < 100) { + if (isLessThanIE7) { + const src = obj.getAttribute('pngSrc'); + if (!isNullish(src) && ( + src.includes('AlphaBar.png') || src.includes('Bars.png') || src.includes('Maps.png') + )) { + obj.css({ + filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + + '\', sizingMethod=\'scale\') progid:DXImageTransform.Microsoft.Alpha(opacity=' + alpha + ')' + }); + } else obj.style.opacity = toFixedNumeric(alpha / 100, 4); + } else obj.style.opacity = toFixedNumeric(alpha / 100, 4); + } else if (alpha === 0 || alpha === 100) { + if (isLessThanIE7) { + const src = obj.getAttribute('pngSrc'); + if (!isNullish(src) && ( + src.includes('AlphaBar.png') || src.includes('Bars.png') || src.includes('Maps.png') + )) { + obj.css({ + filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + + '\', sizingMethod=\'scale\')' + }); + } else obj.style.opacity = ''; + } else obj.style.opacity = ''; + } + } + + /** + * Revert color to original color when opened. + * @returns {void} + */ + function revertColor () { + colorObj.active.val('ahex', colorObj.current.val('ahex')); + } + + /** + * + * @returns {void} + */ + function currentClicked () { + revertColor.call(that); + } + + /** + * + * @returns {void} + */ + function cancelClicked () { + revertColor.call(that); + settings.window.expandable && hide.call(that); + typeof cancelCallback === 'function' && cancelCallback.call(that, colorObj.active, cancelButton); + } + /** + * + * @returns {void} + */ + function okClicked () { + commitColor.call(that); + settings.window.expandable && hide.call(that); + typeof commitCallback === 'function' && commitCallback.call(that, colorObj.active, okButton); + } + + /** + * @param {Event} e + * @returns {false} + */ + function quickPickClicked (e) { + e.preventDefault(); + e.stopPropagation(); + const title = e.target.getAttribute('title'); + colorObj.active.val('ahex', title || null, e.target); + return false; + } + + /** + * User has dragged the ColorBar slider. + * @param {external:jQuery} ui + * @param {?module:jPicker.Slider} context + * @returns {void} + */ + function colorBarValueChanged (ui, context) { + const {active} = color; + if (context !== colorBar && isNullish(active.val())) return; + switch (settings.color.mode) { + case 'h': + active.val('h', {h: 360 - ui.val('y')}, context); + break; + case 's': + active.val('s', {s: 100 - ui.val('y')}, context); + break; + case 'v': + active.val('v', {v: 100 - ui.val('y')}, context); + break; + case 'r': + active.val('r', {r: 255 - ui.val('y')}, context); + break; + case 'g': + active.val('g', {g: 255 - ui.val('y')}, context); + break; + case 'b': + active.val('b', {b: 255 - ui.val('y')}, context); + break; + case 'a': + active.val('a', 255 - ui.val('y'), context); + break; + } + } + /** * @param {external:jQuery} img * @param {string} src The image source @@ -1623,16 +2007,16 @@ export class SeColorPicker extends HTMLElement { ${localization.text.newColor}
-   -   +   +  
${localization.text.currentColor} - - - + + +
-
 
+
@@ -1762,23 +2146,30 @@ export class SeColorPicker extends HTMLElement { } } ); - const preview = tbody.querySelector('#Preview'); - // colorBar.bind(colorBarValueChanged); - /* colorPicker = new ColorValuePicker( + colorBar.bind(colorBarValueChanged); + colorPicker = new ColorValuePicker( tbody, - color.active, + colorObj.active, win.expandable && win.bindToInput ? win.input : null, win.alphaPrecision ); + const hex = !isNullish(all) ? all.hex : null, - preview = tbody.querySelector('#Preview'), // tbody.find('.Preview'), - button = tbody.querySelector('#Button'); // tbody.find('.Button'); - activePreview = preview.find('.Active:first').css({backgroundColor: (hex && '#' + hex) || 'transparent'}); - currentPreview = preview.find('.Current:first').css({backgroundColor: (hex && '#' + hex) || 'transparent'}).bind('click', currentClicked); - setAlpha.call(that, currentPreview, toFixedNumeric((color.current.val('a') * 100) / 255, 4)); - okButton = button.find('.Ok:first').bind('click', okClicked); - cancelButton = button.find('.Cancel:first').bind('click', cancelClicked); - grid = button.find('.Grid:first'); */ + preview = tbody.querySelector('#Preview'), // tbody.find('.Preview'), + button = tbody.querySelector('#Button'); // tbody.find('.Button'); + activePreview = preview.querySelector('#Active'); + activePreview.style.backgroundColor = (hex) ? '#' + hex : 'transparent'; + currentPreview = preview.querySelector('#Current'); + currentPreview.style.backgroundColor = (hex) ? '#' + hex : 'transparent'; + preview.querySelector('#Current').addEventListener('click', currentClicked); + + setAlpha.call(that, currentPreview, toFixedNumeric((colorObj.current.val('a') * 100) / 255, 4)); + //button.find('.Ok:first') + okButton = button.querySelector('#Ok-button'); + okButton.addEventListener('click', okClicked); + cancelButton = button.querySelector('#okCancel-button'); + cancelButton.addEventListener('click', cancelClicked); + grid = button.querySelector('#Grid'); setTimeout(function () { setImg.call(that, colorMapL1, images.clientPath + 'Maps.png'); setImg.call(that, colorMapL2, images.clientPath + 'Maps.png'); @@ -1793,7 +2184,34 @@ export class SeColorPicker extends HTMLElement { }, 0); // preview.find('div:first') // tbody.find('td.Radio input').bind('click', radioClicked); - + // initialize quick list + if (colorObj.quickList && colorObj.quickList.length > 0) { + let html = ''; + for (let i = 0; i < colorObj.quickList.length; i++) { + /* if default colors are hex strings, change them to color objects */ + if ((typeof (colorObj.quickList[i])).toString().toLowerCase() === 'string') { + colorObj.quickList[i] = new Color({hex: colorObj.quickList[i]}); + } + const alpha = colorObj.quickList[i].val('a'); + let ahex = colorObj.quickList[i].val('ahex'); + if (!win.alphaSupport && ahex) ahex = ahex.substring(0, 6) + 'ff'; + const quickHex = colorObj.quickList[i].val('hex'); + if (!ahex) ahex = '00000000'; + html += ' '; + } + setImg.call(that, grid, images.clientPath + 'bar-opacity.png'); + const div = document.createElement('div'); + div.innerHTML = html; + while (div.children.length > 0) { + grid.appendChild(div.children[0]); + } + const quickColorElements = grid.querySelectorAll('.QuickColor'); + for (const quickColorElement of quickColorElements) { + quickColorElement.addEventListener('click', quickPickClicked); + } + } + setColorMode.call(that, settings.color.mode); + // ---------------------------------------------------------------- this.applyStyle('.jGraduate_SliderBar', 'width', this.SLIDERW); From 599be1db35e982ee4785d8dd6f1a0457dda0c4ed Mon Sep 17 00:00:00 2001 From: Agriya Dev5 Date: Tue, 2 Feb 2021 21:04:25 +0530 Subject: [PATCH 04/18] #46 jquery plugin convert to pure javascript --- src/editor/components/PaintBox.js | 3 +- src/editor/components/index.js | 2 +- .../components/jgraduate/ColorValuePicker.js | 303 ++ .../components/jgraduate/jQuery.jGraduate.js | 2293 +++++---- .../components/jgraduate/jQuery.jPicker.js | 4231 +++++++---------- src/editor/components/jgraduate/paint.js | 78 + src/editor/components/seColorPicker.js | 54 +- src/editor/panels/BottomPanelHandlers.js | 7 +- src/svgcanvas/elem-get-set.js | 3 +- 9 files changed, 3330 insertions(+), 3644 deletions(-) create mode 100644 src/editor/components/jgraduate/ColorValuePicker.js create mode 100644 src/editor/components/jgraduate/paint.js diff --git a/src/editor/components/PaintBox.js b/src/editor/components/PaintBox.js index 41d524db..ae604c6d 100644 --- a/src/editor/components/PaintBox.js +++ b/src/editor/components/PaintBox.js @@ -1,4 +1,5 @@ /* globals $ */ +import {jGraduate} from './jgraduate/jQuery.jGraduate.js'; /** * */ @@ -77,7 +78,7 @@ class PaintBox { } else { opts.solidColor = 'none'; } - return new $.jGraduate.Paint(opts); + return new jGraduate.Paint(opts); } /** diff --git a/src/editor/components/index.js b/src/editor/components/index.js index 120e116b..f4d4bbc6 100644 --- a/src/editor/components/index.js +++ b/src/editor/components/index.js @@ -10,4 +10,4 @@ import './seMenuItem.js'; import './seList.js'; import './seListItem.js'; import './seColorPicker.js'; -import './seColorGraduatePicker.js'; +// import './seColorGraduatePicker.js'; diff --git a/src/editor/components/jgraduate/ColorValuePicker.js b/src/editor/components/jgraduate/ColorValuePicker.js new file mode 100644 index 00000000..85d17c4c --- /dev/null +++ b/src/editor/components/jgraduate/ColorValuePicker.js @@ -0,0 +1,303 @@ +/* globals $ */ +/* eslint-disable max-len */ +/* eslint-disable unicorn/prefer-math-trunc */ +/* eslint-disable no-bitwise */ +/** +* @external Math +*/ +/** +* @memberof external:Math +* @param {Float} value +* @param {Float} precision +* @returns {Float} +*/ +function toFixedNumeric (value, precision) { + if (precision === undefined) precision = 0; + return Math.round(value * (10 ** precision)) / (10 ** precision); +} +/** + * Whether a value is `null` or `undefined`. + * @param {any} val + * @returns {boolean} + */ +const isNullish = (val) => { + return val === null || val === undefined; +}; +/** + * Controls for all the input elements for the typing in color values. + */ +export default class ColorValuePicker { + /** + * @param {external:jQuery} picker + * @param {external:jQuery.jPicker.Color} color + * @param {external:jQuery.fn.$.fn.jPicker} bindedHex + * @param {Float} alphaPrecision + */ + constructor (picker, color, bindedHex, alphaPrecision) { + const that = this; // private properties and methods + const inputs = picker.find('td.Text input'); + // input box key down - use arrows to alter color + /** + * + * @param {Event} e + * @returns {Event|false|void} + */ + function keyDown (e) { + if (e.target.value === '' && e.target !== hex.get(0) && ((!isNullish(bindedHex) && e.target !== bindedHex.get(0)) || isNullish(bindedHex))) return undefined; + if (!validateKey(e)) return e; + switch (e.target) { + case red.get(0): + switch (e.keyCode) { + case 38: + red.val(setValueInRange.call(that, (red.val() << 0) + 1, 0, 255)); + color.val('r', red.val(), e.target); + return false; + case 40: + red.val(setValueInRange.call(that, (red.val() << 0) - 1, 0, 255)); + color.val('r', red.val(), e.target); + return false; + } + break; + case green.get(0): + switch (e.keyCode) { + case 38: + green.val(setValueInRange.call(that, (green.val() << 0) + 1, 0, 255)); + color.val('g', green.val(), e.target); + return false; + case 40: + green.val(setValueInRange.call(that, (green.val() << 0) - 1, 0, 255)); + color.val('g', green.val(), e.target); + return false; + } + break; + case blue.get(0): + switch (e.keyCode) { + case 38: + blue.val(setValueInRange.call(that, (blue.val() << 0) + 1, 0, 255)); + color.val('b', blue.val(), e.target); + return false; + case 40: + blue.val(setValueInRange.call(that, (blue.val() << 0) - 1, 0, 255)); + color.val('b', blue.val(), e.target); + return false; + } + break; + case alpha && alpha.get(0): + switch (e.keyCode) { + case 38: + alpha.val(setValueInRange.call(that, Number.parseFloat(alpha.val()) + 1, 0, 100)); + color.val('a', toFixedNumeric((alpha.val() * 255) / 100, alphaPrecision), e.target); + return false; + case 40: + alpha.val(setValueInRange.call(that, Number.parseFloat(alpha.val()) - 1, 0, 100)); + color.val('a', toFixedNumeric((alpha.val() * 255) / 100, alphaPrecision), e.target); + return false; + } + break; + case hue.get(0): + switch (e.keyCode) { + case 38: + hue.val(setValueInRange.call(that, (hue.val() << 0) + 1, 0, 360)); + color.val('h', hue.val(), e.target); + return false; + case 40: + hue.val(setValueInRange.call(that, (hue.val() << 0) - 1, 0, 360)); + color.val('h', hue.val(), e.target); + return false; + } + break; + case saturation.get(0): + switch (e.keyCode) { + case 38: + saturation.val(setValueInRange.call(that, (saturation.val() << 0) + 1, 0, 100)); + color.val('s', saturation.val(), e.target); + return false; + case 40: + saturation.val(setValueInRange.call(that, (saturation.val() << 0) - 1, 0, 100)); + color.val('s', saturation.val(), e.target); + return false; + } + break; + case value.get(0): + switch (e.keyCode) { + case 38: + value.val(setValueInRange.call(that, (value.val() << 0) + 1, 0, 100)); + color.val('v', value.val(), e.target); + return false; + case 40: + value.val(setValueInRange.call(that, (value.val() << 0) - 1, 0, 100)); + color.val('v', value.val(), e.target); + return false; + } + break; + } + return undefined; + } + // input box key up - validate value and set color + /** + * @param {Event} e + * @returns {Event|void} + * @todo Why is this returning an event? + */ + function keyUp (e) { + if (e.target.value === '' && e.target !== hex.get(0) && + ((!isNullish(bindedHex) && e.target !== bindedHex.get(0)) || + isNullish(bindedHex))) return undefined; + if (!validateKey(e)) return e; + switch (e.target) { + case red.get(0): + red.val(setValueInRange.call(that, red.val(), 0, 255)); + color.val('r', red.val(), e.target); + break; + case green.get(0): + green.val(setValueInRange.call(that, green.val(), 0, 255)); + color.val('g', green.val(), e.target); + break; + case blue.get(0): + blue.val(setValueInRange.call(that, blue.val(), 0, 255)); + color.val('b', blue.val(), e.target); + break; + case alpha && alpha.get(0): + alpha.val(setValueInRange.call(that, alpha.val(), 0, 100)); + color.val('a', toFixedNumeric((alpha.val() * 255) / 100, alphaPrecision), e.target); + break; + case hue.get(0): + hue.val(setValueInRange.call(that, hue.val(), 0, 360)); + color.val('h', hue.val(), e.target); + break; + case saturation.get(0): + saturation.val(setValueInRange.call(that, saturation.val(), 0, 100)); + color.val('s', saturation.val(), e.target); + break; + case value.get(0): + value.val(setValueInRange.call(that, value.val(), 0, 100)); + color.val('v', value.val(), e.target); + break; + case hex.get(0): + hex.val(hex.val().replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 6)); + bindedHex && bindedHex.val(hex.val()); + color.val('hex', hex.val() !== '' ? hex.val() : null, e.target); + break; + case bindedHex && bindedHex.get(0): + bindedHex.val(bindedHex.val().replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 6)); + hex.val(bindedHex.val()); + color.val('hex', bindedHex.val() !== '' ? bindedHex.val() : null, e.target); + break; + case ahex && ahex.get(0): + ahex.val(ahex.val().replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 2)); + color.val('a', !isNullish(ahex.val()) ? Number.parseInt(ahex.val(), 16) : null, e.target); + break; + } + return undefined; + } + // input box blur - reset to original if value empty + /** + * @param {Event} e + * @returns {void} + */ + function blur (e) { + if (!isNullish(color.val())) { + switch (e.target) { + case red.get(0): red.val(color.val('r')); break; + case green.get(0): green.val(color.val('g')); break; + case blue.get(0): blue.val(color.val('b')); break; + case alpha && alpha.get(0): alpha.val(toFixedNumeric((color.val('a') * 100) / 255, alphaPrecision)); break; + case hue.get(0): hue.val(color.val('h')); break; + case saturation.get(0): saturation.val(color.val('s')); break; + case value.get(0): value.val(color.val('v')); break; + case hex.get(0): + case bindedHex && bindedHex.get(0): + hex.val(color.val('hex')); + bindedHex && bindedHex.val(color.val('hex')); + break; + case ahex && ahex.get(0): ahex.val(color.val('ahex').substring(6)); break; + } + } + } + /** + * @param {Event} e + * @returns {boolean} + */ + function validateKey (e) { + switch (e.keyCode) { + case 9: + case 16: + case 29: + case 37: + case 39: + return false; + case 'c'.charCodeAt(): + case 'v'.charCodeAt(): + if (e.ctrlKey) return false; + } + return true; + } + + /** + * Constrain value within range. + * @param {Float|string} value + * @param {Float} min + * @param {Float} max + * @returns {Float|string} Returns a number or numeric string + */ + function setValueInRange (value, min, max) { + if (value === '' || isNaN(value)) return min; + if (value > max) return max; + if (value < min) return min; + return value; + } + /** + * @param {external:jQuery} ui + * @param {Element} context + * @returns {void} + */ + function colorChanged (ui, context) { + const all = ui.val('all'); + if (context !== red.get(0)) red.val(!isNullish(all) ? all.r : ''); + if (context !== green.get(0)) green.val(!isNullish(all) ? all.g : ''); + if (context !== blue.get(0)) blue.val(!isNullish(all) ? all.b : ''); + if (alpha && context !== alpha.get(0)) alpha.val(!isNullish(all) ? toFixedNumeric((all.a * 100) / 255, alphaPrecision) : ''); + if (context !== hue.get(0)) hue.val(!isNullish(all) ? all.h : ''); + if (context !== saturation.get(0)) saturation.val(!isNullish(all) ? all.s : ''); + if (context !== value.get(0)) value.val(!isNullish(all) ? all.v : ''); + if (context !== hex.get(0) && ((bindedHex && context !== bindedHex.get(0)) || !bindedHex)) hex.val(!isNullish(all) ? all.hex : ''); + if (bindedHex && context !== bindedHex.get(0) && context !== hex.get(0)) bindedHex.val(!isNullish(all) ? all.hex : ''); + if (ahex && context !== ahex.get(0)) ahex.val(!isNullish(all) ? all.ahex.substring(6) : ''); + } + /** + * Unbind all events and null objects. + * @returns {void} + */ + function destroy () { + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).unbind('keyup', keyUp).unbind('blur', blur); + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).unbind('keydown', keyDown); + color.unbind(colorChanged); + red = null; + green = null; + blue = null; + alpha = null; + hue = null; + saturation = null; + value = null; + hex = null; + ahex = null; + } + let + red = inputs.eq(3), + green = inputs.eq(4), + blue = inputs.eq(5), + alpha = inputs.length > 7 ? inputs.eq(6) : null, + hue = inputs.eq(0), + saturation = inputs.eq(1), + value = inputs.eq(2), + hex = inputs.eq(inputs.length > 7 ? 7 : 6), + ahex = inputs.length > 7 ? inputs.eq(8) : null; + $.extend(true, that, { + // public properties and methods + destroy + }); + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).bind('keyup', keyUp).bind('blur', blur); + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).bind('keydown', keyDown); + color.bind(colorChanged); + } +} diff --git a/src/editor/components/jgraduate/jQuery.jGraduate.js b/src/editor/components/jgraduate/jQuery.jGraduate.js index 79b9b204..e6e09c8e 100644 --- a/src/editor/components/jgraduate/jQuery.jGraduate.js +++ b/src/editor/components/jgraduate/jQuery.jGraduate.js @@ -1,4 +1,3 @@ -/* eslint-disable unicorn/prefer-dom-node-append */ /** * @file jGraduate 0.4 * @@ -17,6 +16,9 @@ * @example $.jGraduate.Paint({radialGradient: o, a: 7}); // creates a radial gradient paint with opacity=0.07 * @example $.jGraduate.Paint({hex: '#rrggbb', linearGradient: o}); // throws an exception? */ +/* globals $ */ +import Paint from './paint.js'; +import {jPickerDefaults, jPickerMethod} from './jQuery.jPicker.js'; /** * @todo JFH: This jQuery plugin was adapted to work within a Web Component. @@ -56,1271 +58,1184 @@ if (!window.console) { * @param {external:jQuery} $ The jQuery instance to wrap * @returns {external:jQuery} */ -export default function jQueryPluginJGraduate ($) { +// export default function jQueryPluginJGraduate ($) { +/* eslint-disable jsdoc/require-property */ +/** +* @namespace {PlainObject} jGraduate +* @memberof external:jQuery +*/ +export const jGraduate = /** @lends external:jQuery.jGraduate */ { + /* eslint-enable jsdoc/require-property */ /** - * @typedef {PlainObject} module:jGraduate.jGraduatePaintOptions - * @property {Float} [alpha] - * @property {module:jGraduate~Paint} [copy] Copy paint object - * @property {SVGLinearGradientElement} [linearGradient] - * @property {SVGRadialGradientElement} [radialGradient] - * @property {string} [solidColor] + * @class external:jQuery.jGraduate.Paint + * @see module:jGraduate~Paint */ + Paint +}; +// JSDoc doesn't show this as belonging to our `module:jGraduate.Options` type, +// so we use `@see` +/** +* @namespace {module:jGraduate.Options} jGraduateDefaults +* @memberof external:jQuery.fn +*/ +export const jGraduateDefaults = /** @lends external:jQuery.fn.jGraduateDefaults */ { /** - * @memberof module:jGraduate~ + * Creates an object with a 'none' color. + * @type {external:jQuery.jGraduate.Paint} + * @see module:jGraduate.Options */ - class Paint { - /** - * @param {module:jGraduate.jGraduatePaintOptions} [opt] - */ - constructor (opt) { - const options = opt || {}; - this.alpha = isNaN(options.alpha) ? 100 : options.alpha; - // copy paint object - if (options.copy) { - /** - * @name module:jGraduate~Paint#type - * @type {"none"|"solidColor"|"linearGradient"|"radialGradient"} - */ - this.type = options.copy.type; - /** - * Represents opacity (0-100). - * @name module:jGraduate~Paint#alpha - * @type {Float} - */ - this.alpha = options.copy.alpha; - /** - * Represents #RRGGBB hex of color. - * @name module:jGraduate~Paint#solidColor - * @type {string} - */ - this.solidColor = null; - /** - * @name module:jGraduate~Paint#linearGradient - * @type {SVGLinearGradientElement} - */ - this.linearGradient = null; - /** - * @name module:jGraduate~Paint#radialGradient - * @type {SVGRadialGradientElement} - */ - this.radialGradient = null; - - switch (this.type) { - case 'none': - break; - case 'solidColor': - this.solidColor = options.copy.solidColor; - break; - case 'linearGradient': - this.linearGradient = options.copy.linearGradient.cloneNode(true); - break; - case 'radialGradient': - this.radialGradient = options.copy.radialGradient.cloneNode(true); - break; - } - // create linear gradient paint - } else if (options.linearGradient) { - this.type = 'linearGradient'; - this.solidColor = null; - this.radialGradient = null; - this.linearGradient = options.linearGradient.cloneNode(true); - // create linear gradient paint - } else if (options.radialGradient) { - this.type = 'radialGradient'; - this.solidColor = null; - this.linearGradient = null; - this.radialGradient = options.radialGradient.cloneNode(true); - // create solid color paint - } else if (options.solidColor) { - this.type = 'solidColor'; - this.solidColor = options.solidColor; - // create empty paint - } else { - this.type = 'none'; - this.solidColor = null; - this.linearGradient = null; - this.radialGradient = null; - } - } - } - - /* eslint-disable jsdoc/require-property */ + paint: new jGraduate.Paint(), /** - * @namespace {PlainObject} jGraduate - * @memberof external:jQuery + * @namespace */ - $.jGraduate = /** @lends external:jQuery.jGraduate */ { - /* eslint-enable jsdoc/require-property */ - /** - * @class external:jQuery.jGraduate.Paint - * @see module:jGraduate~Paint - */ - Paint - }; - - // JSDoc doesn't show this as belonging to our `module:jGraduate.Options` type, - // so we use `@see` - /** - * @namespace {module:jGraduate.Options} jGraduateDefaults - * @memberof external:jQuery.fn - */ - $.fn.jGraduateDefaults = /** @lends external:jQuery.fn.jGraduateDefaults */ { - /** - * Creates an object with a 'none' color. - * @type {external:jQuery.jGraduate.Paint} - * @see module:jGraduate.Options - */ - paint: new $.jGraduate.Paint(), - /** - * @namespace - */ - window: { - /** - * @type {string} - * @see module:jGraduate.Options - */ - pickerTitle: 'Drag markers to pick a paint' - }, - /** - * @namespace - */ - images: { - /** - * @type {string} - * @see module:jGraduate.Options - */ - clientPath: 'images/' - }, + window: { /** * @type {string} * @see module:jGraduate.Options */ - newstop: 'inverse' // same, inverse, black, white - }; - - const isGecko = navigator.userAgent.includes('Gecko/'); - + pickerTitle: 'Drag markers to pick a paint' + }, /** - * @typedef {PlainObject} module:jGraduate.Attrs + * @namespace */ + images: { + /** + * @type {string} + * @see module:jGraduate.Options + */ + clientPath: 'images/' + }, /** - * @param {SVGElement} elem - * @param {module:jGraduate.Attrs} attrs - * @returns {void} + * @type {string} + * @see module:jGraduate.Options */ - function setAttrs (elem, attrs) { - if (isGecko) { - Object.entries(attrs).forEach(([aname, val]) => { + newstop: 'inverse' // same, inverse, black, white +}; + +const isGecko = navigator.userAgent.includes('Gecko/'); + +/** +* @typedef {PlainObject} module:jGraduate.Attrs +*/ +/** +* @param {SVGElement} elem +* @param {module:jGraduate.Attrs} attrs +* @returns {void} +*/ +function setAttrs (elem, attrs) { + if (isGecko) { + Object.entries(attrs).forEach(([aname, val]) => { + elem.setAttribute(aname, val); + }); + } else { + Object.entries(attrs).forEach(([aname, val]) => { + const prop = elem[aname]; + if (prop && prop.constructor === 'SVGLength') { + prop.baseVal.value = val; + } else { elem.setAttribute(aname, val); - }); - } else { - Object.entries(attrs).forEach(([aname, val]) => { - const prop = elem[aname]; - if (prop && prop.constructor === 'SVGLength') { - prop.baseVal.value = val; - } else { - elem.setAttribute(aname, val); - } - }); - } - } - - /** - * @param {string} name - * @param {module:jGraduate.Attrs} attrs - * @param {Element} newparent - * @returns {SVGElement} - */ - function mkElem (name, attrs, newparent) { - const elem = document.createElementNS(ns.svg, name); - setAttrs(elem, attrs); - if (newparent) { - newparent.append(elem); - } - return elem; - } - - /** - * @typedef {PlainObject} module:jGraduate.ColorOpac Object may have one or both values - * @property {string} [color] #Hex color - * @property {Float} [opac] 0-1 - */ - /** - * @typedef {PlainObject} module:jGraduate.Options - * @property {module:jGraduate~Paint} [paint] A Paint object object describing the paint to display initially; defaults to a new instance without options (defaults to opaque white) - * @property {external:Window} [window] - * @property {string} [window.pickerTitle="Drag markers to pick a paint"] - * @property {PlainObject} [images] - * @property {string} [images.clientPath="images/"] - * @property {"same"|"inverse"|"black"|"white"|module:jGraduate.ColorOpac} [newstop="inverse"] - */ - - /** - * @callback external:jQuery.fn.jGraduate.OkCallback - * @param {external:jQuery.jGraduate.Paint} paint - * @returns {void} - */ - /** - * @callback external:jQuery.fn.jGraduate.CancelCallback - * @returns {void} - */ - - /** - * @function external:jQuery.fn.jGraduate - * @param {module:jGraduate.Options} [options] - * @param {external:jQuery.fn.jGraduate.OkCallback} [okCallback] Called with a Paint object when Ok is pressed - * @param {external:jQuery.fn.jGraduate.CancelCallback} [cancelCallback] Called with no arguments when Cancel is pressed - * @returns {external:jQuery} - */ - $.fn.jGraduate = function (options, okCallback, cancelCallback) { - return this.each(function () { - const $this = $(this), - $settings = $.extend(true, {}, $.fn.jGraduateDefaults, options || {}), - id = $this.attr('id'), - idref = '#' + $this.attr('id') + ' '; - // JFH !!!!! - const $shadowRoot = this.parentNode; - const $wc = (selector) => $($shadowRoot.querySelectorAll(selector)); - - if (!idref) { - // eslint-disable-next-line no-alert - alert('Container element must have an id attribute to maintain unique id strings for sub-elements.'); - return; } + }); + } +} - const okClicked = function () { - switch ($this.paint.type) { - case 'radialGradient': - $this.paint.linearGradient = null; - break; - case 'linearGradient': - $this.paint.radialGradient = null; - break; - case 'solidColor': - $this.paint.radialGradient = $this.paint.linearGradient = null; - break; - } - typeof $this.okCallback === 'function' && $this.okCallback($this.paint); - $this.hide(); - }; - const cancelClicked = function () { - typeof $this.cancelCallback === 'function' && $this.cancelCallback(); - $this.hide(); - }; +/** +* @param {string} name +* @param {module:jGraduate.Attrs} attrs +* @param {Element} newparent +* @returns {SVGElement} +*/ +function mkElem (name, attrs, newparent) { + const elem = document.createElementNS(ns.svg, name); + setAttrs(elem, attrs); + if (newparent) { + newparent.append(elem); + } + return elem; +} - $.extend( - true, - $this, - // public properties, methods, and callbacks - { - // make a copy of the incoming paint - paint: new $.jGraduate.Paint({copy: $settings.paint}), - okCallback: typeof okCallback === 'function' ? okCallback : null, - cancelCallback: typeof cancelCallback === 'function' ? cancelCallback : null - } - ); +/** +* @typedef {PlainObject} module:jGraduate.ColorOpac Object may have one or both values +* @property {string} [color] #Hex color +* @property {Float} [opac] 0-1 +*/ +/** +* @typedef {PlainObject} module:jGraduate.Options +* @property {module:jGraduate~Paint} [paint] A Paint object object describing the paint to display initially; defaults to a new instance without options (defaults to opaque white) +* @property {external:Window} [window] +* @property {string} [window.pickerTitle="Drag markers to pick a paint"] +* @property {PlainObject} [images] +* @property {string} [images.clientPath="images/"] +* @property {"same"|"inverse"|"black"|"white"|module:jGraduate.ColorOpac} [newstop="inverse"] +*/ - let // pos = $this.position(), - color = null; - const $win = $(window); +/** +* @callback external:jQuery.fn.jGraduate.OkCallback +* @param {external:jQuery.jGraduate.Paint} paint +* @returns {void} +*/ +/** +* @callback external:jQuery.fn.jGraduate.CancelCallback +* @returns {void} +*/ - if ($this.paint.type === 'none') { - $this.paint = new $.jGraduate.Paint({solidColor: 'ffffff'}); - } +/** +* @function external:jQuery.fn.jGraduate +* @param {module:jGraduate.Options} [options] +* @param {external:jQuery.fn.jGraduate.OkCallback} [okCallback] Called with a Paint object when Ok is pressed +* @param {external:jQuery.fn.jGraduate.CancelCallback} [cancelCallback] Called with no arguments when Cancel is pressed +* @returns {external:jQuery} +*/ +export function jGraduateMethod (elem, options, okCallback, cancelCallback) { + return elem.each(function () { + const $this = $(this), + $settings = $.extend(true, {}, jGraduateDefaults, options || {}), + id = $this.attr('id'), + idref = '#' + $this.attr('id') + ' '; + // JFH !!!!! + const $shadowRoot = this.parentNode; + const $wc = (selector) => $($shadowRoot.querySelectorAll(selector)); - $this.addClass('jGraduate_Picker'); - /* eslint-disable max-len */ - $this.html( - '
    ' + - '
  • Solid Color
  • ' + - '
  • Linear Gradient
  • ' + - '
  • Radial Gradient
  • ' + - '
' + - '
' + - '
' + - '
' + - '
' - ); - /* JFH !!!! */ - const colPicker = $wc(idref + '> .jGraduate_colPick'); - const gradPicker = $wc(idref + '> .jGraduate_gradPick'); + if (!idref) { + // eslint-disable-next-line no-alert + alert('Container element must have an id attribute to maintain unique id strings for sub-elements.'); + return; + } - gradPicker.html( - '
' + - '

' + $settings.window.pickerTitle + '

' + - '
' + - '
' + - '
' + - '
' + - '
' + - '' + - '
' + - '' + - '' + - '' + - '' + - '
' + - '
' + - '
' + - '' + - '
' + - '' + - '' + - '' + - '' + - '
' + - '
' + - '
' + - '
' + - '
' + - '' + - '
' + - '' + - '' + - '' + - '' + - '
' + - '
' + - '
' + - '' + - '
' + - '
' + - '' + - '' + - '' + - '' + - '
' + - '
' + - '
' + - '
' + - '' + - '
' + - '' + - '
' + - '
' + - '
' + - '
' + - '' + - '
' + - '' + - '
' + - '' + - '
' + - '
' + - '' + - '
' + - '' + - '
' + - '' + - '
' + - '
' + - '' + - '
' + - '' + - '
' + - '' + - '
' + - '
' + - '' + - '
' + - '' + - '
' + - '' + - '
' + - '
' + - '
' + - '' + - '' + - '
' - ); - /* eslint-enable max-len */ - // -------------- - // Set up all the SVG elements (the gradient, stops and rectangle) - const MAX = 256, - MARGINX = 0, - MARGINY = 0, - // STOP_RADIUS = 15 / 2, - SIZEX = MAX - 2 * MARGINX, - SIZEY = MAX - 2 * MARGINY; - - const attrInput = {}; - - const SLIDERW = 145; - $wc('.jGraduate_SliderBar').width(SLIDERW); - // JFH !!!!!! - const container = $wc('#' + id + '_jGraduate_GradContainer')[0]; - - const svg = mkElem('svg', { - id: id + '_jgraduate_svg', - width: MAX, - height: MAX, - xmlns: ns.svg - }, container); - - // This wasn't working as designed - // let curType; - // curType = curType || $this.paint.type; - - // if we are sent a gradient, import it - let curType = $this.paint.type; - - let grad = $this.paint[curType]; - let curGradient = grad; - - const gradalpha = $this.paint.alpha; - - const isSolid = curType === 'solidColor'; - - // Make any missing gradients - switch (curType) { - case 'solidColor': - // fall through - case 'linearGradient': - if (!isSolid) { - curGradient.id = id + '_lg_jgraduate_grad'; - grad = curGradient = svg.appendChild(curGradient); - } - mkElem('radialGradient', { - id: id + '_rg_jgraduate_grad' - }, svg); - if (curType === 'linearGradient') { break; } - // fall through + const okClicked = function () { + switch ($this.paint.type) { case 'radialGradient': - if (!isSolid) { - curGradient.id = id + '_rg_jgraduate_grad'; - grad = curGradient = svg.appendChild(curGradient); - } - mkElem('linearGradient', { - id: id + '_lg_jgraduate_grad' - }, svg); + $this.paint.linearGradient = null; + break; + case 'linearGradient': + $this.paint.radialGradient = null; + break; + case 'solidColor': + $this.paint.radialGradient = $this.paint.linearGradient = null; + break; } + typeof $this.okCallback === 'function' && $this.okCallback($this.paint); + $this.hide(); + }; + const cancelClicked = function () { + typeof $this.cancelCallback === 'function' && $this.cancelCallback(); + $this.hide(); + }; - let stopGroup; // eslint-disable-line prefer-const - if (isSolid) { - // JFH !!!!!!!! - grad = curGradient = $wc('#' + id + '_lg_jgraduate_grad')[0]; - color = $this.paint[curType]; - mkStop(0, '#' + color, 1); - - const type = typeof $settings.newstop; - - if (type === 'string') { - switch ($settings.newstop) { - case 'same': - mkStop(1, '#' + color, 1); - break; - - case 'inverse': { - // Invert current color for second stop - let inverted = ''; - for (let i = 0; i < 6; i += 2) { - // const ch = color.substr(i, 2); - let inv = (255 - Number.parseInt(color.substr(i, 2), 16)).toString(16); - if (inv.length < 2) inv = 0 + inv; - inverted += inv; - } - mkStop(1, '#' + inverted, 1); - break; - } case 'white': - mkStop(1, '#ffffff', 1); - break; - - case 'black': - mkStop(1, '#000000', 1); - break; - } - } else if (type === 'object') { - const opac = ('opac' in $settings.newstop) ? $settings.newstop.opac : 1; - mkStop(1, ($settings.newstop.color || '#' + color), opac); - } + $.extend( + true, + $this, + // public properties, methods, and callbacks + { + // make a copy of the incoming paint + paint: new jGraduate.Paint({copy: $settings.paint}), + okCallback: typeof okCallback === 'function' ? okCallback : null, + cancelCallback: typeof cancelCallback === 'function' ? cancelCallback : null } + ); - const x1 = Number.parseFloat(grad.getAttribute('x1') || 0.0), - y1 = Number.parseFloat(grad.getAttribute('y1') || 0.0), - x2 = Number.parseFloat(grad.getAttribute('x2') || 1.0), - y2 = Number.parseFloat(grad.getAttribute('y2') || 0.0); + let // pos = $this.position(), + color = null; + const $win = $(window); - const cx = Number.parseFloat(grad.getAttribute('cx') || 0.5), - cy = Number.parseFloat(grad.getAttribute('cy') || 0.5), - fx = Number.parseFloat(grad.getAttribute('fx') || cx), - fy = Number.parseFloat(grad.getAttribute('fy') || cy); + if ($this.paint.type === 'none') { + $this.paint = new jGraduate.Paint({solidColor: 'ffffff'}); + } - const previewRect = mkElem('rect', { - id: id + '_jgraduate_rect', - x: MARGINX, - y: MARGINY, - width: SIZEX, - height: SIZEY, - fill: 'url(#' + id + '_jgraduate_grad)', - 'fill-opacity': gradalpha / 100 + $this.addClass('jGraduate_Picker'); + /* eslint-disable max-len */ + $this.html( + '
    ' + + '
  • Solid Color
  • ' + + '
  • Linear Gradient
  • ' + + '
  • Radial Gradient
  • ' + + '
' + + '
' + + '
' + + '
' + + '
' + ); + /* JFH !!!! */ + const colPicker = $wc(idref + '> .jGraduate_colPick'); + const gradPicker = $wc(idref + '> .jGraduate_gradPick'); + + gradPicker.html( + '
' + + '

' + $settings.window.pickerTitle + '

' + + '
' + + '
' + + '
' + + '
' + + '
' + + '' + + '
' + + '' + + '' + + '' + + '' + + '
' + + '
' + + '
' + + '' + + '
' + + '' + + '' + + '' + + '' + + '
' + + '
' + + '
' + + '
' + + '
' + + '' + + '
' + + '' + + '' + + '' + + '' + + '
' + + '
' + + '
' + + '' + + '
' + + '
' + + '' + + '' + + '' + + '' + + '
' + + '
' + + '
' + + '
' + + '' + + '
' + + '' + + '
' + + '
' + + '
' + + '
' + + '' + + '
' + + '' + + '
' + + '' + + '
' + + '
' + + '' + + '
' + + '' + + '
' + + '' + + '
' + + '
' + + '' + + '
' + + '' + + '
' + + '' + + '
' + + '
' + + '' + + '
' + + '' + + '
' + + '' + + '
' + + '
' + + '
' + + '' + + '' + + '
' + ); + /* eslint-enable max-len */ + // -------------- + // Set up all the SVG elements (the gradient, stops and rectangle) + const MAX = 256, + MARGINX = 0, + MARGINY = 0, + // STOP_RADIUS = 15 / 2, + SIZEX = MAX - 2 * MARGINX, + SIZEY = MAX - 2 * MARGINY; + + const attrInput = {}; + + const SLIDERW = 145; + $wc('.jGraduate_SliderBar').width(SLIDERW); + // JFH !!!!!! + const container = $wc('#' + id + '_jGraduate_GradContainer')[0]; + + const svg = mkElem('svg', { + id: id + '_jgraduate_svg', + width: MAX, + height: MAX, + xmlns: ns.svg + }, container); + + // This wasn't working as designed + // let curType; + // curType = curType || $this.paint.type; + + // if we are sent a gradient, import it + let curType = $this.paint.type; + + let grad = $this.paint[curType]; + let curGradient = grad; + + const gradalpha = $this.paint.alpha; + + const isSolid = curType === 'solidColor'; + + // Make any missing gradients + switch (curType) { + case 'solidColor': + // fall through + case 'linearGradient': + if (!isSolid) { + curGradient.id = id + '_lg_jgraduate_grad'; + grad = curGradient = svg.appendChild(curGradient); + } + mkElem('radialGradient', { + id: id + '_rg_jgraduate_grad' }, svg); + if (curType === 'linearGradient') { break; } + // fall through + case 'radialGradient': + if (!isSolid) { + curGradient.id = id + '_rg_jgraduate_grad'; + grad = curGradient = svg.appendChild(curGradient); + } + mkElem('linearGradient', { + id: id + '_lg_jgraduate_grad' + }, svg); + } - // stop visuals created here - const beginCoord = $('
').attr({ - class: 'grad_coord jGraduate_lg_field', - title: 'Begin Stop' - }).text(1).css({ - top: y1 * MAX, - left: x1 * MAX - }).data('coord', 'start').appendTo(container); + let stopGroup; // eslint-disable-line prefer-const + if (isSolid) { + // JFH !!!!!!!! + grad = curGradient = $wc('#' + id + '_lg_jgraduate_grad')[0]; + color = $this.paint[curType]; + mkStop(0, '#' + color, 1); - const endCoord = beginCoord.clone().text(2).css({ - top: y2 * MAX, - left: x2 * MAX - }).attr('title', 'End stop').data('coord', 'end').appendTo(container); + const type = typeof $settings.newstop; - const centerCoord = $('
').attr({ - class: 'grad_coord jGraduate_rg_field', - title: 'Center stop' - }).text('C').css({ - top: cy * MAX, - left: cx * MAX - }).data('coord', 'center').appendTo(container); + if (type === 'string') { + switch ($settings.newstop) { + case 'same': + mkStop(1, '#' + color, 1); + break; - const focusCoord = centerCoord.clone().text('F').css({ - top: fy * MAX, - left: fx * MAX, - display: 'none' - }).attr('title', 'Focus point').data('coord', 'focus').appendTo(container); - - focusCoord[0].id = id + '_jGraduate_focusCoord'; - - let showFocus; - $.each(['x1', 'y1', 'x2', 'y2', 'cx', 'cy', 'fx', 'fy'], function (i, attr) { - const isRadial = isNaN(attr[1]); - - let attrval = curGradient.getAttribute(attr); - if (!attrval) { - // Set defaults - if (isRadial) { - // For radial points - attrval = '0.5'; - } else { - // Only x2 is 1 - attrval = attr === 'x2' ? '1.0' : '0.0'; + case 'inverse': { + // Invert current color for second stop + let inverted = ''; + for (let i = 0; i < 6; i += 2) { + // const ch = color.substr(i, 2); + let inv = (255 - Number.parseInt(color.substr(i, 2), 16)).toString(16); + if (inv.length < 2) inv = 0 + inv; + inverted += inv; } + mkStop(1, '#' + inverted, 1); + break; + } case 'white': + mkStop(1, '#ffffff', 1); + break; + + case 'black': + mkStop(1, '#000000', 1); + break; } + } else if (type === 'object') { + const opac = ('opac' in $settings.newstop) ? $settings.newstop.opac : 1; + mkStop(1, ($settings.newstop.color || '#' + color), opac); + } + } - attrInput[attr] = $wc('#' + id + '_jGraduate_' + attr) - .val(attrval) - .change(function () { - // TODO: Support values < 0 and > 1 (zoomable preview?) - if (isNaN(Number.parseFloat(this.value)) || this.value < 0) { - this.value = 0.0; - } else if (this.value > 1) { - this.value = 1.0; - } + const x1 = Number.parseFloat(grad.getAttribute('x1') || 0.0), + y1 = Number.parseFloat(grad.getAttribute('y1') || 0.0), + x2 = Number.parseFloat(grad.getAttribute('x2') || 1.0), + y2 = Number.parseFloat(grad.getAttribute('y2') || 0.0); - if (!(attr[0] === 'f' && - !showFocus) && - ((isRadial && curType === 'radialGradient') || (!isRadial && curType === 'linearGradient'))) { - curGradient.setAttribute(attr, this.value); - } + const cx = Number.parseFloat(grad.getAttribute('cx') || 0.5), + cy = Number.parseFloat(grad.getAttribute('cy') || 0.5), + fx = Number.parseFloat(grad.getAttribute('fx') || cx), + fy = Number.parseFloat(grad.getAttribute('fy') || cy); - const $elem = isRadial - ? attr[0] === 'c' ? centerCoord : focusCoord - : attr[1] === '1' ? beginCoord : endCoord; + const previewRect = mkElem('rect', { + id: id + '_jgraduate_rect', + x: MARGINX, + y: MARGINY, + width: SIZEX, + height: SIZEY, + fill: 'url(#' + id + '_jgraduate_grad)', + 'fill-opacity': gradalpha / 100 + }, svg); - const cssName = attr.includes('x') ? 'left' : 'top'; + // stop visuals created here + const beginCoord = $('
').attr({ + class: 'grad_coord jGraduate_lg_field', + title: 'Begin Stop' + }).text(1).css({ + top: y1 * MAX, + left: x1 * MAX + }).data('coord', 'start').appendTo(container); - $elem.css(cssName, this.value * MAX); - }).change(); - }); + const endCoord = beginCoord.clone().text(2).css({ + top: y2 * MAX, + left: x2 * MAX + }).attr('title', 'End stop').data('coord', 'end').appendTo(container); - /** - * - * @param {Float} n - * @param {Float|string} colr - * @param {Float} opac - * @param {boolean} [sel] - * @param {SVGStopElement} [stopElem] - * @returns {SVGStopElement} - */ - function mkStop (n, colr, opac, sel, stopElem) { - const stop = stopElem || mkElem('stop', { - 'stop-color': colr, - 'stop-opacity': opac, - offset: n - }, curGradient); - if (stopElem) { - colr = stopElem.getAttribute('stop-color'); - opac = stopElem.getAttribute('stop-opacity'); - n = stopElem.getAttribute('offset'); + const centerCoord = $('
').attr({ + class: 'grad_coord jGraduate_rg_field', + title: 'Center stop' + }).text('C').css({ + top: cy * MAX, + left: cx * MAX + }).data('coord', 'center').appendTo(container); + + const focusCoord = centerCoord.clone().text('F').css({ + top: fy * MAX, + left: fx * MAX, + display: 'none' + }).attr('title', 'Focus point').data('coord', 'focus').appendTo(container); + + focusCoord[0].id = id + '_jGraduate_focusCoord'; + + let showFocus; + $.each(['x1', 'y1', 'x2', 'y2', 'cx', 'cy', 'fx', 'fy'], function (i, attr) { + const isRadial = isNaN(attr[1]); + + let attrval = curGradient.getAttribute(attr); + if (!attrval) { + // Set defaults + if (isRadial) { + // For radial points + attrval = '0.5'; } else { - curGradient.append(stop); + // Only x2 is 1 + attrval = attr === 'x2' ? '1.0' : '0.0'; } - if (opac === null) opac = 1; + } - const pickerD = 'M-6.2,0.9c3.6-4,6.7-4.3,6.7-12.4c-0.2,7.9,' + - '3.1,8.8,6.5,12.4c3.5,3.8,2.9,9.6,0,12.3c-3.1,2.8-10.4,' + - '2.7-13.2,0C-9.6,9.9-9.4,4.4-6.2,0.9z'; - - const pathbg = mkElem('path', { - d: pickerD, - fill: 'url(#jGraduate_trans)', - transform: 'translate(' + (10 + n * MAX) + ', 26)' - }, stopGroup); - - const path = mkElem('path', { - d: pickerD, - fill: colr, - 'fill-opacity': opac, - transform: 'translate(' + (10 + n * MAX) + ', 26)', - stroke: '#000', - 'stroke-width': 1.5 - }, stopGroup); - - $(path).mousedown(function (e) { - selectStop(this); - drag = curStop; - $win.mousemove(dragColor).mouseup(remDrags); - stopOffset = stopMakerDiv.offset(); - e.preventDefault(); - return false; - }).data('stop', stop).data('bg', pathbg).dblclick(function () { - $wc('div.jGraduate_LightBox').show(); - const colorhandle = this; - let stopOpacity = Number(stop.getAttribute('stop-opacity')) || 1; - let stopColor = stop.getAttribute('stop-color') || 1; - let thisAlpha = (Number.parseFloat(stopOpacity) * 255).toString(16); - while (thisAlpha.length < 2) { thisAlpha = '0' + thisAlpha; } - colr = stopColor.substr(1) + thisAlpha; - $wc('#' + id + '_jGraduate_stopPicker').css({left: 100, bottom: 15}).jPicker({ - window: {title: 'Pick the start color and opacity for the gradient'}, - images: {clientPath: $settings.images.clientPath}, - color: {active: colr, alphaSupport: true} - }, function (clr, arg2) { - stopColor = clr.val('hex') ? ('#' + clr.val('hex')) : 'none'; - stopOpacity = clr.val('a') !== null ? clr.val('a') / 256 : 1; - colorhandle.setAttribute('fill', stopColor); - colorhandle.setAttribute('fill-opacity', stopOpacity); - stop.setAttribute('stop-color', stopColor); - stop.setAttribute('stop-opacity', stopOpacity); - $wc('div.jGraduate_LightBox').hide(); - $wc('#' + id + '_jGraduate_stopPicker').hide(); - }, null, function () { - $wc('div.jGraduate_LightBox').hide(); - $wc('#' + id + '_jGraduate_stopPicker').hide(); - }); - }); - - $(curGradient).find('stop').each(function () { - const curS = $(this); - if (Number(this.getAttribute('offset')) > n) { - if (!colr) { - const newcolor = this.getAttribute('stop-color'); - const newopac = this.getAttribute('stop-opacity'); - stop.setAttribute('stop-color', newcolor); - path.setAttribute('fill', newcolor); - stop.setAttribute('stop-opacity', newopac === null ? 1 : newopac); - path.setAttribute('fill-opacity', newopac === null ? 1 : newopac); - } - curS.before(stop); - return false; + attrInput[attr] = $wc('#' + id + '_jGraduate_' + attr) + .val(attrval) + .change(function () { + // TODO: Support values < 0 and > 1 (zoomable preview?) + if (isNaN(Number.parseFloat(this.value)) || this.value < 0) { + this.value = 0.0; + } else if (this.value > 1) { + this.value = 1.0; } - return true; - }); - if (sel) selectStop(path); - return stop; - } - /** - * - * @returns {void} - */ - function remStop () { - delStop.setAttribute('display', 'none'); - const path = $wc(curStop); - const stop = path.data('stop'); - const bg = path.data('bg'); - $([curStop, stop, bg]).remove(); - } - - const stopMakerDiv = $wc('#' + id + '_jGraduate_StopSlider'); - - let stops, curStop, drag; - - const delStop = mkElem('path', { - d: 'm9.75,-6l-19.5,19.5m0,-19.5l19.5,19.5', - fill: 'none', - stroke: '#D00', - 'stroke-width': 5, - display: 'none' - }, undefined); // stopMakerSVG); - - /** - * @param {Element} item - * @returns {void} - */ - function selectStop (item) { - if (curStop) curStop.setAttribute('stroke', '#000'); - item.setAttribute('stroke', 'blue'); - curStop = item; - } - - let stopOffset; - - /** - * - * @returns {void} - */ - function remDrags () { - $win.unbind('mousemove', dragColor); - if (delStop.getAttribute('display') !== 'none') { - remStop(); - } - drag = null; - } - - let scaleX = 1, scaleY = 1, angle = 0; - - let cX = cx; - let cY = cy; - /** - * - * @returns {void} - */ - function xform () { - const rot = angle ? 'rotate(' + angle + ',' + cX + ',' + cY + ') ' : ''; - if (scaleX === 1 && scaleY === 1) { - curGradient.removeAttribute('gradientTransform'); - // $wc('#ang').addClass('dis'); - } else { - const x = -cX * (scaleX - 1); - const y = -cY * (scaleY - 1); - curGradient.setAttribute( - 'gradientTransform', - rot + 'translate(' + x + ',' + y + ') scale(' + - scaleX + ',' + scaleY + ')' - ); - // $wc('#ang').removeClass('dis'); - } - } - - /** - * @param {Event} evt - * @returns {void} - */ - function dragColor (evt) { - let x = evt.pageX - stopOffset.left; - const y = evt.pageY - stopOffset.top; - x = x < 10 - ? 10 - : x > MAX + 10 - ? MAX + 10 - : x; - - const xfStr = 'translate(' + x + ', 26)'; - if (y < -60 || y > 130) { - delStop.setAttribute('display', 'block'); - delStop.setAttribute('transform', xfStr); - } else { - delStop.setAttribute('display', 'none'); - } - - drag.setAttribute('transform', xfStr); - $.data(drag, 'bg').setAttribute('transform', xfStr); - const stop = $.data(drag, 'stop'); - const sX = (x - 10) / MAX; - - stop.setAttribute('offset', sX); - - let last = 0; - $(curGradient).find('stop').each(function (i) { - const cur = this.getAttribute('offset'); - const t = $(this); - if (cur < last) { - t.prev().before(t); - stops = $(curGradient).find('stop'); + if (!(attr[0] === 'f' && + !showFocus) && + ((isRadial && curType === 'radialGradient') || (!isRadial && curType === 'linearGradient'))) { + curGradient.setAttribute(attr, this.value); } - last = cur; - }); + + const $elem = isRadial + ? attr[0] === 'c' ? centerCoord : focusCoord + : attr[1] === '1' ? beginCoord : endCoord; + + const cssName = attr.includes('x') ? 'left' : 'top'; + + $elem.css(cssName, this.value * MAX); + }).change(); + }); + + /** + * + * @param {Float} n + * @param {Float|string} colr + * @param {Float} opac + * @param {boolean} [sel] + * @param {SVGStopElement} [stopElem] + * @returns {SVGStopElement} + */ + function mkStop (n, colr, opac, sel, stopElem) { + const stop = stopElem || mkElem('stop', { + 'stop-color': colr, + 'stop-opacity': opac, + offset: n + }, curGradient); + if (stopElem) { + colr = stopElem.getAttribute('stop-color'); + opac = stopElem.getAttribute('stop-opacity'); + n = stopElem.getAttribute('offset'); + } else { + curGradient.append(stop); } + if (opac === null) opac = 1; - const stopMakerSVG = mkElem('svg', { - width: '100%', - height: 45 - }, stopMakerDiv[0]); + const pickerD = 'M-6.2,0.9c3.6-4,6.7-4.3,6.7-12.4c-0.2,7.9,' + + '3.1,8.8,6.5,12.4c3.5,3.8,2.9,9.6,0,12.3c-3.1,2.8-10.4,' + + '2.7-13.2,0C-9.6,9.9-9.4,4.4-6.2,0.9z'; - const transPattern = mkElem('pattern', { - width: 16, - height: 16, - patternUnits: 'userSpaceOnUse', - id: 'jGraduate_trans' - }, stopMakerSVG); + const pathbg = mkElem('path', { + d: pickerD, + fill: 'url(#jGraduate_trans)', + transform: 'translate(' + (10 + n * MAX) + ', 26)' + }, stopGroup); - const transImg = mkElem('image', { - width: 16, - height: 16 - }, transPattern); + const path = mkElem('path', { + d: pickerD, + fill: colr, + 'fill-opacity': opac, + transform: 'translate(' + (10 + n * MAX) + ', 26)', + stroke: '#000', + 'stroke-width': 1.5 + }, stopGroup); - const bgImage = $settings.images.clientPath + 'map-opacity.png'; - - transImg.setAttributeNS(ns.xlink, 'xlink:href', bgImage); - - $(stopMakerSVG).click(function (evt) { + $(path).mousedown(function (e) { + selectStop(this); + drag = curStop; + $win.mousemove(dragColor).mouseup(remDrags); stopOffset = stopMakerDiv.offset(); - const {target} = evt; - if (target.tagName === 'path') return; - let x = evt.pageX - stopOffset.left - 8; - x = x < 10 ? 10 : x > MAX + 10 ? MAX + 10 : x; - mkStop(x / MAX, 0, 0, true); - evt.stopPropagation(); + e.preventDefault(); + return false; + }).data('stop', stop).data('bg', pathbg).dblclick(function () { + $wc('div.jGraduate_LightBox').show(); + const colorhandle = this; + let stopOpacity = Number(stop.getAttribute('stop-opacity')) || 1; + let stopColor = stop.getAttribute('stop-color') || 1; + let thisAlpha = (Number.parseFloat(stopOpacity) * 255).toString(16); + while (thisAlpha.length < 2) { thisAlpha = '0' + thisAlpha; } + colr = stopColor.substr(1) + thisAlpha; + jPickerMethod($wc('#' + id + '_jGraduate_stopPicker').css({left: 100, bottom: 15}), { + window: {title: 'Pick the start color and opacity for the gradient'}, + images: {clientPath: $settings.images.clientPath}, + color: {active: colr, alphaSupport: true} + }, function (clr, arg2) { + stopColor = clr.val('hex') ? ('#' + clr.val('hex')) : 'none'; + stopOpacity = clr.val('a') !== null ? clr.val('a') / 256 : 1; + colorhandle.setAttribute('fill', stopColor); + colorhandle.setAttribute('fill-opacity', stopOpacity); + stop.setAttribute('stop-color', stopColor); + stop.setAttribute('stop-opacity', stopOpacity); + $wc('div.jGraduate_LightBox').hide(); + $wc('#' + id + '_jGraduate_stopPicker').hide(); + }, null, function () { + $wc('div.jGraduate_LightBox').hide(); + $wc('#' + id + '_jGraduate_stopPicker').hide(); + }); }); - $(stopMakerSVG).mouseover(function () { - stopMakerSVG.append(delStop); - }); - - stopGroup = mkElem('g', {}, stopMakerSVG); - - mkElem('line', { - x1: 10, - y1: 15, - x2: MAX + 10, - y2: 15, - 'stroke-width': 2, - stroke: '#000' - }, stopMakerSVG); - - const spreadMethodOpt = gradPicker.find('.jGraduate_spreadMethod').change(function () { - curGradient.setAttribute('spreadMethod', $(this).val()); - }); - - // handle dragging the stop around the swatch - let draggingCoord = null; - - const onCoordDrag = function (evt) { - let x = evt.pageX - offset.left; - let y = evt.pageY - offset.top; - - // clamp stop to the swatch - x = x < 0 ? 0 : x > MAX ? MAX : x; - y = y < 0 ? 0 : y > MAX ? MAX : y; - - draggingCoord.css('left', x).css('top', y); - - // calculate stop offset - const fracx = x / SIZEX; - const fracy = y / SIZEY; - - const type = draggingCoord.data('coord'); - const grd = curGradient; - - switch (type) { - case 'start': - attrInput.x1.val(fracx); - attrInput.y1.val(fracy); - grd.setAttribute('x1', fracx); - grd.setAttribute('y1', fracy); - break; - case 'end': - attrInput.x2.val(fracx); - attrInput.y2.val(fracy); - grd.setAttribute('x2', fracx); - grd.setAttribute('y2', fracy); - break; - case 'center': - attrInput.cx.val(fracx); - attrInput.cy.val(fracy); - grd.setAttribute('cx', fracx); - grd.setAttribute('cy', fracy); - cX = fracx; - cY = fracy; - xform(); - break; - case 'focus': - attrInput.fx.val(fracx); - attrInput.fy.val(fracy); - grd.setAttribute('fx', fracx); - grd.setAttribute('fy', fracy); - xform(); + $(curGradient).find('stop').each(function () { + const curS = $(this); + if (Number(this.getAttribute('offset')) > n) { + if (!colr) { + const newcolor = this.getAttribute('stop-color'); + const newopac = this.getAttribute('stop-opacity'); + stop.setAttribute('stop-color', newcolor); + path.setAttribute('fill', newcolor); + stop.setAttribute('stop-opacity', newopac === null ? 1 : newopac); + path.setAttribute('fill-opacity', newopac === null ? 1 : newopac); + } + curS.before(stop); + return false; } + return true; + }); + if (sel) selectStop(path); + return stop; + } - evt.preventDefault(); - }; + /** + * + * @returns {void} + */ + function remStop () { + delStop.setAttribute('display', 'none'); + const path = $wc(curStop); + const stop = path.data('stop'); + const bg = path.data('bg'); + $([curStop, stop, bg]).remove(); + } - const onCoordUp = function () { - draggingCoord = null; - $win.unbind('mousemove', onCoordDrag).unbind('mouseup', onCoordUp); - }; + const stopMakerDiv = $wc('#' + id + '_jGraduate_StopSlider'); - // Linear gradient - // (function () { + let stops, curStop, drag; + const delStop = mkElem('path', { + d: 'm9.75,-6l-19.5,19.5m0,-19.5l19.5,19.5', + fill: 'none', + stroke: '#D00', + 'stroke-width': 5, + display: 'none' + }, undefined); // stopMakerSVG); + + /** + * @param {Element} item + * @returns {void} + */ + function selectStop (item) { + if (curStop) curStop.setAttribute('stroke', '#000'); + item.setAttribute('stroke', 'blue'); + curStop = item; + } + + let stopOffset; + + /** + * + * @returns {void} + */ + function remDrags () { + $win.unbind('mousemove', dragColor); + if (delStop.getAttribute('display') !== 'none') { + remStop(); + } + drag = null; + } + + let scaleX = 1, scaleY = 1, angle = 0; + + let cX = cx; + let cY = cy; + /** + * + * @returns {void} + */ + function xform () { + const rot = angle ? 'rotate(' + angle + ',' + cX + ',' + cY + ') ' : ''; + if (scaleX === 1 && scaleY === 1) { + curGradient.removeAttribute('gradientTransform'); + // $wc('#ang').addClass('dis'); + } else { + const x = -cX * (scaleX - 1); + const y = -cY * (scaleY - 1); + curGradient.setAttribute( + 'gradientTransform', + rot + 'translate(' + x + ',' + y + ') scale(' + + scaleX + ',' + scaleY + ')' + ); + // $wc('#ang').removeClass('dis'); + } + } + + /** + * @param {Event} evt + * @returns {void} + */ + function dragColor (evt) { + let x = evt.pageX - stopOffset.left; + const y = evt.pageY - stopOffset.top; + x = x < 10 + ? 10 + : x > MAX + 10 + ? MAX + 10 + : x; + + const xfStr = 'translate(' + x + ', 26)'; + if (y < -60 || y > 130) { + delStop.setAttribute('display', 'block'); + delStop.setAttribute('transform', xfStr); + } else { + delStop.setAttribute('display', 'none'); + } + + drag.setAttribute('transform', xfStr); + $.data(drag, 'bg').setAttribute('transform', xfStr); + const stop = $.data(drag, 'stop'); + const sX = (x - 10) / MAX; + + stop.setAttribute('offset', sX); + + let last = 0; + $(curGradient).find('stop').each(function (i) { + const cur = this.getAttribute('offset'); + const t = $(this); + if (cur < last) { + t.prev().before(t); + stops = $(curGradient).find('stop'); + } + last = cur; + }); + } + + const stopMakerSVG = mkElem('svg', { + width: '100%', + height: 45 + }, stopMakerDiv[0]); + + const transPattern = mkElem('pattern', { + width: 16, + height: 16, + patternUnits: 'userSpaceOnUse', + id: 'jGraduate_trans' + }, stopMakerSVG); + + const transImg = mkElem('image', { + width: 16, + height: 16 + }, transPattern); + + const bgImage = $settings.images.clientPath + 'map-opacity.png'; + + transImg.setAttributeNS(ns.xlink, 'xlink:href', bgImage); + + $(stopMakerSVG).click(function (evt) { + stopOffset = stopMakerDiv.offset(); + const {target} = evt; + if (target.tagName === 'path') return; + let x = evt.pageX - stopOffset.left - 8; + x = x < 10 ? 10 : x > MAX + 10 ? MAX + 10 : x; + mkStop(x / MAX, 0, 0, true); + evt.stopPropagation(); + }); + + $(stopMakerSVG).mouseover(function () { + stopMakerSVG.append(delStop); + }); + + stopGroup = mkElem('g', {}, stopMakerSVG); + + mkElem('line', { + x1: 10, + y1: 15, + x2: MAX + 10, + y2: 15, + 'stroke-width': 2, + stroke: '#000' + }, stopMakerSVG); + + const spreadMethodOpt = gradPicker.find('.jGraduate_spreadMethod').change(function () { + curGradient.setAttribute('spreadMethod', $(this).val()); + }); + + // handle dragging the stop around the swatch + let draggingCoord = null; + + const onCoordDrag = function (evt) { + let x = evt.pageX - offset.left; + let y = evt.pageY - offset.top; + + // clamp stop to the swatch + x = x < 0 ? 0 : x > MAX ? MAX : x; + y = y < 0 ? 0 : y > MAX ? MAX : y; + + draggingCoord.css('left', x).css('top', y); + + // calculate stop offset + const fracx = x / SIZEX; + const fracy = y / SIZEY; + + const type = draggingCoord.data('coord'); + const grd = curGradient; + + switch (type) { + case 'start': + attrInput.x1.val(fracx); + attrInput.y1.val(fracy); + grd.setAttribute('x1', fracx); + grd.setAttribute('y1', fracy); + break; + case 'end': + attrInput.x2.val(fracx); + attrInput.y2.val(fracy); + grd.setAttribute('x2', fracx); + grd.setAttribute('y2', fracy); + break; + case 'center': + attrInput.cx.val(fracx); + attrInput.cy.val(fracy); + grd.setAttribute('cx', fracx); + grd.setAttribute('cy', fracy); + cX = fracx; + cY = fracy; + xform(); + break; + case 'focus': + attrInput.fx.val(fracx); + attrInput.fy.val(fracy); + grd.setAttribute('fx', fracx); + grd.setAttribute('fy', fracy); + xform(); + } + + evt.preventDefault(); + }; + + const onCoordUp = function () { + draggingCoord = null; + $win.unbind('mousemove', onCoordDrag).unbind('mouseup', onCoordUp); + }; + + // Linear gradient + // (function () { + + stops = curGradient.getElementsByTagNameNS(ns.svg, 'stop'); + + let numstops = stops.length; + // if there are not at least two stops, then + if (numstops < 2) { + while (numstops < 2) { + curGradient.append(document.createElementNS(ns.svg, 'stop')); + ++numstops; + } stops = curGradient.getElementsByTagNameNS(ns.svg, 'stop'); + } - let numstops = stops.length; - // if there are not at least two stops, then - if (numstops < 2) { - while (numstops < 2) { - curGradient.append(document.createElementNS(ns.svg, 'stop')); - ++numstops; - } - stops = curGradient.getElementsByTagNameNS(ns.svg, 'stop'); - } + for (let i = 0; i < numstops; i++) { + mkStop(0, 0, 0, 0, stops[i]); + } - for (let i = 0; i < numstops; i++) { - mkStop(0, 0, 0, 0, stops[i]); - } + spreadMethodOpt.val(curGradient.getAttribute('spreadMethod') || 'pad'); - spreadMethodOpt.val(curGradient.getAttribute('spreadMethod') || 'pad'); + let offset; - let offset; + // No match, so show focus point + showFocus = false; - // No match, so show focus point - showFocus = false; + previewRect.setAttribute('fill-opacity', gradalpha / 100); - previewRect.setAttribute('fill-opacity', gradalpha / 100); + $wc('#' + id + ' div.grad_coord').mousedown(function (evt) { + evt.preventDefault(); + draggingCoord = $(this); + // const sPos = draggingCoord.offset(); + offset = draggingCoord.parent().offset(); + $win.mousemove(onCoordDrag).mouseup(onCoordUp); + }); - $wc('#' + id + ' div.grad_coord').mousedown(function (evt) { - evt.preventDefault(); - draggingCoord = $(this); - // const sPos = draggingCoord.offset(); - offset = draggingCoord.parent().offset(); - $win.mousemove(onCoordDrag).mouseup(onCoordUp); - }); + // bind GUI elements + $wc('#' + id + '_jGraduate_Ok').bind('click', function () { + $this.paint.type = curType; + $this.paint[curType] = curGradient.cloneNode(true); + $this.paint.solidColor = null; + okClicked(); + }); + $wc('#' + id + '_jGraduate_Cancel').bind('click', function (paint) { + cancelClicked(); + }); - // bind GUI elements - $wc('#' + id + '_jGraduate_Ok').bind('click', function () { - $this.paint.type = curType; - $this.paint[curType] = curGradient.cloneNode(true); - $this.paint.solidColor = null; - okClicked(); - }); - $wc('#' + id + '_jGraduate_Cancel').bind('click', function (paint) { - cancelClicked(); - }); - - if (curType === 'radialGradient') { - if (showFocus) { - focusCoord.show(); - } else { - focusCoord.hide(); - attrInput.fx.val(''); - attrInput.fy.val(''); - } - } - - $wc('#' + id + '_jGraduate_match_ctr')[0].checked = !showFocus; - - let lastfx, lastfy; - - $wc('#' + id + '_jGraduate_match_ctr').change(function () { - showFocus = !this.checked; - focusCoord.toggle(showFocus); + if (curType === 'radialGradient') { + if (showFocus) { + focusCoord.show(); + } else { + focusCoord.hide(); attrInput.fx.val(''); attrInput.fy.val(''); - const grd = curGradient; - if (!showFocus) { - lastfx = grd.getAttribute('fx'); - lastfy = grd.getAttribute('fy'); - grd.removeAttribute('fx'); - grd.removeAttribute('fy'); - } else { - const fX = lastfx || 0.5; - const fY = lastfy || 0.5; - grd.setAttribute('fx', fX); - grd.setAttribute('fy', fY); - attrInput.fx.val(fX); - attrInput.fy.val(fY); - } - }); - - stops = curGradient.getElementsByTagNameNS(ns.svg, 'stop'); - numstops = stops.length; - // if there are not at least two stops, then - if (numstops < 2) { - while (numstops < 2) { - curGradient.append(document.createElementNS(ns.svg, 'stop')); - ++numstops; - } - stops = curGradient.getElementsByTagNameNS(ns.svg, 'stop'); } + } - let slider; + $wc('#' + id + '_jGraduate_match_ctr')[0].checked = !showFocus; - const setSlider = function (e) { - const {offset: {left}} = slider; - const div = slider.parent; - let x = (e.pageX - left - Number.parseInt(div.css('border-left-width'))); - if (x > SLIDERW) x = SLIDERW; - if (x <= 0) x = 0; - const posx = x - 5; - x /= SLIDERW; + let lastfx, lastfy; - switch (slider.type) { - case 'radius': - x = (x * 2) ** 2.5; - if (x > 0.98 && x < 1.02) x = 1; - if (x <= 0.01) x = 0.01; - curGradient.setAttribute('r', x); - break; - case 'opacity': - $this.paint.alpha = Number.parseInt(x * 100); - previewRect.setAttribute('fill-opacity', x); - break; - case 'ellip': - scaleX = 1; - scaleY = 1; - if (x < 0.5) { - x /= 0.5; // 0.001 - scaleX = x <= 0 ? 0.01 : x; - } else if (x > 0.5) { - x /= 0.5; // 2 - x = 2 - x; - scaleY = x <= 0 ? 0.01 : x; - } - xform(); - x -= 1; - if (scaleY === x + 1) { - x = Math.abs(x); - } - break; - case 'angle': - x -= 0.5; - angle = x *= 180; - xform(); - x /= 100; - break; - } - slider.elem.css({'margin-left': posx}); - x = Math.round(x * 100); - slider.input.val(x); - }; - - let ellipVal = 0, angleVal = 0; - - if (curType === 'radialGradient') { - const tlist = curGradient.gradientTransform.baseVal; - if (tlist.numberOfItems === 2) { - const t = tlist.getItem(0); - const s = tlist.getItem(1); - if (t.type === 2 && s.type === 3) { - const m = s.matrix; - if (m.a !== 1) { - ellipVal = Math.round(-(1 - m.a) * 100); - } else if (m.d !== 1) { - ellipVal = Math.round((1 - m.d) * 100); - } - } - } else if (tlist.numberOfItems === 3) { - // Assume [R][T][S] - const r = tlist.getItem(0); - const t = tlist.getItem(1); - const s = tlist.getItem(2); - - if (r.type === 4 && - t.type === 2 && - s.type === 3 - ) { - angleVal = Math.round(r.angle); - const m = s.matrix; - if (m.a !== 1) { - ellipVal = Math.round(-(1 - m.a) * 100); - } else if (m.d !== 1) { - ellipVal = Math.round((1 - m.d) * 100); - } - } - } + $wc('#' + id + '_jGraduate_match_ctr').change(function () { + showFocus = !this.checked; + focusCoord.toggle(showFocus); + attrInput.fx.val(''); + attrInput.fy.val(''); + const grd = curGradient; + if (!showFocus) { + lastfx = grd.getAttribute('fx'); + lastfy = grd.getAttribute('fy'); + grd.removeAttribute('fx'); + grd.removeAttribute('fy'); + } else { + const fX = lastfx || 0.5; + const fY = lastfy || 0.5; + grd.setAttribute('fx', fX); + grd.setAttribute('fy', fY); + attrInput.fx.val(fX); + attrInput.fy.val(fY); } - - const sliders = { - radius: { - handle: '#' + id + '_jGraduate_RadiusArrows', - input: '#' + id + '_jGraduate_RadiusInput', - val: (curGradient.getAttribute('r') || 0.5) * 100 - }, - opacity: { - handle: '#' + id + '_jGraduate_OpacArrows', - input: '#' + id + '_jGraduate_OpacInput', - val: $this.paint.alpha || 100 - }, - ellip: { - handle: '#' + id + '_jGraduate_EllipArrows', - input: '#' + id + '_jGraduate_EllipInput', - val: ellipVal - }, - angle: { - handle: '#' + id + '_jGraduate_AngleArrows', - input: '#' + id + '_jGraduate_AngleInput', - val: angleVal - } - }; - - $.each(sliders, function (type, data) { - const handle = $(data.handle); - handle.mousedown(function (evt) { - const parent = handle.parent(); - slider = { - type, - elem: handle, - input: $(data.input), - parent, - offset: parent.offset() - }; - $win.mousemove(dragSlider).mouseup(stopSlider); - evt.preventDefault(); - }); - - $(data.input).val(data.val).change(function () { - const isRad = curType === 'radialGradient'; - let val = Number(this.value); - let xpos = 0; - switch (type) { - case 'radius': - if (isRad) curGradient.setAttribute('r', val / 100); - xpos = (((val / 100) ** (1 / 2.5)) / 2) * SLIDERW; - break; - - case 'opacity': - $this.paint.alpha = val; - previewRect.setAttribute('fill-opacity', val / 100); - xpos = val * (SLIDERW / 100); - break; - - case 'ellip': - scaleX = scaleY = 1; - if (val === 0) { - xpos = SLIDERW * 0.5; - break; - } - if (val > 99.5) val = 99.5; - if (val > 0) { - scaleY = 1 - (val / 100); - } else { - scaleX = -(val / 100) - 1; - } - - xpos = SLIDERW * ((val + 100) / 2) / 100; - if (isRad) xform(); - break; - - case 'angle': - angle = val; - xpos = angle / 180; - xpos += 0.5; - xpos *= SLIDERW; - if (isRad) xform(); - } - if (xpos > SLIDERW) { - xpos = SLIDERW; - } else if (xpos < 0) { - xpos = 0; - } - handle.css({'margin-left': xpos - 5}); - }).change(); - }); - - const dragSlider = function (evt) { - setSlider(evt); - evt.preventDefault(); - }; - - const stopSlider = function (evt) { - $win.unbind('mousemove', dragSlider).unbind('mouseup', stopSlider); - slider = null; - }; - - // -------------- - let thisAlpha = ($this.paint.alpha * 255 / 100).toString(16); - while (thisAlpha.length < 2) { thisAlpha = '0' + thisAlpha; } - thisAlpha = thisAlpha.split('.')[0]; - color = $this.paint.solidColor === 'none' ? '' : $this.paint.solidColor + thisAlpha; - - if (!isSolid) { - color = stops[0].getAttribute('stop-color'); - } - - // This should be done somewhere else, probably - $.extend($.fn.jPicker.defaults.window, { - alphaSupport: true, effects: {type: 'show', speed: 0} - }); - - colPicker.jPicker( - { - window: {title: $settings.window.pickerTitle}, - images: {clientPath: $settings.images.clientPath}, - color: {active: color, alphaSupport: true} - }, - function (clr) { - $this.paint.type = 'solidColor'; - $this.paint.alpha = clr.val('ahex') ? Math.round((clr.val('a') / 255) * 100) : 100; - $this.paint.solidColor = clr.val('hex') ? clr.val('hex') : 'none'; - $this.paint.radialGradient = null; - okClicked(); - }, - null, - function () { cancelClicked(); } - ); - // JFH !!!! - // const tabs = $wc(idref + ' .jGraduate_tabs li'); - const tabs = $wc('.jGraduate_tabs li'); - tabs.click(function () { - tabs.removeClass('jGraduate_tab_current'); - $(this).addClass('jGraduate_tab_current'); - $wc(idref + ' > div').hide(); - const type = $(this).attr('data-type'); - $wc(idref + ' .jGraduate_gradPick').show(); - if (type === 'rg' || type === 'lg') { - // Show/hide appropriate fields - $wc('.jGraduate_' + type + '_field').show(); - $wc('.jGraduate_' + (type === 'lg' ? 'rg' : 'lg') + '_field').hide(); - - $wc('#' + id + '_jgraduate_rect')[0] - .setAttribute('fill', 'url(#' + id + '_' + type + '_jgraduate_grad)'); - - // Copy stops - - curType = type === 'lg' ? 'linearGradient' : 'radialGradient'; - - $wc('#' + id + '_jGraduate_OpacInput').val($this.paint.alpha).change(); - - const newGrad = $wc('#' + id + '_' + type + '_jgraduate_grad')[0]; - - if (curGradient !== newGrad) { - const curStops = $(curGradient).find('stop'); - $(newGrad).empty().append(curStops); - curGradient = newGrad; - const sm = spreadMethodOpt.val(); - curGradient.setAttribute('spreadMethod', sm); - } - showFocus = type === 'rg' && curGradient.getAttribute('fx') !== null && !(cx === fx && cy === fy); - $wc('#' + id + '_jGraduate_focusCoord').toggle(showFocus); - if (showFocus) { - $wc('#' + id + '_jGraduate_match_ctr')[0].checked = false; - } - } else { - $wc(idref + ' .jGraduate_gradPick').hide(); - $wc(idref + ' .jGraduate_colPick').show(); - } - }); - $wc(idref + ' > div').hide(); - tabs.removeClass('jGraduate_tab_current'); - let tab; - switch ($this.paint.type) { - case 'linearGradient': - tab = $wc(idref + ' .jGraduate_tab_lingrad'); - break; - case 'radialGradient': - tab = $wc(idref + ' .jGraduate_tab_radgrad'); - break; - default: - tab = $wc(idref + ' .jGraduate_tab_color'); - break; - } - $this.show(); - - // jPicker will try to show after a 0ms timeout, so need to fire this after that - setTimeout(() => { - tab.addClass('jGraduate_tab_current').click(); - }, 10); }); - }; - return $; + + stops = curGradient.getElementsByTagNameNS(ns.svg, 'stop'); + numstops = stops.length; + // if there are not at least two stops, then + if (numstops < 2) { + while (numstops < 2) { + curGradient.append(document.createElementNS(ns.svg, 'stop')); + ++numstops; + } + stops = curGradient.getElementsByTagNameNS(ns.svg, 'stop'); + } + + let slider; + + const setSlider = function (e) { + const {offset: {left}} = slider; + const div = slider.parent; + let x = (e.pageX - left - Number.parseInt(div.css('border-left-width'))); + if (x > SLIDERW) x = SLIDERW; + if (x <= 0) x = 0; + const posx = x - 5; + x /= SLIDERW; + + switch (slider.type) { + case 'radius': + x = (x * 2) ** 2.5; + if (x > 0.98 && x < 1.02) x = 1; + if (x <= 0.01) x = 0.01; + curGradient.setAttribute('r', x); + break; + case 'opacity': + $this.paint.alpha = Number.parseInt(x * 100); + previewRect.setAttribute('fill-opacity', x); + break; + case 'ellip': + scaleX = 1; + scaleY = 1; + if (x < 0.5) { + x /= 0.5; // 0.001 + scaleX = x <= 0 ? 0.01 : x; + } else if (x > 0.5) { + x /= 0.5; // 2 + x = 2 - x; + scaleY = x <= 0 ? 0.01 : x; + } + xform(); + x -= 1; + if (scaleY === x + 1) { + x = Math.abs(x); + } + break; + case 'angle': + x -= 0.5; + angle = x *= 180; + xform(); + x /= 100; + break; + } + slider.elem.css({'margin-left': posx}); + x = Math.round(x * 100); + slider.input.val(x); + }; + + let ellipVal = 0, angleVal = 0; + + if (curType === 'radialGradient') { + const tlist = curGradient.gradientTransform.baseVal; + if (tlist.numberOfItems === 2) { + const t = tlist.getItem(0); + const s = tlist.getItem(1); + if (t.type === 2 && s.type === 3) { + const m = s.matrix; + if (m.a !== 1) { + ellipVal = Math.round(-(1 - m.a) * 100); + } else if (m.d !== 1) { + ellipVal = Math.round((1 - m.d) * 100); + } + } + } else if (tlist.numberOfItems === 3) { + // Assume [R][T][S] + const r = tlist.getItem(0); + const t = tlist.getItem(1); + const s = tlist.getItem(2); + + if (r.type === 4 && + t.type === 2 && + s.type === 3 + ) { + angleVal = Math.round(r.angle); + const m = s.matrix; + if (m.a !== 1) { + ellipVal = Math.round(-(1 - m.a) * 100); + } else if (m.d !== 1) { + ellipVal = Math.round((1 - m.d) * 100); + } + } + } + } + + const sliders = { + radius: { + handle: '#' + id + '_jGraduate_RadiusArrows', + input: '#' + id + '_jGraduate_RadiusInput', + val: (curGradient.getAttribute('r') || 0.5) * 100 + }, + opacity: { + handle: '#' + id + '_jGraduate_OpacArrows', + input: '#' + id + '_jGraduate_OpacInput', + val: $this.paint.alpha || 100 + }, + ellip: { + handle: '#' + id + '_jGraduate_EllipArrows', + input: '#' + id + '_jGraduate_EllipInput', + val: ellipVal + }, + angle: { + handle: '#' + id + '_jGraduate_AngleArrows', + input: '#' + id + '_jGraduate_AngleInput', + val: angleVal + } + }; + + $.each(sliders, function (type, data) { + const handle = $(data.handle); + handle.mousedown(function (evt) { + const parent = handle.parent(); + slider = { + type, + elem: handle, + input: $(data.input), + parent, + offset: parent.offset() + }; + $win.mousemove(dragSlider).mouseup(stopSlider); + evt.preventDefault(); + }); + + $(data.input).val(data.val).change(function () { + const isRad = curType === 'radialGradient'; + let val = Number(this.value); + let xpos = 0; + switch (type) { + case 'radius': + if (isRad) curGradient.setAttribute('r', val / 100); + xpos = (((val / 100) ** (1 / 2.5)) / 2) * SLIDERW; + break; + + case 'opacity': + $this.paint.alpha = val; + previewRect.setAttribute('fill-opacity', val / 100); + xpos = val * (SLIDERW / 100); + break; + + case 'ellip': + scaleX = scaleY = 1; + if (val === 0) { + xpos = SLIDERW * 0.5; + break; + } + if (val > 99.5) val = 99.5; + if (val > 0) { + scaleY = 1 - (val / 100); + } else { + scaleX = -(val / 100) - 1; + } + + xpos = SLIDERW * ((val + 100) / 2) / 100; + if (isRad) xform(); + break; + + case 'angle': + angle = val; + xpos = angle / 180; + xpos += 0.5; + xpos *= SLIDERW; + if (isRad) xform(); + } + if (xpos > SLIDERW) { + xpos = SLIDERW; + } else if (xpos < 0) { + xpos = 0; + } + handle.css({'margin-left': xpos - 5}); + }).change(); + }); + + const dragSlider = function (evt) { + setSlider(evt); + evt.preventDefault(); + }; + + const stopSlider = function (evt) { + $win.unbind('mousemove', dragSlider).unbind('mouseup', stopSlider); + slider = null; + }; + + // -------------- + let thisAlpha = ($this.paint.alpha * 255 / 100).toString(16); + while (thisAlpha.length < 2) { thisAlpha = '0' + thisAlpha; } + thisAlpha = thisAlpha.split('.')[0]; + color = $this.paint.solidColor === 'none' ? '' : $this.paint.solidColor + thisAlpha; + + if (!isSolid) { + color = stops[0].getAttribute('stop-color'); + } + + // This should be done somewhere else, probably + $.extend(jPickerDefaults.window, { + alphaSupport: true, effects: {type: 'show', speed: 0} + }); + + jPickerMethod(colPicker, + { + window: {title: $settings.window.pickerTitle}, + images: {clientPath: $settings.images.clientPath}, + color: {active: color, alphaSupport: true} + }, + function (clr) { + $this.paint.type = 'solidColor'; + $this.paint.alpha = clr.val('ahex') ? Math.round((clr.val('a') / 255) * 100) : 100; + $this.paint.solidColor = clr.val('hex') ? clr.val('hex') : 'none'; + $this.paint.radialGradient = null; + okClicked(); + }, + null, + function () { cancelClicked(); } + ); + // JFH !!!! + // const tabs = $wc(idref + ' .jGraduate_tabs li'); + const tabs = $wc('.jGraduate_tabs li'); + tabs.click(function () { + tabs.removeClass('jGraduate_tab_current'); + $(this).addClass('jGraduate_tab_current'); + $wc(idref + ' > div').hide(); + const type = $(this).attr('data-type'); + $wc(idref + ' .jGraduate_gradPick').show(); + if (type === 'rg' || type === 'lg') { + // Show/hide appropriate fields + $wc('.jGraduate_' + type + '_field').show(); + $wc('.jGraduate_' + (type === 'lg' ? 'rg' : 'lg') + '_field').hide(); + + $wc('#' + id + '_jgraduate_rect')[0] + .setAttribute('fill', 'url(#' + id + '_' + type + '_jgraduate_grad)'); + + // Copy stops + + curType = type === 'lg' ? 'linearGradient' : 'radialGradient'; + + $wc('#' + id + '_jGraduate_OpacInput').val($this.paint.alpha).change(); + + const newGrad = $wc('#' + id + '_' + type + '_jgraduate_grad')[0]; + + if (curGradient !== newGrad) { + const curStops = $(curGradient).find('stop'); + $(newGrad).empty().append(curStops); + curGradient = newGrad; + const sm = spreadMethodOpt.val(); + curGradient.setAttribute('spreadMethod', sm); + } + showFocus = type === 'rg' && curGradient.getAttribute('fx') !== null && !(cx === fx && cy === fy); + $wc('#' + id + '_jGraduate_focusCoord').toggle(showFocus); + if (showFocus) { + $wc('#' + id + '_jGraduate_match_ctr')[0].checked = false; + } + } else { + $wc(idref + ' .jGraduate_gradPick').hide(); + $wc(idref + ' .jGraduate_colPick').show(); + } + }); + $wc(idref + ' > div').hide(); + tabs.removeClass('jGraduate_tab_current'); + let tab; + switch ($this.paint.type) { + case 'linearGradient': + tab = $wc(idref + ' .jGraduate_tab_lingrad'); + break; + case 'radialGradient': + tab = $wc(idref + ' .jGraduate_tab_radgrad'); + break; + default: + tab = $wc(idref + ' .jGraduate_tab_color'); + break; + } + $this.show(); + + // jPicker will try to show after a 0ms timeout, so need to fire this after that + setTimeout(() => { + tab.addClass('jGraduate_tab_current').click(); + }, 10); + }); } + +// return $; +// } diff --git a/src/editor/components/jgraduate/jQuery.jPicker.js b/src/editor/components/jgraduate/jQuery.jPicker.js index 86232ac6..808abc65 100755 --- a/src/editor/components/jgraduate/jQuery.jPicker.js +++ b/src/editor/components/jgraduate/jQuery.jPicker.js @@ -1,4 +1,7 @@ -/* eslint-disable no-bitwise, max-len, unicorn/prefer-math-trunc, unicorn/prefer-ternary */ +/* eslint-disable jsdoc/require-file-overview */ +import ColorValuePicker from './ColorValuePicker.js'; +import Slider from './Slider.js'; +/* globals $ */ /** * @file jPicker (Adapted from version 1.1.6) * @@ -44,2469 +47,1857 @@ const isNullish = (val) => { * @param {external:jQuery} $ The jQuery object, {@link external:jQuery.fn.$.fn.jPicker}, {@link external:jQuery.fn.$.fn.jPicker.defaults}) * @returns {external:jQuery} */ -const jPicker = function ($) { - /** - * @typedef {PlainObject} module:jPicker.SliderOptions - * @property {external:jQuery|PlainObject} arrow - * @property {string} arrow.image Not in use? - * @property {Float} arrow.width - * @property {Float} arrow.height - * @property {PlainObject} map - * @property {Float} map.width - * @property {Float} map.height - */ +// const jPicker = function ($) { +/** +* @typedef {PlainObject} module:jPicker.SliderOptions +* @property {external:jQuery|PlainObject} arrow +* @property {string} arrow.image Not in use? +* @property {Float} arrow.width +* @property {Float} arrow.height +* @property {PlainObject} map +* @property {Float} map.width +* @property {Float} map.height +*/ +/** +* @typedef {PlainObject} module:jPicker.JPickerInit +* @property {Integer} [a] +* @property {Integer} [b] +* @property {Integer} [g] +* @property {Integer} [h] +* @property {Integer} [r] +* @property {Integer} [s] +* @property {Integer} [v] +* @property {string} [hex] +* @property {string} [ahex] +*/ + +/* eslint-disable jsdoc/require-property */ +/** +* @namespace {PlainObject} jPicker +* @memberof external:jQuery +*/ +export const jPicker = /** @lends external:jQuery.jPicker */ { + /* eslint-enable jsdoc/require-property */ /** - * Encapsulate slider functionality for the ColorMap and ColorBar - - * could be useful to use a jQuery UI draggable for this with certain extensions. - * @memberof module:jPicker + * Array holding references to each active instance of the jPicker control. + * @type {external:jQuery.fn.$.fn.jPicker[]} */ - class Slider { + List: [], + /** + * Color object - we will be able to assign by any color space type or + * retrieve any color space info. + * We want this public so we can optionally assign new color objects to + * initial values using inputs other than a string hex value (also supported) + * Note: JSDoc didn't document when expressed here as an ES6 Class. + * @namespace + * @class + * @memberof external:jQuery.jPicker + * @param {module:jPicker.JPickerInit} init + * @returns {external:jQuery.jPicker.Color} + */ + Color: function (init) { // eslint-disable-line object-shorthand + const that = this; /** - * @param {external:jQuery} bar - * @param {module:jPicker.SliderOptions} options + * + * @param {module:jPicker.Slider} context + * @returns {void} */ - constructor (bar, options) { - const that = this; - /** - * Fire events on the supplied `context` - * @param {module:jPicker.JPickerInit} context - * @returns {void} - */ - function fireChangeEvents (context) { - changeEvents.forEach((changeEvent) => { - changeEvent.call(that, that, context); - }); - } + function fireChangeEvents (context) { + for (let i = 0; i < changeEvents.length; i++) changeEvents[i].call(that, that, context); + } - /** - * Bind the mousedown to the bar not the arrow for quick snapping to the clicked location. - * @param {external:jQuery.Event} e - * @returns {void} - */ - function mouseDown (e) { - const off = bar.offset(); - offset = {l: off.left | 0, t: off.top | 0}; - clearTimeout(timeout); - // using setTimeout for visual updates - once the style is updated the browser will re-render internally allowing the next Javascript to run - timeout = setTimeout(function () { - setValuesFromMousePosition.call(that, e); - }, 0); - // Bind mousemove and mouseup event to the document so it responds when dragged of of the bar - we will unbind these when on mouseup to save processing - $(document).bind('mousemove', mouseMove).bind('mouseup', mouseUp); - e.preventDefault(); // don't try to select anything or drag the image to the desktop - } - /** - * Set the values as the mouse moves. - * @param {external:jQuery.Event} e - * @returns {false} - */ - function mouseMove (e) { - clearTimeout(timeout); - timeout = setTimeout(function () { - setValuesFromMousePosition.call(that, e); - }, 0); - e.stopPropagation(); - e.preventDefault(); - return false; - } - /** - * Unbind the document events - they aren't needed when not dragging. - * @param {external:jQuery.Event} e - * @returns {false} - */ - function mouseUp (e) { - $(document).unbind('mouseup', mouseUp).unbind('mousemove', mouseMove); - e.stopPropagation(); - e.preventDefault(); - return false; - } - - /** - * Calculate mouse position and set value within the current range. - * @param {Event} e - * @returns {void} - */ - function setValuesFromMousePosition (e) { - const barW = bar.w, // local copies for YUI compressor - barH = bar.h; - let locX = e.pageX - offset.l, - locY = e.pageY - offset.t; - // keep the arrow within the bounds of the bar - if (locX < 0) locX = 0; - else if (locX > barW) locX = barW; - if (locY < 0) locY = 0; - else if (locY > barH) locY = barH; - val.call(that, 'xy', { - x: ((locX / barW) * rangeX) + minX, - y: ((locY / barH) * rangeY) + minY - }); - } - /** - * - * @returns {void} - */ - function draw () { - const - barW = bar.w, - barH = bar.h, - arrowW = arrow.w, - arrowH = arrow.h; - let arrowOffsetX = 0, - arrowOffsetY = 0; - setTimeout(function () { - if (rangeX > 0) { // range is greater than zero - // constrain to bounds - if (x === maxX) arrowOffsetX = barW; - else arrowOffsetX = ((x / rangeX) * barW) | 0; - } - if (rangeY > 0) { // range is greater than zero - // constrain to bounds - if (y === maxY) arrowOffsetY = barH; - else arrowOffsetY = ((y / rangeY) * barH) | 0; - } - // if arrow width is greater than bar width, center arrow and prevent horizontal dragging - if (arrowW >= barW) arrowOffsetX = (barW >> 1) - (arrowW >> 1); // number >> 1 - superfast bitwise divide by two and truncate (move bits over one bit discarding lowest) - else arrowOffsetX -= arrowW >> 1; - // if arrow height is greater than bar height, center arrow and prevent vertical dragging - if (arrowH >= barH) arrowOffsetY = (barH >> 1) - (arrowH >> 1); - else arrowOffsetY -= arrowH >> 1; - // set the arrow position based on these offsets - arrow.css({left: arrowOffsetX + 'px', top: arrowOffsetY + 'px'}); - }); - } - - /** - * Get or set a value. - * @param {?("xy"|"x"|"y")} name - * @param {module:math.XYObject} value - * @param {module:jPicker.Slider} context - * @returns {module:math.XYObject|Float|void} - */ - function val (name, value, context) { - const set = value !== undefined; - if (!set) { - if (isNullish(name)) name = 'xy'; - switch (name.toLowerCase()) { - case 'x': return x; - case 'y': return y; - case 'xy': - default: return {x, y}; - } - } - if (!isNullish(context) && context === that) return undefined; - let changed = false; - - let newX, newY; - if (isNullish(name)) name = 'xy'; + /** + * @param {string|"ahex"|"hex"|"all"|""|null|void} name String composed of letters "r", "g", "b", "a", "h", "s", and/or "v" + * @param {module:jPicker.RGBA|module:jPicker.JPickerInit|string} [value] + * @param {external:jQuery.jPicker.Color} context + * @returns {module:jPicker.JPickerInit|string|null|void} + */ + function val (name, value, context) { + // Kind of ugly + const set = Boolean(value); + if (set && value.ahex === '') value.ahex = '00000000'; + if (!set) { + let ret; + if (isNullish(name) || name === '') name = 'all'; + if (isNullish(r)) return null; switch (name.toLowerCase()) { - case 'x': - newX = (value && ((value.x && value.x | 0) || value | 0)) || 0; - break; - case 'y': - newY = (value && ((value.y && value.y | 0) || value | 0)) || 0; - break; - case 'xy': - default: - newX = (value && value.x && value.x | 0) || 0; - newY = (value && value.y && value.y | 0) || 0; - break; + case 'ahex': return ColorMethods.rgbaToHex({r, g, b, a}); + case 'hex': return val('ahex').substring(0, 6); + case 'all': return { + r, g, b, a, h, s, v, + hex: val.call(that, 'hex'), + ahex: val.call(that, 'ahex') + }; + default: { + ret = {}; + const nameLength = name.length; + [...name].forEach((ch) => { + switch (ch) { + case 'r': + if (nameLength === 1) ret = r; + else ret.r = r; + break; + case 'g': + if (nameLength === 1) ret = g; + else ret.g = g; + break; + case 'b': + if (nameLength === 1) ret = b; + else ret.b = b; + break; + case 'a': + if (nameLength === 1) ret = a; + else ret.a = a; + break; + case 'h': + if (nameLength === 1) ret = h; + else ret.h = h; + break; + case 's': + if (nameLength === 1) ret = s; + else ret.s = s; + break; + case 'v': + if (nameLength === 1) ret = v; + else ret.v = v; + break; + } + }); } - if (!isNullish(newX)) { - if (newX < minX) newX = minX; - else if (newX > maxX) newX = maxX; - if (x !== newX) { - x = newX; - changed = true; - } } - if (!isNullish(newY)) { - if (newY < minY) newY = minY; - else if (newY > maxY) newY = maxY; - if (y !== newY) { - y = newY; - changed = true; - } + return typeof ret === 'object' && !Object.keys(ret).length + ? val.call(that, 'all') + : ret; + } + if (!isNullish(context) && context === that) return undefined; + if (isNullish(name)) name = ''; + + let changed = false; + if (isNullish(value)) { + if (!isNullish(r)) { + r = null; + changed = true; + } + if (!isNullish(g)) { + g = null; + changed = true; + } + if (!isNullish(b)) { + b = null; + changed = true; + } + if (!isNullish(a)) { + a = null; + changed = true; + } + if (!isNullish(h)) { + h = null; + changed = true; + } + if (!isNullish(s)) { + s = null; + changed = true; + } + if (!isNullish(v)) { + v = null; + changed = true; } changed && fireChangeEvents.call(that, context || that); return undefined; } - - /** - * @typedef {PlainObject} module:jPicker.MinMaxRangeX - * @property {Float} minX - * @property {Float} maxX - * @property {Float} rangeX - */ - /** - * @typedef {PlainObject} module:jPicker.MinMaxRangeY - * @property {Float} minY - * @property {Float} maxY - * @property {Float} rangeY - */ - /** - * @typedef {module:jPicker.MinMaxRangeY|module:jPicker.MinMaxRangeX} module:jPicker.MinMaxRangeXY - */ - - /** - * - * @param {"minx"|"maxx"|"rangex"|"miny"|"maxy"|"rangey"|"all"} name - * @param {module:jPicker.MinMaxRangeXY} value - * @returns {module:jPicker.MinMaxRangeXY|module:jPicker.MinMaxRangeX|module:jPicker.MinMaxRangeY|void} - */ - function range (name, value) { - const set = value !== undefined; - if (!set) { - if (isNullish(name)) name = 'all'; - switch (name.toLowerCase()) { - case 'minx': return minX; - case 'maxx': return maxX; - case 'rangex': return {minX, maxX, rangeX}; - case 'miny': return minY; - case 'maxy': return maxY; - case 'rangey': return {minY, maxY, rangeY}; - case 'all': - default: return {minX, maxX, rangeX, minY, maxY, rangeY}; - } - } - let // changed = false, - newMinX, - newMaxX, - newMinY, - newMaxY; - if (isNullish(name)) name = 'all'; - switch (name.toLowerCase()) { - case 'minx': - newMinX = (value && ((value.minX && value.minX | 0) || value | 0)) || 0; - break; - case 'maxx': - newMaxX = (value && ((value.maxX && value.maxX | 0) || value | 0)) || 0; - break; - case 'rangex': - newMinX = (value && value.minX && value.minX | 0) || 0; - newMaxX = (value && value.maxX && value.maxX | 0) || 0; - break; - case 'miny': - newMinY = (value && ((value.minY && value.minY | 0) || value | 0)) || 0; - break; - case 'maxy': - newMaxY = (value && ((value.maxY && value.maxY | 0) || value | 0)) || 0; - break; - case 'rangey': - newMinY = (value && value.minY && value.minY | 0) || 0; - newMaxY = (value && value.maxY && value.maxY | 0) || 0; - break; - case 'all': - default: - newMinX = (value && value.minX && value.minX | 0) || 0; - newMaxX = (value && value.maxX && value.maxX | 0) || 0; - newMinY = (value && value.minY && value.minY | 0) || 0; - newMaxY = (value && value.maxY && value.maxY | 0) || 0; - break; - } - - if (!isNullish(newMinX) && minX !== newMinX) { - minX = newMinX; - rangeX = maxX - minX; - } - if (!isNullish(newMaxX) && maxX !== newMaxX) { - maxX = newMaxX; - rangeX = maxX - minX; - } - if (!isNullish(newMinY) && minY !== newMinY) { - minY = newMinY; - rangeY = maxY - minY; - } - if (!isNullish(newMaxY) && maxY !== newMaxY) { - maxY = newMaxY; - rangeY = maxY - minY; - } - return undefined; - } - /** - * @param {GenericCallback} callback - * @returns {void} - */ - function bind (callback) { // eslint-disable-line promise/prefer-await-to-callbacks - if (typeof callback === 'function') changeEvents.push(callback); - } - /** - * @param {GenericCallback} callback - * @returns {void} - */ - function unbind (callback) { // eslint-disable-line promise/prefer-await-to-callbacks - if (typeof callback !== 'function') return; - let i; - while ((i = changeEvents.includes(callback))) changeEvents.splice(i, 1); - } - /** - * - * @returns {void} - */ - function destroy () { - // unbind all possible events and null objects - $(document).unbind('mouseup', mouseUp).unbind('mousemove', mouseMove); - bar.unbind('mousedown', mouseDown); - bar = null; - arrow = null; - changeEvents = null; - } - let offset, - timeout, - x = 0, - y = 0, - minX = 0, - maxX = 100, - rangeX = 100, - minY = 0, - maxY = 100, - rangeY = 100, - arrow = bar.find('img:first'), // the arrow image to drag - changeEvents = []; - - $.extend( - true, - // public properties, methods, and event bindings - these we need - // to access from other controls - that, - { - val, - range, - bind, - unbind, - destroy - } - ); - // initialize this control - arrow.src = options.arrow && options.arrow.image; - arrow.w = (options.arrow && options.arrow.width) || arrow.width(); - arrow.h = (options.arrow && options.arrow.height) || arrow.height(); - bar.w = (options.map && options.map.width) || bar.width(); - bar.h = (options.map && options.map.height) || bar.height(); - // bind mousedown event - bar.bind('mousedown', mouseDown); - bind.call(that, draw); - } - } - - /** - * Controls for all the input elements for the typing in color values. - */ - class ColorValuePicker { - /** - * @param {external:jQuery} picker - * @param {external:jQuery.jPicker.Color} color - * @param {external:jQuery.fn.$.fn.jPicker} bindedHex - * @param {Float} alphaPrecision - */ - constructor (picker, color, bindedHex, alphaPrecision) { - const that = this; // private properties and methods - const inputs = picker.find('td.Text input'); - // input box key down - use arrows to alter color - /** - * - * @param {Event} e - * @returns {Event|false|void} - */ - function keyDown (e) { - if (e.target.value === '' && e.target !== hex.get(0) && ((!isNullish(bindedHex) && e.target !== bindedHex.get(0)) || isNullish(bindedHex))) return undefined; - if (!validateKey(e)) return e; - switch (e.target) { - case red.get(0): - switch (e.keyCode) { - case 38: - red.val(setValueInRange.call(that, (red.val() << 0) + 1, 0, 255)); - color.val('r', red.val(), e.target); - return false; - case 40: - red.val(setValueInRange.call(that, (red.val() << 0) - 1, 0, 255)); - color.val('r', red.val(), e.target); - return false; - } - break; - case green.get(0): - switch (e.keyCode) { - case 38: - green.val(setValueInRange.call(that, (green.val() << 0) + 1, 0, 255)); - color.val('g', green.val(), e.target); - return false; - case 40: - green.val(setValueInRange.call(that, (green.val() << 0) - 1, 0, 255)); - color.val('g', green.val(), e.target); - return false; - } - break; - case blue.get(0): - switch (e.keyCode) { - case 38: - blue.val(setValueInRange.call(that, (blue.val() << 0) + 1, 0, 255)); - color.val('b', blue.val(), e.target); - return false; - case 40: - blue.val(setValueInRange.call(that, (blue.val() << 0) - 1, 0, 255)); - color.val('b', blue.val(), e.target); - return false; - } - break; - case alpha && alpha.get(0): - switch (e.keyCode) { - case 38: - alpha.val(setValueInRange.call(that, Number.parseFloat(alpha.val()) + 1, 0, 100)); - color.val('a', toFixedNumeric((alpha.val() * 255) / 100, alphaPrecision), e.target); - return false; - case 40: - alpha.val(setValueInRange.call(that, Number.parseFloat(alpha.val()) - 1, 0, 100)); - color.val('a', toFixedNumeric((alpha.val() * 255) / 100, alphaPrecision), e.target); - return false; - } - break; - case hue.get(0): - switch (e.keyCode) { - case 38: - hue.val(setValueInRange.call(that, (hue.val() << 0) + 1, 0, 360)); - color.val('h', hue.val(), e.target); - return false; - case 40: - hue.val(setValueInRange.call(that, (hue.val() << 0) - 1, 0, 360)); - color.val('h', hue.val(), e.target); - return false; - } - break; - case saturation.get(0): - switch (e.keyCode) { - case 38: - saturation.val(setValueInRange.call(that, (saturation.val() << 0) + 1, 0, 100)); - color.val('s', saturation.val(), e.target); - return false; - case 40: - saturation.val(setValueInRange.call(that, (saturation.val() << 0) - 1, 0, 100)); - color.val('s', saturation.val(), e.target); - return false; - } - break; - case value.get(0): - switch (e.keyCode) { - case 38: - value.val(setValueInRange.call(that, (value.val() << 0) + 1, 0, 100)); - color.val('v', value.val(), e.target); - return false; - case 40: - value.val(setValueInRange.call(that, (value.val() << 0) - 1, 0, 100)); - color.val('v', value.val(), e.target); - return false; - } - break; - } - return undefined; - } - // input box key up - validate value and set color - /** - * @param {Event} e - * @returns {Event|void} - * @todo Why is this returning an event? - */ - function keyUp (e) { - if (e.target.value === '' && e.target !== hex.get(0) && - ((!isNullish(bindedHex) && e.target !== bindedHex.get(0)) || - isNullish(bindedHex))) return undefined; - if (!validateKey(e)) return e; - switch (e.target) { - case red.get(0): - red.val(setValueInRange.call(that, red.val(), 0, 255)); - color.val('r', red.val(), e.target); - break; - case green.get(0): - green.val(setValueInRange.call(that, green.val(), 0, 255)); - color.val('g', green.val(), e.target); - break; - case blue.get(0): - blue.val(setValueInRange.call(that, blue.val(), 0, 255)); - color.val('b', blue.val(), e.target); - break; - case alpha && alpha.get(0): - alpha.val(setValueInRange.call(that, alpha.val(), 0, 100)); - color.val('a', toFixedNumeric((alpha.val() * 255) / 100, alphaPrecision), e.target); - break; - case hue.get(0): - hue.val(setValueInRange.call(that, hue.val(), 0, 360)); - color.val('h', hue.val(), e.target); - break; - case saturation.get(0): - saturation.val(setValueInRange.call(that, saturation.val(), 0, 100)); - color.val('s', saturation.val(), e.target); - break; - case value.get(0): - value.val(setValueInRange.call(that, value.val(), 0, 100)); - color.val('v', value.val(), e.target); - break; - case hex.get(0): - hex.val(hex.val().replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 6)); - bindedHex && bindedHex.val(hex.val()); - color.val('hex', hex.val() !== '' ? hex.val() : null, e.target); - break; - case bindedHex && bindedHex.get(0): - bindedHex.val(bindedHex.val().replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 6)); - hex.val(bindedHex.val()); - color.val('hex', bindedHex.val() !== '' ? bindedHex.val() : null, e.target); - break; - case ahex && ahex.get(0): - ahex.val(ahex.val().replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 2)); - color.val('a', !isNullish(ahex.val()) ? Number.parseInt(ahex.val(), 16) : null, e.target); - break; - } - return undefined; - } - // input box blur - reset to original if value empty - /** - * @param {Event} e - * @returns {void} - */ - function blur (e) { - if (!isNullish(color.val())) { - switch (e.target) { - case red.get(0): red.val(color.val('r')); break; - case green.get(0): green.val(color.val('g')); break; - case blue.get(0): blue.val(color.val('b')); break; - case alpha && alpha.get(0): alpha.val(toFixedNumeric((color.val('a') * 100) / 255, alphaPrecision)); break; - case hue.get(0): hue.val(color.val('h')); break; - case saturation.get(0): saturation.val(color.val('s')); break; - case value.get(0): value.val(color.val('v')); break; - case hex.get(0): - case bindedHex && bindedHex.get(0): - hex.val(color.val('hex')); - bindedHex && bindedHex.val(color.val('hex')); - break; - case ahex && ahex.get(0): ahex.val(color.val('ahex').substring(6)); break; - } - } - } - /** - * @param {Event} e - * @returns {boolean} - */ - function validateKey (e) { - switch (e.keyCode) { - case 9: - case 16: - case 29: - case 37: - case 39: - return false; - case 'c'.charCodeAt(): - case 'v'.charCodeAt(): - if (e.ctrlKey) return false; - } - return true; - } - - /** - * Constrain value within range. - * @param {Float|string} value - * @param {Float} min - * @param {Float} max - * @returns {Float|string} Returns a number or numeric string - */ - function setValueInRange (value, min, max) { - if (value === '' || isNaN(value)) return min; - if (value > max) return max; - if (value < min) return min; - return value; - } - /** - * @param {external:jQuery} ui - * @param {Element} context - * @returns {void} - */ - function colorChanged (ui, context) { - const all = ui.val('all'); - if (context !== red.get(0)) red.val(!isNullish(all) ? all.r : ''); - if (context !== green.get(0)) green.val(!isNullish(all) ? all.g : ''); - if (context !== blue.get(0)) blue.val(!isNullish(all) ? all.b : ''); - if (alpha && context !== alpha.get(0)) alpha.val(!isNullish(all) ? toFixedNumeric((all.a * 100) / 255, alphaPrecision) : ''); - if (context !== hue.get(0)) hue.val(!isNullish(all) ? all.h : ''); - if (context !== saturation.get(0)) saturation.val(!isNullish(all) ? all.s : ''); - if (context !== value.get(0)) value.val(!isNullish(all) ? all.v : ''); - if (context !== hex.get(0) && ((bindedHex && context !== bindedHex.get(0)) || !bindedHex)) hex.val(!isNullish(all) ? all.hex : ''); - if (bindedHex && context !== bindedHex.get(0) && context !== hex.get(0)) bindedHex.val(!isNullish(all) ? all.hex : ''); - if (ahex && context !== ahex.get(0)) ahex.val(!isNullish(all) ? all.ahex.substring(6) : ''); - } - /** - * Unbind all events and null objects. - * @returns {void} - */ - function destroy () { - red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).unbind('keyup', keyUp).unbind('blur', blur); - red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).unbind('keydown', keyDown); - color.unbind(colorChanged); - red = null; - green = null; - blue = null; - alpha = null; - hue = null; - saturation = null; - value = null; - hex = null; - ahex = null; - } - let - red = inputs.eq(3), - green = inputs.eq(4), - blue = inputs.eq(5), - alpha = inputs.length > 7 ? inputs.eq(6) : null, - hue = inputs.eq(0), - saturation = inputs.eq(1), - value = inputs.eq(2), - hex = inputs.eq(inputs.length > 7 ? 7 : 6), - ahex = inputs.length > 7 ? inputs.eq(8) : null; - $.extend(true, that, { - // public properties and methods - destroy - }); - red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).bind('keyup', keyUp).bind('blur', blur); - red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).bind('keydown', keyDown); - color.bind(colorChanged); - } - } - - /** - * @typedef {PlainObject} module:jPicker.JPickerInit - * @property {Integer} [a] - * @property {Integer} [b] - * @property {Integer} [g] - * @property {Integer} [h] - * @property {Integer} [r] - * @property {Integer} [s] - * @property {Integer} [v] - * @property {string} [hex] - * @property {string} [ahex] - */ - - /* eslint-disable jsdoc/require-property */ - /** - * @namespace {PlainObject} jPicker - * @memberof external:jQuery - */ - $.jPicker = /** @lends external:jQuery.jPicker */ { - /* eslint-enable jsdoc/require-property */ - /** - * Array holding references to each active instance of the jPicker control. - * @type {external:jQuery.fn.$.fn.jPicker[]} - */ - List: [], - /** - * Color object - we will be able to assign by any color space type or - * retrieve any color space info. - * We want this public so we can optionally assign new color objects to - * initial values using inputs other than a string hex value (also supported) - * Note: JSDoc didn't document when expressed here as an ES6 Class. - * @namespace - * @class - * @memberof external:jQuery.jPicker - * @param {module:jPicker.JPickerInit} init - * @returns {external:jQuery.jPicker.Color} - */ - Color: function (init) { // eslint-disable-line object-shorthand - const that = this; - /** - * - * @param {module:jPicker.Slider} context - * @returns {void} - */ - function fireChangeEvents (context) { - for (let i = 0; i < changeEvents.length; i++) changeEvents[i].call(that, that, context); - } - - /** - * @param {string|"ahex"|"hex"|"all"|""|null|void} name String composed of letters "r", "g", "b", "a", "h", "s", and/or "v" - * @param {module:jPicker.RGBA|module:jPicker.JPickerInit|string} [value] - * @param {external:jQuery.jPicker.Color} context - * @returns {module:jPicker.JPickerInit|string|null|void} - */ - function val (name, value, context) { - // Kind of ugly - const set = Boolean(value); - if (set && value.ahex === '') value.ahex = '00000000'; - if (!set) { - let ret; - if (isNullish(name) || name === '') name = 'all'; - if (isNullish(r)) return null; - switch (name.toLowerCase()) { - case 'ahex': return ColorMethods.rgbaToHex({r, g, b, a}); - case 'hex': return val('ahex').substring(0, 6); - case 'all': return { - r, g, b, a, h, s, v, - hex: val.call(that, 'hex'), - ahex: val.call(that, 'ahex') - }; - default: { - ret = {}; - const nameLength = name.length; - [...name].forEach((ch) => { - switch (ch) { - case 'r': - if (nameLength === 1) ret = r; - else ret.r = r; - break; - case 'g': - if (nameLength === 1) ret = g; - else ret.g = g; - break; - case 'b': - if (nameLength === 1) ret = b; - else ret.b = b; - break; - case 'a': - if (nameLength === 1) ret = a; - else ret.a = a; - break; - case 'h': - if (nameLength === 1) ret = h; - else ret.h = h; - break; - case 's': - if (nameLength === 1) ret = s; - else ret.s = s; - break; - case 'v': - if (nameLength === 1) ret = v; - else ret.v = v; - break; - } - }); - } - } - return typeof ret === 'object' && !Object.keys(ret).length - ? val.call(that, 'all') - : ret; - } - if (!isNullish(context) && context === that) return undefined; - if (isNullish(name)) name = ''; - - let changed = false; - if (isNullish(value)) { - if (!isNullish(r)) { - r = null; - changed = true; - } - if (!isNullish(g)) { - g = null; - changed = true; - } - if (!isNullish(b)) { - b = null; - changed = true; - } - if (!isNullish(a)) { - a = null; - changed = true; - } - if (!isNullish(h)) { - h = null; - changed = true; - } - if (!isNullish(s)) { - s = null; - changed = true; - } - if (!isNullish(v)) { - v = null; - changed = true; - } - changed && fireChangeEvents.call(that, context || that); + switch (name.toLowerCase()) { + case 'ahex': + case 'hex': { + const ret = ColorMethods.hexToRgba((value && (value.ahex || value.hex)) || value || 'none'); + val.call(that, 'rgba', { + r: ret.r, + g: ret.g, + b: ret.b, + a: name === 'ahex' + ? ret.a + : !isNullish(a) + ? a + : 255 + }, context); + break; + } default: { + if (value && (!isNullish(value.ahex) || !isNullish(value.hex))) { + val.call(that, 'ahex', value.ahex || value.hex || '00000000', context); return undefined; } - switch (name.toLowerCase()) { - case 'ahex': - case 'hex': { - const ret = ColorMethods.hexToRgba((value && (value.ahex || value.hex)) || value || 'none'); - val.call(that, 'rgba', { - r: ret.r, - g: ret.g, - b: ret.b, - a: name === 'ahex' - ? ret.a - : !isNullish(a) - ? a - : 255 - }, context); - break; - } default: { - if (value && (!isNullish(value.ahex) || !isNullish(value.hex))) { - val.call(that, 'ahex', value.ahex || value.hex || '00000000', context); - return undefined; - } - const newV = {}; - let rgb = false, hsv = false; - if (value.r !== undefined && !name.includes('r')) name += 'r'; - if (value.g !== undefined && !name.includes('g')) name += 'g'; - if (value.b !== undefined && !name.includes('b')) name += 'b'; - if (value.a !== undefined && !name.includes('a')) name += 'a'; - if (value.h !== undefined && !name.includes('h')) name += 'h'; - if (value.s !== undefined && !name.includes('s')) name += 's'; - if (value.v !== undefined && !name.includes('v')) name += 'v'; - [...name].forEach((ch) => { - switch (ch) { - case 'r': - if (hsv) return; - rgb = true; - newV.r = (value.r && value.r | 0) || (value | 0) || 0; - if (newV.r < 0) newV.r = 0; - else if (newV.r > 255) newV.r = 255; - if (r !== newV.r) { - ({r} = newV); - changed = true; - } - break; - case 'g': - if (hsv) return; - rgb = true; - newV.g = (value && value.g && value.g | 0) || (value && value | 0) || 0; - if (newV.g < 0) newV.g = 0; - else if (newV.g > 255) newV.g = 255; - if (g !== newV.g) { - ({g} = newV); - changed = true; - } - break; - case 'b': - if (hsv) return; - rgb = true; - newV.b = (value && value.b && value.b | 0) || (value && value | 0) || 0; - if (newV.b < 0) newV.b = 0; - else if (newV.b > 255) newV.b = 255; - if (b !== newV.b) { - ({b} = newV); - changed = true; - } - break; - case 'a': - newV.a = value && !isNullish(value.a) ? value.a | 0 : value | 0; - if (newV.a < 0) newV.a = 0; - else if (newV.a > 255) newV.a = 255; - if (a !== newV.a) { - ({a} = newV); - changed = true; - } - break; - case 'h': - if (rgb) return; - hsv = true; - newV.h = (value && value.h && value.h | 0) || (value && value | 0) || 0; - if (newV.h < 0) newV.h = 0; - else if (newV.h > 360) newV.h = 360; - if (h !== newV.h) { - ({h} = newV); - changed = true; - } - break; - case 's': - if (rgb) return; - hsv = true; - newV.s = !isNullish(value.s) ? value.s | 0 : value | 0; - if (newV.s < 0) newV.s = 0; - else if (newV.s > 100) newV.s = 100; - if (s !== newV.s) { - ({s} = newV); - changed = true; - } - break; - case 'v': - if (rgb) return; - hsv = true; - newV.v = !isNullish(value.v) ? value.v | 0 : value | 0; - if (newV.v < 0) newV.v = 0; - else if (newV.v > 100) newV.v = 100; - if (v !== newV.v) { - ({v} = newV); - changed = true; - } - break; + const newV = {}; + let rgb = false, hsv = false; + if (value.r !== undefined && !name.includes('r')) name += 'r'; + if (value.g !== undefined && !name.includes('g')) name += 'g'; + if (value.b !== undefined && !name.includes('b')) name += 'b'; + if (value.a !== undefined && !name.includes('a')) name += 'a'; + if (value.h !== undefined && !name.includes('h')) name += 'h'; + if (value.s !== undefined && !name.includes('s')) name += 's'; + if (value.v !== undefined && !name.includes('v')) name += 'v'; + [...name].forEach((ch) => { + switch (ch) { + case 'r': + if (hsv) return; + rgb = true; + newV.r = (value.r && value.r | 0) || (value | 0) || 0; + if (newV.r < 0) newV.r = 0; + else if (newV.r > 255) newV.r = 255; + if (r !== newV.r) { + ({r} = newV); + changed = true; } - }); - if (changed) { - if (rgb) { - r = r || 0; - g = g || 0; - b = b || 0; - const ret = ColorMethods.rgbToHsv({r, g, b}); - ({h, s, v} = ret); - } else if (hsv) { - h = h || 0; - s = !isNullish(s) ? s : 100; - v = !isNullish(v) ? v : 100; - const ret = ColorMethods.hsvToRgb({h, s, v}); - ({r, g, b} = ret); - } - a = !isNullish(a) ? a : 255; - fireChangeEvents.call(that, context || that); - } - break; - } - } - return undefined; - } - /** - * @param {GenericCallback} callback - * @returns {void} - */ - function bind (callback) { // eslint-disable-line promise/prefer-await-to-callbacks - if (typeof callback === 'function') changeEvents.push(callback); - } - /** - * @param {GenericCallback} callback - * @returns {void} - */ - function unbind (callback) { // eslint-disable-line promise/prefer-await-to-callbacks - if (typeof callback !== 'function') return; - let i; - while ((i = changeEvents.includes(callback))) { - changeEvents.splice(i, 1); - } - } - /** - * Unset `changeEvents` - * @returns {void} - */ - function destroy () { - changeEvents = null; - } - let r, g, b, a, h, s, v, changeEvents = []; - - $.extend(true, that, { - // public properties and methods - val, - bind, - unbind, - destroy - }); - if (init) { - if (!isNullish(init.ahex)) { - val('ahex', init); - } else if (!isNullish(init.hex)) { - val( - (!isNullish(init.a) ? 'a' : '') + 'hex', - !isNullish(init.a) - ? {ahex: init.hex + ColorMethods.intToHex(init.a)} - : init - ); - } else if (!isNullish(init.r) && !isNullish(init.g) && !isNullish(init.b)) { - val('rgb' + (!isNullish(init.a) ? 'a' : ''), init); - } else if (!isNullish(init.h) && !isNullish(init.s) && !isNullish(init.v)) { - val('hsv' + (!isNullish(init.a) ? 'a' : ''), init); - } - } - }, - /** - * Color conversion methods - make public to give use to external scripts. - * @namespace - */ - ColorMethods: { - /** - * @typedef {PlainObject} module:jPicker.RGBA - * @property {Integer} r - * @property {Integer} g - * @property {Integer} b - * @property {Integer} a - */ - /** - * @typedef {PlainObject} module:jPicker.RGB - * @property {Integer} r - * @property {Integer} g - * @property {Integer} b - */ - /** - * @param {string} hex - * @returns {module:jPicker.RGBA} - */ - hexToRgba (hex) { - if (hex === '' || hex === 'none') return {r: null, g: null, b: null, a: null}; - hex = this.validateHex(hex); - let r = '00', g = '00', b = '00', a = '255'; - if (hex.length === 6) hex += 'ff'; - if (hex.length > 6) { - r = hex.substring(0, 2); - g = hex.substring(2, 4); - b = hex.substring(4, 6); - a = hex.substring(6, hex.length); - } else { - if (hex.length > 4) { - r = hex.substring(4, hex.length); - hex = hex.substring(0, 4); - } - if (hex.length > 2) { - g = hex.substring(2, hex.length); - hex = hex.substring(0, 2); - } - if (hex.length > 0) b = hex.substring(0, hex.length); - } - return { - r: this.hexToInt(r), g: this.hexToInt(g), b: this.hexToInt(b), a: this.hexToInt(a) - }; - }, - /** - * @param {string} hex - * @returns {string} - */ - validateHex (hex) { - // if (typeof hex === 'object') return ''; - hex = hex.toLowerCase().replace(/[^a-f\d]/g, ''); - if (hex.length > 8) hex = hex.substring(0, 8); - return hex; - }, - /** - * @param {module:jPicker.RGBA} rgba - * @returns {string} - */ - rgbaToHex (rgba) { - return this.intToHex(rgba.r) + this.intToHex(rgba.g) + this.intToHex(rgba.b) + this.intToHex(rgba.a); - }, - /** - * @param {Integer} dec - * @returns {string} - */ - intToHex (dec) { - let result = (dec | 0).toString(16); - if (result.length === 1) result = ('0' + result); - return result.toLowerCase(); - }, - /** - * @param {string} hex - * @returns {Integer} - */ - hexToInt (hex) { - return Number.parseInt(hex, 16); - }, - /** - * @typedef {PlainObject} module:jPicker.HSV - * @property {Integer} h - * @property {Integer} s - * @property {Integer} v - */ - /** - * @param {module:jPicker.RGB} rgb - * @returns {module:jPicker.HSV} - */ - rgbToHsv (rgb) { - const r = rgb.r / 255, g = rgb.g / 255, b = rgb.b / 255, hsv = {h: 0, s: 0, v: 0}; - let min = 0, max = 0; - if (r >= g && r >= b) { - max = r; - min = g > b ? b : g; - } else if (g >= b && g >= r) { - max = g; - min = r > b ? b : r; - } else { - max = b; - min = g > r ? r : g; - } - hsv.v = max; - hsv.s = max ? (max - min) / max : 0; - let delta; - if (!hsv.s) hsv.h = 0; - else { - delta = max - min; - if (r === max) hsv.h = (g - b) / delta; - else if (g === max) hsv.h = 2 + (b - r) / delta; - else hsv.h = 4 + (r - g) / delta; - hsv.h = Number.parseInt(hsv.h * 60); - if (hsv.h < 0) hsv.h += 360; - } - hsv.s = (hsv.s * 100) | 0; - hsv.v = (hsv.v * 100) | 0; - return hsv; - }, - /** - * @param {module:jPicker.HSV} hsv - * @returns {module:jPicker.RGB} - */ - hsvToRgb (hsv) { - const rgb = {r: 0, g: 0, b: 0, a: 100}; - let {h, s, v} = hsv; - if (s === 0) { - if (v === 0) rgb.r = rgb.g = rgb.b = 0; - else rgb.r = rgb.g = rgb.b = (v * 255 / 100) | 0; - } else { - if (h === 360) h = 0; - h /= 60; - s /= 100; - v /= 100; - const i = h | 0, - f = h - i, - p = v * (1 - s), - q = v * (1 - (s * f)), - t = v * (1 - (s * (1 - f))); - switch (i) { - case 0: - rgb.r = v; - rgb.g = t; - rgb.b = p; - break; - case 1: - rgb.r = q; - rgb.g = v; - rgb.b = p; - break; - case 2: - rgb.r = p; - rgb.g = v; - rgb.b = t; - break; - case 3: - rgb.r = p; - rgb.g = q; - rgb.b = v; - break; - case 4: - rgb.r = t; - rgb.g = p; - rgb.b = v; - break; - case 5: - rgb.r = v; - rgb.g = p; - rgb.b = q; - break; - } - rgb.r = (rgb.r * 255) | 0; - rgb.g = (rgb.g * 255) | 0; - rgb.b = (rgb.b * 255) | 0; - } - return rgb; - } - } - }; - const {Color, List, ColorMethods} = $.jPicker; // local copies for YUI compressor - /* eslint-disable jsdoc/require-returns */ - /** - * @function external:jQuery.fn.jPicker - * @see {@link external:jQuery.fn.$.fn.jPicker} - */ - /* eslint-enable jsdoc/require-returns */ - - /** - * Will be bound to active {@link jQuery.jPicker.Color}. - * @callback module:jPicker.LiveCallback - * @param {external:jQuery} ui - * @param {Element} context - * @returns {void} - */ - /** - * @callback module:jPicker.CommitCallback - * @param {external:jQuery.jPicker.Color} activeColor - * @param {external:jQuery} okButton - * @returns {void} Return value not used. - */ - /** - * @callback module:jPicker.CancelCallback - * @param {external:jQuery.jPicker.Color} activeColor - * @param {external:jQuery} cancelButton - * @returns {void} Return value not used. - */ - /** - * While it would seem this should specify the name `jPicker` for JSDoc, that doesn't - * get us treated as a function as well as a namespace (even with `@function name`), - * so we use an approach to add a redundant `$.fn.` in the name. - * @namespace - * @memberof external:jQuery.fn - * @param {external:jQuery.fn.jPickerOptions} options - * @param {module:jPicker.CommitCallback} [commitCallback] - * @param {module:jPicker.LiveCallback} [liveCallback] - * @param {module:jPicker.CancelCallback} [cancelCallback] - * @returns {external:jQuery} - */ - $.fn.jPicker = function (options, commitCallback, liveCallback, cancelCallback) { - return this.each(function () { - const that = this, - settings = $.extend(true, {}, $.fn.jPicker.defaults, options); // local copies for YUI compressor - if ($(that).get(0).nodeName.toLowerCase() === 'input') { // Add color picker icon if binding to an input element and bind the events to the input - $.extend(true, settings, { - window: { - bindToInput: true, - expandable: true, - input: $(that) - } - }); - if ($(that).val() === '') { - settings.color.active = new Color({hex: null}); - settings.color.current = new Color({hex: null}); - } else if (ColorMethods.validateHex($(that).val())) { - settings.color.active = new Color({hex: $(that).val(), a: settings.color.active.val('a')}); - settings.color.current = new Color({hex: $(that).val(), a: settings.color.active.val('a')}); - } - } - if (settings.window.expandable) { - $(that).after('    '); - } else { - settings.window.liveUpdate = false; // Basic control binding for inline use - You will need to override the liveCallback or commitCallback function to retrieve results - } - const isLessThanIE7 = Number.parseFloat(navigator.appVersion.split('MSIE')[1]) < 7 && document.body.filters; // needed to run the AlphaImageLoader function for IE6 - // set color mode and update visuals for the new color mode - /** - * - * @param {"h"|"s"|"v"|"r"|"g"|"b"|"a"} colorMode - * @throws {Error} Invalid mode - * @returns {void} - */ - function setColorMode (colorMode) { - const {active} = color, // local copies for YUI compressor - // {clientPath} = images, - hex = active.val('hex'); - let rgbMap, rgbBar; - settings.color.mode = colorMode; - switch (colorMode) { - case 'h': - setTimeout(function () { - setBG.call(that, colorMapDiv, 'transparent'); - setImgLoc.call(that, colorMapL1, 0); - setAlpha.call(that, colorMapL1, 100); - setImgLoc.call(that, colorMapL2, 260); - setAlpha.call(that, colorMapL2, 100); - setBG.call(that, colorBarDiv, 'transparent'); - setImgLoc.call(that, colorBarL1, 0); - setAlpha.call(that, colorBarL1, 100); - setImgLoc.call(that, colorBarL2, 260); - setAlpha.call(that, colorBarL2, 100); - setImgLoc.call(that, colorBarL3, 260); - setAlpha.call(that, colorBarL3, 100); - setImgLoc.call(that, colorBarL4, 260); - setAlpha.call(that, colorBarL4, 100); - setImgLoc.call(that, colorBarL6, 260); - setAlpha.call(that, colorBarL6, 100); - }, 0); - colorMap.range('all', {minX: 0, maxX: 100, minY: 0, maxY: 100}); - colorBar.range('rangeY', {minY: 0, maxY: 360}); - if (isNullish(active.val('ahex'))) break; - colorMap.val('xy', {x: active.val('s'), y: 100 - active.val('v')}, colorMap); - colorBar.val('y', 360 - active.val('h'), colorBar); - break; - case 's': - setTimeout(function () { - setBG.call(that, colorMapDiv, 'transparent'); - setImgLoc.call(that, colorMapL1, -260); - setImgLoc.call(that, colorMapL2, -520); - setImgLoc.call(that, colorBarL1, -260); - setImgLoc.call(that, colorBarL2, -520); - setImgLoc.call(that, colorBarL6, 260); - setAlpha.call(that, colorBarL6, 100); - }, 0); - colorMap.range('all', {minX: 0, maxX: 360, minY: 0, maxY: 100}); - colorBar.range('rangeY', {minY: 0, maxY: 100}); - if (isNullish(active.val('ahex'))) break; - colorMap.val('xy', {x: active.val('h'), y: 100 - active.val('v')}, colorMap); - colorBar.val('y', 100 - active.val('s'), colorBar); - break; - case 'v': - setTimeout(function () { - setBG.call(that, colorMapDiv, '000000'); - setImgLoc.call(that, colorMapL1, -780); - setImgLoc.call(that, colorMapL2, 260); - setBG.call(that, colorBarDiv, hex); - setImgLoc.call(that, colorBarL1, -520); - setImgLoc.call(that, colorBarL2, 260); - setAlpha.call(that, colorBarL2, 100); - setImgLoc.call(that, colorBarL6, 260); - setAlpha.call(that, colorBarL6, 100); - }, 0); - colorMap.range('all', {minX: 0, maxX: 360, minY: 0, maxY: 100}); - colorBar.range('rangeY', {minY: 0, maxY: 100}); - if (isNullish(active.val('ahex'))) break; - colorMap.val('xy', {x: active.val('h'), y: 100 - active.val('s')}, colorMap); - colorBar.val('y', 100 - active.val('v'), colorBar); - break; - case 'r': - rgbMap = -1040; - rgbBar = -780; - colorMap.range('all', {minX: 0, maxX: 255, minY: 0, maxY: 255}); - colorBar.range('rangeY', {minY: 0, maxY: 255}); - if (isNullish(active.val('ahex'))) break; - colorMap.val('xy', {x: active.val('b'), y: 255 - active.val('g')}, colorMap); - colorBar.val('y', 255 - active.val('r'), colorBar); - break; - case 'g': - rgbMap = -1560; - rgbBar = -1820; - colorMap.range('all', {minX: 0, maxX: 255, minY: 0, maxY: 255}); - colorBar.range('rangeY', {minY: 0, maxY: 255}); - if (isNullish(active.val('ahex'))) break; - colorMap.val('xy', {x: active.val('b'), y: 255 - active.val('r')}, colorMap); - colorBar.val('y', 255 - active.val('g'), colorBar); - break; - case 'b': - rgbMap = -2080; - rgbBar = -2860; - colorMap.range('all', {minX: 0, maxX: 255, minY: 0, maxY: 255}); - colorBar.range('rangeY', {minY: 0, maxY: 255}); - if (isNullish(active.val('ahex'))) break; - colorMap.val('xy', {x: active.val('r'), y: 255 - active.val('g')}, colorMap); - colorBar.val('y', 255 - active.val('b'), colorBar); - break; - case 'a': - setTimeout(function () { - setBG.call(that, colorMapDiv, 'transparent'); - setImgLoc.call(that, colorMapL1, -260); - setImgLoc.call(that, colorMapL2, -520); - setImgLoc.call(that, colorBarL1, 260); - setImgLoc.call(that, colorBarL2, 260); - setAlpha.call(that, colorBarL2, 100); - setImgLoc.call(that, colorBarL6, 0); - setAlpha.call(that, colorBarL6, 100); - }, 0); - colorMap.range('all', {minX: 0, maxX: 360, minY: 0, maxY: 100}); - colorBar.range('rangeY', {minY: 0, maxY: 255}); - if (isNullish(active.val('ahex'))) break; - colorMap.val('xy', {x: active.val('h'), y: 100 - active.val('v')}, colorMap); - colorBar.val('y', 255 - active.val('a'), colorBar); - break; - default: - throw new Error('Invalid Mode'); - } - switch (colorMode) { - case 'h': - break; - case 's': - case 'v': - case 'a': - setTimeout(function () { - setAlpha.call(that, colorMapL1, 100); - setAlpha.call(that, colorBarL1, 100); - setImgLoc.call(that, colorBarL3, 260); - setAlpha.call(that, colorBarL3, 100); - setImgLoc.call(that, colorBarL4, 260); - setAlpha.call(that, colorBarL4, 100); - }, 0); - break; - case 'r': - case 'g': - case 'b': - setTimeout(function () { - setBG.call(that, colorMapDiv, 'transparent'); - setBG.call(that, colorBarDiv, 'transparent'); - setAlpha.call(that, colorBarL1, 100); - setAlpha.call(that, colorMapL1, 100); - setImgLoc.call(that, colorMapL1, rgbMap); - setImgLoc.call(that, colorMapL2, rgbMap - 260); - setImgLoc.call(that, colorBarL1, rgbBar - 780); - setImgLoc.call(that, colorBarL2, rgbBar - 520); - setImgLoc.call(that, colorBarL3, rgbBar); - setImgLoc.call(that, colorBarL4, rgbBar - 260); - setImgLoc.call(that, colorBarL6, 260); - setAlpha.call(that, colorBarL6, 100); - }, 0); - break; - } - if (isNullish(active.val('ahex'))) return; - activeColorChanged.call(that, active); - } - /** - * Update color when user changes text values. - * @param {external:jQuery} ui - * @param {?module:jPicker.Slider} context - * @returns {void} - */ - function activeColorChanged (ui, context) { - if (isNullish(context) || (context !== colorBar && context !== colorMap)) positionMapAndBarArrows.call(that, ui, context); - setTimeout(function () { - updatePreview.call(that, ui); - updateMapVisuals.call(that, ui); - updateBarVisuals.call(that, ui); - }, 0); - } - - /** - * User has dragged the ColorMap pointer. - * @param {external:jQuery} ui - * @param {?module:jPicker.Slider} context - * @returns {void} - */ - function mapValueChanged (ui, context) { - const {active} = color; - if (context !== colorMap && isNullish(active.val())) return; - const xy = ui.val('all'); - switch (settings.color.mode) { - case 'h': - active.val('sv', {s: xy.x, v: 100 - xy.y}, context); - break; - case 's': - case 'a': - active.val('hv', {h: xy.x, v: 100 - xy.y}, context); - break; - case 'v': - active.val('hs', {h: xy.x, s: 100 - xy.y}, context); - break; - case 'r': - active.val('gb', {g: 255 - xy.y, b: xy.x}, context); - break; - case 'g': - active.val('rb', {r: 255 - xy.y, b: xy.x}, context); - break; - case 'b': - active.val('rg', {r: xy.x, g: 255 - xy.y}, context); - break; - } - } - - /** - * User has dragged the ColorBar slider. - * @param {external:jQuery} ui - * @param {?module:jPicker.Slider} context - * @returns {void} - */ - function colorBarValueChanged (ui, context) { - const {active} = color; - if (context !== colorBar && isNullish(active.val())) return; - switch (settings.color.mode) { - case 'h': - active.val('h', {h: 360 - ui.val('y')}, context); - break; - case 's': - active.val('s', {s: 100 - ui.val('y')}, context); - break; - case 'v': - active.val('v', {v: 100 - ui.val('y')}, context); - break; - case 'r': - active.val('r', {r: 255 - ui.val('y')}, context); - break; - case 'g': - active.val('g', {g: 255 - ui.val('y')}, context); - break; - case 'b': - active.val('b', {b: 255 - ui.val('y')}, context); - break; - case 'a': - active.val('a', 255 - ui.val('y'), context); - break; - } - } - - /** - * Position map and bar arrows to match current color. - * @param {external:jQuery} ui - * @param {?module:jPicker.Slider} context - * @returns {void} - */ - function positionMapAndBarArrows (ui, context) { - if (context !== colorMap) { - switch (settings.color.mode) { - case 'h': { - const sv = ui.val('sv'); - colorMap.val('xy', {x: !isNullish(sv) ? sv.s : 100, y: 100 - (!isNullish(sv) ? sv.v : 100)}, context); - break; - } case 's': - // Fall through - case 'a': { - const hv = ui.val('hv'); - colorMap.val('xy', {x: (hv && hv.h) || 0, y: 100 - (!isNullish(hv) ? hv.v : 100)}, context); - break; - } case 'v': { - const hs = ui.val('hs'); - colorMap.val('xy', {x: (hs && hs.h) || 0, y: 100 - (!isNullish(hs) ? hs.s : 100)}, context); - break; - } case 'r': { - const bg = ui.val('bg'); - colorMap.val('xy', {x: (bg && bg.b) || 0, y: 255 - ((bg && bg.g) || 0)}, context); - break; - } case 'g': { - const br = ui.val('br'); - colorMap.val('xy', {x: (br && br.b) || 0, y: 255 - ((br && br.r) || 0)}, context); - break; - } case 'b': { - const rg = ui.val('rg'); - colorMap.val('xy', {x: (rg && rg.r) || 0, y: 255 - ((rg && rg.g) || 0)}, context); - break; - } - } - } - if (context !== colorBar) { - switch (settings.color.mode) { - case 'h': - colorBar.val('y', 360 - (ui.val('h') || 0), context); - break; - case 's': { - const s = ui.val('s'); - colorBar.val('y', 100 - (!isNullish(s) ? s : 100), context); - break; - } case 'v': { - const v = ui.val('v'); - colorBar.val('y', 100 - (!isNullish(v) ? v : 100), context); - break; - } case 'r': - colorBar.val('y', 255 - (ui.val('r') || 0), context); break; case 'g': - colorBar.val('y', 255 - (ui.val('g') || 0), context); + if (hsv) return; + rgb = true; + newV.g = (value && value.g && value.g | 0) || (value && value | 0) || 0; + if (newV.g < 0) newV.g = 0; + else if (newV.g > 255) newV.g = 255; + if (g !== newV.g) { + ({g} = newV); + changed = true; + } break; case 'b': - colorBar.val('y', 255 - (ui.val('b') || 0), context); + if (hsv) return; + rgb = true; + newV.b = (value && value.b && value.b | 0) || (value && value | 0) || 0; + if (newV.b < 0) newV.b = 0; + else if (newV.b > 255) newV.b = 255; + if (b !== newV.b) { + ({b} = newV); + changed = true; + } break; - case 'a': { - const a = ui.val('a'); - colorBar.val('y', 255 - (!isNullish(a) ? a : 255), context); + case 'a': + newV.a = value && !isNullish(value.a) ? value.a | 0 : value | 0; + if (newV.a < 0) newV.a = 0; + else if (newV.a > 255) newV.a = 255; + if (a !== newV.a) { + ({a} = newV); + changed = true; + } + break; + case 'h': + if (rgb) return; + hsv = true; + newV.h = (value && value.h && value.h | 0) || (value && value | 0) || 0; + if (newV.h < 0) newV.h = 0; + else if (newV.h > 360) newV.h = 360; + if (h !== newV.h) { + ({h} = newV); + changed = true; + } + break; + case 's': + if (rgb) return; + hsv = true; + newV.s = !isNullish(value.s) ? value.s | 0 : value | 0; + if (newV.s < 0) newV.s = 0; + else if (newV.s > 100) newV.s = 100; + if (s !== newV.s) { + ({s} = newV); + changed = true; + } + break; + case 'v': + if (rgb) return; + hsv = true; + newV.v = !isNullish(value.v) ? value.v | 0 : value | 0; + if (newV.v < 0) newV.v = 0; + else if (newV.v > 100) newV.v = 100; + if (v !== newV.v) { + ({v} = newV); + changed = true; + } break; } + }); + if (changed) { + if (rgb) { + r = r || 0; + g = g || 0; + b = b || 0; + const ret = ColorMethods.rgbToHsv({r, g, b}); + ({h, s, v} = ret); + } else if (hsv) { + h = h || 0; + s = !isNullish(s) ? s : 100; + v = !isNullish(v) ? v : 100; + const ret = ColorMethods.hsvToRgb({h, s, v}); + ({r, g, b} = ret); } + a = !isNullish(a) ? a : 255; + fireChangeEvents.call(that, context || that); + } + break; + } + } + return undefined; + } + /** + * @param {GenericCallback} callback + * @returns {void} + */ + function bind (callback) { // eslint-disable-line promise/prefer-await-to-callbacks + if (typeof callback === 'function') changeEvents.push(callback); + } + /** + * @param {GenericCallback} callback + * @returns {void} + */ + function unbind (callback) { // eslint-disable-line promise/prefer-await-to-callbacks + if (typeof callback !== 'function') return; + let i; + while ((i = changeEvents.includes(callback))) { + changeEvents.splice(i, 1); + } + } + /** + * Unset `changeEvents` + * @returns {void} + */ + function destroy () { + changeEvents = null; + } + let r, g, b, a, h, s, v, changeEvents = []; + + $.extend(true, that, { + // public properties and methods + val, + bind, + unbind, + destroy + }); + if (init) { + if (!isNullish(init.ahex)) { + val('ahex', init); + } else if (!isNullish(init.hex)) { + val( + (!isNullish(init.a) ? 'a' : '') + 'hex', + !isNullish(init.a) + ? {ahex: init.hex + ColorMethods.intToHex(init.a)} + : init + ); + } else if (!isNullish(init.r) && !isNullish(init.g) && !isNullish(init.b)) { + val('rgb' + (!isNullish(init.a) ? 'a' : ''), init); + } else if (!isNullish(init.h) && !isNullish(init.s) && !isNullish(init.v)) { + val('hsv' + (!isNullish(init.a) ? 'a' : ''), init); + } + } + }, + /** + * Color conversion methods - make public to give use to external scripts. + * @namespace + */ + ColorMethods: { + /** + * @typedef {PlainObject} module:jPicker.RGBA + * @property {Integer} r + * @property {Integer} g + * @property {Integer} b + * @property {Integer} a + */ + /** + * @typedef {PlainObject} module:jPicker.RGB + * @property {Integer} r + * @property {Integer} g + * @property {Integer} b + */ + /** + * @param {string} hex + * @returns {module:jPicker.RGBA} + */ + hexToRgba (hex) { + if (hex === '' || hex === 'none') return {r: null, g: null, b: null, a: null}; + hex = this.validateHex(hex); + let r = '00', g = '00', b = '00', a = '255'; + if (hex.length === 6) hex += 'ff'; + if (hex.length > 6) { + r = hex.substring(0, 2); + g = hex.substring(2, 4); + b = hex.substring(4, 6); + a = hex.substring(6, hex.length); + } else { + if (hex.length > 4) { + r = hex.substring(4, hex.length); + hex = hex.substring(0, 4); + } + if (hex.length > 2) { + g = hex.substring(2, hex.length); + hex = hex.substring(0, 2); + } + if (hex.length > 0) b = hex.substring(0, hex.length); + } + return { + r: this.hexToInt(r), g: this.hexToInt(g), b: this.hexToInt(b), a: this.hexToInt(a) + }; + }, + /** + * @param {string} hex + * @returns {string} + */ + validateHex (hex) { + // if (typeof hex === 'object') return ''; + hex = hex.toLowerCase().replace(/[^a-f\d]/g, ''); + if (hex.length > 8) hex = hex.substring(0, 8); + return hex; + }, + /** + * @param {module:jPicker.RGBA} rgba + * @returns {string} + */ + rgbaToHex (rgba) { + return this.intToHex(rgba.r) + this.intToHex(rgba.g) + this.intToHex(rgba.b) + this.intToHex(rgba.a); + }, + /** + * @param {Integer} dec + * @returns {string} + */ + intToHex (dec) { + let result = (dec | 0).toString(16); + if (result.length === 1) result = ('0' + result); + return result.toLowerCase(); + }, + /** + * @param {string} hex + * @returns {Integer} + */ + hexToInt (hex) { + return Number.parseInt(hex, 16); + }, + /** + * @typedef {PlainObject} module:jPicker.HSV + * @property {Integer} h + * @property {Integer} s + * @property {Integer} v + */ + /** + * @param {module:jPicker.RGB} rgb + * @returns {module:jPicker.HSV} + */ + rgbToHsv (rgb) { + const r = rgb.r / 255, g = rgb.g / 255, b = rgb.b / 255, hsv = {h: 0, s: 0, v: 0}; + let min = 0, max = 0; + if (r >= g && r >= b) { + max = r; + min = g > b ? b : g; + } else if (g >= b && g >= r) { + max = g; + min = r > b ? b : r; + } else { + max = b; + min = g > r ? r : g; + } + hsv.v = max; + hsv.s = max ? (max - min) / max : 0; + let delta; + if (!hsv.s) hsv.h = 0; + else { + delta = max - min; + if (r === max) hsv.h = (g - b) / delta; + else if (g === max) hsv.h = 2 + (b - r) / delta; + else hsv.h = 4 + (r - g) / delta; + hsv.h = Number.parseInt(hsv.h * 60); + if (hsv.h < 0) hsv.h += 360; + } + hsv.s = (hsv.s * 100) | 0; + hsv.v = (hsv.v * 100) | 0; + return hsv; + }, + /** + * @param {module:jPicker.HSV} hsv + * @returns {module:jPicker.RGB} + */ + hsvToRgb (hsv) { + const rgb = {r: 0, g: 0, b: 0, a: 100}; + let {h, s, v} = hsv; + if (s === 0) { + if (v === 0) rgb.r = rgb.g = rgb.b = 0; + else rgb.r = rgb.g = rgb.b = (v * 255 / 100) | 0; + } else { + if (h === 360) h = 0; + h /= 60; + s /= 100; + v /= 100; + const i = h | 0, + f = h - i, + p = v * (1 - s), + q = v * (1 - (s * f)), + t = v * (1 - (s * (1 - f))); + switch (i) { + case 0: + rgb.r = v; + rgb.g = t; + rgb.b = p; + break; + case 1: + rgb.r = q; + rgb.g = v; + rgb.b = p; + break; + case 2: + rgb.r = p; + rgb.g = v; + rgb.b = t; + break; + case 3: + rgb.r = p; + rgb.g = q; + rgb.b = v; + break; + case 4: + rgb.r = t; + rgb.g = p; + rgb.b = v; + break; + case 5: + rgb.r = v; + rgb.g = p; + rgb.b = q; + break; + } + rgb.r = (rgb.r * 255) | 0; + rgb.g = (rgb.g * 255) | 0; + rgb.b = (rgb.b * 255) | 0; + } + return rgb; + } + } +}; +const {Color, List, ColorMethods} = jPicker; // local copies for YUI compressor +/* eslint-disable jsdoc/require-returns */ +/** + * @function external:jQuery.fn.jPicker + * @see {@link external:jQuery.fn.$.fn.jPicker} + */ +/* eslint-enable jsdoc/require-returns */ + +/** +* Will be bound to active {@link jQuery.jPicker.Color}. +* @callback module:jPicker.LiveCallback +* @param {external:jQuery} ui +* @param {Element} context +* @returns {void} +*/ +/** +* @callback module:jPicker.CommitCallback +* @param {external:jQuery.jPicker.Color} activeColor +* @param {external:jQuery} okButton +* @returns {void} Return value not used. +*/ +/** + * @callback module:jPicker.CancelCallback + * @param {external:jQuery.jPicker.Color} activeColor + * @param {external:jQuery} cancelButton + * @returns {void} Return value not used. + */ +/** +* While it would seem this should specify the name `jPicker` for JSDoc, that doesn't +* get us treated as a function as well as a namespace (even with `@function name`), +* so we use an approach to add a redundant `$.fn.` in the name. +* @namespace +* @memberof external:jQuery.fn +* @param {external:jQuery.fn.jPickerOptions} options +* @param {module:jPicker.CommitCallback} [commitCallback] +* @param {module:jPicker.LiveCallback} [liveCallback] +* @param {module:jPicker.CancelCallback} [cancelCallback] +* @returns {external:jQuery} +*/ +export function jPickerMethod (elem, options, commitCallback, liveCallback, cancelCallback) { + return elem.each(function () { + const that = this, + settings = $.extend(true, {}, jPickerDefaults, options); // local copies for YUI compressor + if ($(that).get(0).nodeName.toLowerCase() === 'input') { // Add color picker icon if binding to an input element and bind the events to the input + $.extend(true, settings, { + window: { + bindToInput: true, + expandable: true, + input: $(that) + } + }); + if ($(that).val() === '') { + settings.color.active = new Color({hex: null}); + settings.color.current = new Color({hex: null}); + } else if (ColorMethods.validateHex($(that).val())) { + settings.color.active = new Color({hex: $(that).val(), a: settings.color.active.val('a')}); + settings.color.current = new Color({hex: $(that).val(), a: settings.color.active.val('a')}); + } + } + if (settings.window.expandable) { + $(that).after('    '); + } else { + settings.window.liveUpdate = false; // Basic control binding for inline use - You will need to override the liveCallback or commitCallback function to retrieve results + } + const isLessThanIE7 = Number.parseFloat(navigator.appVersion.split('MSIE')[1]) < 7 && document.body.filters; // needed to run the AlphaImageLoader function for IE6 + // set color mode and update visuals for the new color mode + /** + * + * @param {"h"|"s"|"v"|"r"|"g"|"b"|"a"} colorMode + * @throws {Error} Invalid mode + * @returns {void} + */ + function setColorMode (colorMode) { + const {active} = color, // local copies for YUI compressor + // {clientPath} = images, + hex = active.val('hex'); + let rgbMap, rgbBar; + settings.color.mode = colorMode; + switch (colorMode) { + case 'h': + setTimeout(function () { + setBG.call(that, colorMapDiv, 'transparent'); + setImgLoc.call(that, colorMapL1, 0); + setAlpha.call(that, colorMapL1, 100); + setImgLoc.call(that, colorMapL2, 260); + setAlpha.call(that, colorMapL2, 100); + setBG.call(that, colorBarDiv, 'transparent'); + setImgLoc.call(that, colorBarL1, 0); + setAlpha.call(that, colorBarL1, 100); + setImgLoc.call(that, colorBarL2, 260); + setAlpha.call(that, colorBarL2, 100); + setImgLoc.call(that, colorBarL3, 260); + setAlpha.call(that, colorBarL3, 100); + setImgLoc.call(that, colorBarL4, 260); + setAlpha.call(that, colorBarL4, 100); + setImgLoc.call(that, colorBarL6, 260); + setAlpha.call(that, colorBarL6, 100); + }, 0); + colorMap.range('all', {minX: 0, maxX: 100, minY: 0, maxY: 100}); + colorBar.range('rangeY', {minY: 0, maxY: 360}); + if (isNullish(active.val('ahex'))) break; + colorMap.val('xy', {x: active.val('s'), y: 100 - active.val('v')}, colorMap); + colorBar.val('y', 360 - active.val('h'), colorBar); + break; + case 's': + setTimeout(function () { + setBG.call(that, colorMapDiv, 'transparent'); + setImgLoc.call(that, colorMapL1, -260); + setImgLoc.call(that, colorMapL2, -520); + setImgLoc.call(that, colorBarL1, -260); + setImgLoc.call(that, colorBarL2, -520); + setImgLoc.call(that, colorBarL6, 260); + setAlpha.call(that, colorBarL6, 100); + }, 0); + colorMap.range('all', {minX: 0, maxX: 360, minY: 0, maxY: 100}); + colorBar.range('rangeY', {minY: 0, maxY: 100}); + if (isNullish(active.val('ahex'))) break; + colorMap.val('xy', {x: active.val('h'), y: 100 - active.val('v')}, colorMap); + colorBar.val('y', 100 - active.val('s'), colorBar); + break; + case 'v': + setTimeout(function () { + setBG.call(that, colorMapDiv, '000000'); + setImgLoc.call(that, colorMapL1, -780); + setImgLoc.call(that, colorMapL2, 260); + setBG.call(that, colorBarDiv, hex); + setImgLoc.call(that, colorBarL1, -520); + setImgLoc.call(that, colorBarL2, 260); + setAlpha.call(that, colorBarL2, 100); + setImgLoc.call(that, colorBarL6, 260); + setAlpha.call(that, colorBarL6, 100); + }, 0); + colorMap.range('all', {minX: 0, maxX: 360, minY: 0, maxY: 100}); + colorBar.range('rangeY', {minY: 0, maxY: 100}); + if (isNullish(active.val('ahex'))) break; + colorMap.val('xy', {x: active.val('h'), y: 100 - active.val('s')}, colorMap); + colorBar.val('y', 100 - active.val('v'), colorBar); + break; + case 'r': + rgbMap = -1040; + rgbBar = -780; + colorMap.range('all', {minX: 0, maxX: 255, minY: 0, maxY: 255}); + colorBar.range('rangeY', {minY: 0, maxY: 255}); + if (isNullish(active.val('ahex'))) break; + colorMap.val('xy', {x: active.val('b'), y: 255 - active.val('g')}, colorMap); + colorBar.val('y', 255 - active.val('r'), colorBar); + break; + case 'g': + rgbMap = -1560; + rgbBar = -1820; + colorMap.range('all', {minX: 0, maxX: 255, minY: 0, maxY: 255}); + colorBar.range('rangeY', {minY: 0, maxY: 255}); + if (isNullish(active.val('ahex'))) break; + colorMap.val('xy', {x: active.val('b'), y: 255 - active.val('r')}, colorMap); + colorBar.val('y', 255 - active.val('g'), colorBar); + break; + case 'b': + rgbMap = -2080; + rgbBar = -2860; + colorMap.range('all', {minX: 0, maxX: 255, minY: 0, maxY: 255}); + colorBar.range('rangeY', {minY: 0, maxY: 255}); + if (isNullish(active.val('ahex'))) break; + colorMap.val('xy', {x: active.val('r'), y: 255 - active.val('g')}, colorMap); + colorBar.val('y', 255 - active.val('b'), colorBar); + break; + case 'a': + setTimeout(function () { + setBG.call(that, colorMapDiv, 'transparent'); + setImgLoc.call(that, colorMapL1, -260); + setImgLoc.call(that, colorMapL2, -520); + setImgLoc.call(that, colorBarL1, 260); + setImgLoc.call(that, colorBarL2, 260); + setAlpha.call(that, colorBarL2, 100); + setImgLoc.call(that, colorBarL6, 0); + setAlpha.call(that, colorBarL6, 100); + }, 0); + colorMap.range('all', {minX: 0, maxX: 360, minY: 0, maxY: 100}); + colorBar.range('rangeY', {minY: 0, maxY: 255}); + if (isNullish(active.val('ahex'))) break; + colorMap.val('xy', {x: active.val('h'), y: 100 - active.val('v')}, colorMap); + colorBar.val('y', 255 - active.val('a'), colorBar); + break; + default: + throw new Error('Invalid Mode'); + } + switch (colorMode) { + case 'h': + break; + case 's': + case 'v': + case 'a': + setTimeout(function () { + setAlpha.call(that, colorMapL1, 100); + setAlpha.call(that, colorBarL1, 100); + setImgLoc.call(that, colorBarL3, 260); + setAlpha.call(that, colorBarL3, 100); + setImgLoc.call(that, colorBarL4, 260); + setAlpha.call(that, colorBarL4, 100); + }, 0); + break; + case 'r': + case 'g': + case 'b': + setTimeout(function () { + setBG.call(that, colorMapDiv, 'transparent'); + setBG.call(that, colorBarDiv, 'transparent'); + setAlpha.call(that, colorBarL1, 100); + setAlpha.call(that, colorMapL1, 100); + setImgLoc.call(that, colorMapL1, rgbMap); + setImgLoc.call(that, colorMapL2, rgbMap - 260); + setImgLoc.call(that, colorBarL1, rgbBar - 780); + setImgLoc.call(that, colorBarL2, rgbBar - 520); + setImgLoc.call(that, colorBarL3, rgbBar); + setImgLoc.call(that, colorBarL4, rgbBar - 260); + setImgLoc.call(that, colorBarL6, 260); + setAlpha.call(that, colorBarL6, 100); + }, 0); + break; + } + if (isNullish(active.val('ahex'))) return; + activeColorChanged.call(that, active); + } + /** + * Update color when user changes text values. + * @param {external:jQuery} ui + * @param {?module:jPicker.Slider} context + * @returns {void} + */ + function activeColorChanged (ui, context) { + if (isNullish(context) || (context !== colorBar && context !== colorMap)) positionMapAndBarArrows.call(that, ui, context); + setTimeout(function () { + updatePreview.call(that, ui); + updateMapVisuals.call(that, ui); + updateBarVisuals.call(that, ui); + }, 0); + } + + /** + * User has dragged the ColorMap pointer. + * @param {external:jQuery} ui + * @param {?module:jPicker.Slider} context + * @returns {void} + */ + function mapValueChanged (ui, context) { + const {active} = color; + if (context !== colorMap && isNullish(active.val())) return; + const xy = ui.val('all'); + switch (settings.color.mode) { + case 'h': + active.val('sv', {s: xy.x, v: 100 - xy.y}, context); + break; + case 's': + case 'a': + active.val('hv', {h: xy.x, v: 100 - xy.y}, context); + break; + case 'v': + active.val('hs', {h: xy.x, s: 100 - xy.y}, context); + break; + case 'r': + active.val('gb', {g: 255 - xy.y, b: xy.x}, context); + break; + case 'g': + active.val('rb', {r: 255 - xy.y, b: xy.x}, context); + break; + case 'b': + active.val('rg', {r: xy.x, g: 255 - xy.y}, context); + break; + } + } + + /** + * User has dragged the ColorBar slider. + * @param {external:jQuery} ui + * @param {?module:jPicker.Slider} context + * @returns {void} + */ + function colorBarValueChanged (ui, context) { + const {active} = color; + if (context !== colorBar && isNullish(active.val())) return; + switch (settings.color.mode) { + case 'h': + active.val('h', {h: 360 - ui.val('y')}, context); + break; + case 's': + active.val('s', {s: 100 - ui.val('y')}, context); + break; + case 'v': + active.val('v', {v: 100 - ui.val('y')}, context); + break; + case 'r': + active.val('r', {r: 255 - ui.val('y')}, context); + break; + case 'g': + active.val('g', {g: 255 - ui.val('y')}, context); + break; + case 'b': + active.val('b', {b: 255 - ui.val('y')}, context); + break; + case 'a': + active.val('a', 255 - ui.val('y'), context); + break; + } + } + + /** + * Position map and bar arrows to match current color. + * @param {external:jQuery} ui + * @param {?module:jPicker.Slider} context + * @returns {void} + */ + function positionMapAndBarArrows (ui, context) { + if (context !== colorMap) { + switch (settings.color.mode) { + case 'h': { + const sv = ui.val('sv'); + colorMap.val('xy', {x: !isNullish(sv) ? sv.s : 100, y: 100 - (!isNullish(sv) ? sv.v : 100)}, context); + break; + } case 's': + // Fall through + case 'a': { + const hv = ui.val('hv'); + colorMap.val('xy', {x: (hv && hv.h) || 0, y: 100 - (!isNullish(hv) ? hv.v : 100)}, context); + break; + } case 'v': { + const hs = ui.val('hs'); + colorMap.val('xy', {x: (hs && hs.h) || 0, y: 100 - (!isNullish(hs) ? hs.s : 100)}, context); + break; + } case 'r': { + const bg = ui.val('bg'); + colorMap.val('xy', {x: (bg && bg.b) || 0, y: 255 - ((bg && bg.g) || 0)}, context); + break; + } case 'g': { + const br = ui.val('br'); + colorMap.val('xy', {x: (br && br.b) || 0, y: 255 - ((br && br.r) || 0)}, context); + break; + } case 'b': { + const rg = ui.val('rg'); + colorMap.val('xy', {x: (rg && rg.r) || 0, y: 255 - ((rg && rg.g) || 0)}, context); + break; + } } } - /** - * @param {external:jQuery} ui - * @returns {void} - */ - function updatePreview (ui) { - try { - const all = ui.val('all'); - activePreview.css({backgroundColor: (all && '#' + all.hex) || 'transparent'}); - setAlpha.call(that, activePreview, (all && toFixedNumeric((all.a * 100) / 255, 4)) || 0); - } catch (e) {} - } - /** - * @param {external:jQuery} ui - * @returns {void} - */ - function updateMapVisuals (ui) { + if (context !== colorBar) { switch (settings.color.mode) { case 'h': - setBG.call(that, colorMapDiv, new Color({h: ui.val('h') || 0, s: 100, v: 100}).val('hex')); + colorBar.val('y', 360 - (ui.val('h') || 0), context); break; - case 's': - case 'a': { + case 's': { const s = ui.val('s'); - setAlpha.call(that, colorMapL2, 100 - (!isNullish(s) ? s : 100)); + colorBar.val('y', 100 - (!isNullish(s) ? s : 100), context); break; } case 'v': { const v = ui.val('v'); - setAlpha.call(that, colorMapL1, !isNullish(v) ? v : 100); + colorBar.val('y', 100 - (!isNullish(v) ? v : 100), context); break; } case 'r': - setAlpha.call(that, colorMapL2, toFixedNumeric((ui.val('r') || 0) / 255 * 100, 4)); + colorBar.val('y', 255 - (ui.val('r') || 0), context); break; case 'g': - setAlpha.call(that, colorMapL2, toFixedNumeric((ui.val('g') || 0) / 255 * 100, 4)); + colorBar.val('y', 255 - (ui.val('g') || 0), context); break; case 'b': - setAlpha.call(that, colorMapL2, toFixedNumeric((ui.val('b') || 0) / 255 * 100)); + colorBar.val('y', 255 - (ui.val('b') || 0), context); break; - } - const a = ui.val('a'); - setAlpha.call(that, colorMapL3, toFixedNumeric(((255 - (a || 0)) * 100) / 255, 4)); - } - /** - * @param {external:jQuery} ui - * @returns {void} - */ - function updateBarVisuals (ui) { - switch (settings.color.mode) { - case 'h': { + case 'a': { const a = ui.val('a'); - setAlpha.call(that, colorBarL5, toFixedNumeric(((255 - (a || 0)) * 100) / 255, 4)); - break; - } case 's': { - const hva = ui.val('hva'), - saturatedColor = new Color({h: (hva && hva.h) || 0, s: 100, v: !isNullish(hva) ? hva.v : 100}); - setBG.call(that, colorBarDiv, saturatedColor.val('hex')); - setAlpha.call(that, colorBarL2, 100 - (!isNullish(hva) ? hva.v : 100)); - setAlpha.call(that, colorBarL5, toFixedNumeric(((255 - ((hva && hva.a) || 0)) * 100) / 255, 4)); - break; - } case 'v': { - const hsa = ui.val('hsa'), - valueColor = new Color({h: (hsa && hsa.h) || 0, s: !isNullish(hsa) ? hsa.s : 100, v: 100}); - setBG.call(that, colorBarDiv, valueColor.val('hex')); - setAlpha.call(that, colorBarL5, toFixedNumeric(((255 - ((hsa && hsa.a) || 0)) * 100) / 255, 4)); - break; - } case 'r': - case 'g': - case 'b': { - const rgba = ui.val('rgba'); - let hValue = 0, vValue = 0; - if (settings.color.mode === 'r') { - hValue = (rgba && rgba.b) || 0; - vValue = (rgba && rgba.g) || 0; - } else if (settings.color.mode === 'g') { - hValue = (rgba && rgba.b) || 0; - vValue = (rgba && rgba.r) || 0; - } else if (settings.color.mode === 'b') { - hValue = (rgba && rgba.r) || 0; - vValue = (rgba && rgba.g) || 0; - } - const middle = vValue > hValue ? hValue : vValue; - setAlpha.call(that, colorBarL2, hValue > vValue ? toFixedNumeric(((hValue - vValue) / (255 - vValue)) * 100, 4) : 0); - setAlpha.call(that, colorBarL3, vValue > hValue ? toFixedNumeric(((vValue - hValue) / (255 - hValue)) * 100, 4) : 0); - setAlpha.call(that, colorBarL4, toFixedNumeric((middle / 255) * 100, 4)); - setAlpha.call(that, colorBarL5, toFixedNumeric(((255 - ((rgba && rgba.a) || 0)) * 100) / 255, 4)); - break; - } case 'a': { - const a = ui.val('a'); - setBG.call(that, colorBarDiv, ui.val('hex') || '000000'); - setAlpha.call(that, colorBarL5, !isNullish(a) ? 0 : 100); - setAlpha.call(that, colorBarL6, !isNullish(a) ? 100 : 0); + colorBar.val('y', 255 - (!isNullish(a) ? a : 255), context); break; } } } - /** - * @param {external:jQuery} el - * @param {string} [c="transparent"] - * @returns {void} - */ - function setBG (el, c) { - el.css({backgroundColor: (c && c.length === 6 && '#' + c) || 'transparent'}); - } - - /** - * @param {external:jQuery} img - * @param {string} src The image source - * @returns {void} - */ - function setImg (img, src) { - if (isLessThanIE7 && (src.includes('AlphaBar.png') || src.includes('Bars.png') || src.includes('Maps.png'))) { - img.attr('pngSrc', src); - img.css({backgroundImage: 'none', filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\', sizingMethod=\'scale\')'}); - } else img.css({backgroundImage: 'url(\'' + src + '\')'}); - } - /** - * @param {external:jQuery} img - * @param {Float} y - * @returns {void} - */ - function setImgLoc (img, y) { - img.css({top: y + 'px'}); - } - /** - * @param {external:jQuery} obj - * @param {Float} alpha - * @returns {void} - */ - function setAlpha (obj, alpha) { - obj.css({visibility: alpha > 0 ? 'visible' : 'hidden'}); - if (alpha > 0 && alpha < 100) { - if (isLessThanIE7) { - const src = obj.attr('pngSrc'); - if (!isNullish(src) && ( - src.includes('AlphaBar.png') || src.includes('Bars.png') || src.includes('Maps.png') - )) { - obj.css({ - filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + - '\', sizingMethod=\'scale\') progid:DXImageTransform.Microsoft.Alpha(opacity=' + alpha + ')' - }); - } else obj.css({opacity: toFixedNumeric(alpha / 100, 4)}); - } else obj.css({opacity: toFixedNumeric(alpha / 100, 4)}); - } else if (alpha === 0 || alpha === 100) { - if (isLessThanIE7) { - const src = obj.attr('pngSrc'); - if (!isNullish(src) && ( - src.includes('AlphaBar.png') || src.includes('Bars.png') || src.includes('Maps.png') - )) { - obj.css({ - filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + - '\', sizingMethod=\'scale\')' - }); - } else obj.css({opacity: ''}); - } else obj.css({opacity: ''}); - } - } - - /** - * Revert color to original color when opened. - * @returns {void} - */ - function revertColor () { - color.active.val('ahex', color.current.val('ahex')); - } - /** - * Commit the color changes. - * @returns {void} - */ - function commitColor () { - color.current.val('ahex', color.active.val('ahex')); - } - /** - * @param {Event} e - * @returns {void} - */ - function radioClicked (e) { - $(this).parents('tbody:first').find('input:radio[value!="' + e.target.value + '"]').removeAttr('checked'); - setColorMode.call(that, e.target.value); - } - /** - * - * @returns {void} - */ - function currentClicked () { - revertColor.call(that); - } - /** - * - * @returns {void} - */ - function cancelClicked () { - revertColor.call(that); - settings.window.expandable && hide.call(that); - typeof cancelCallback === 'function' && cancelCallback.call(that, color.active, cancelButton); - } - /** - * - * @returns {void} - */ - function okClicked () { - commitColor.call(that); - settings.window.expandable && hide.call(that); - typeof commitCallback === 'function' && commitCallback.call(that, color.active, okButton); - } - /** - * - * @returns {void} - */ - function iconImageClicked () { - show.call(that); - } - /** - * @param {external:jQuery} ui - * @returns {void} - */ - function currentColorChanged (ui) { - const hex = ui.val('hex'); - currentPreview.css({backgroundColor: (hex && '#' + hex) || 'transparent'}); - setAlpha.call(that, currentPreview, toFixedNumeric(((ui.val('a') || 0) * 100) / 255, 4)); - } - /** - * @param {external:jQuery} ui - * @returns {void} - */ - function expandableColorChanged (ui) { - const hex = ui.val('hex'); - const va = ui.val('va'); - iconColor.css({backgroundColor: (hex && '#' + hex) || 'transparent'}); - setAlpha.call(that, iconAlpha, toFixedNumeric(((255 - ((va && va.a) || 0)) * 100) / 255, 4)); - if (settings.window.bindToInput && settings.window.updateInputColor) { - settings.window.input.css({ - backgroundColor: (hex && '#' + hex) || 'transparent', - color: isNullish(va) || va.v > 75 ? '#000000' : '#ffffff' - }); - } - } - /** - * @param {Event} e - * @returns {void} - */ - function moveBarMouseDown (e) { - // const {element} = settings.window, // local copies for YUI compressor - // {page} = settings.window; - elementStartX = Number.parseInt(container.css('left')); - elementStartY = Number.parseInt(container.css('top')); - pageStartX = e.pageX; - pageStartY = e.pageY; - // bind events to document to move window - we will unbind these on mouseup - $(document).bind('mousemove', documentMouseMove).bind('mouseup', documentMouseUp); - e.preventDefault(); // prevent attempted dragging of the column - } - /** - * @param {Event} e - * @returns {false} - */ - function documentMouseMove (e) { - container.css({ - left: elementStartX - (pageStartX - e.pageX) + 'px', - top: elementStartY - (pageStartY - e.pageY) + 'px' - }); - if (settings.window.expandable && !$.support.boxModel) { - container.prev().css({ - left: container.css('left'), - top: container.css('top') - }); - } - e.stopPropagation(); - e.preventDefault(); - return false; - } - /** - * @param {Event} e - * @returns {false} - */ - function documentMouseUp (e) { - $(document).unbind('mousemove', documentMouseMove).unbind('mouseup', documentMouseUp); - e.stopPropagation(); - e.preventDefault(); - return false; - } - /** - * @param {Event} e - * @returns {false} - */ - function quickPickClicked (e) { - e.preventDefault(); - e.stopPropagation(); - color.active.val('ahex', $(this).attr('title') || null, e.target); - return false; - } - /** - * - * @returns {void} - */ - function show () { - color.current.val('ahex', color.active.val('ahex')); - /** - * - * @returns {void} - */ - function attachIFrame () { - if (!settings.window.expandable || $.support.boxModel) return; - const table = container.find('table:first'); - container.before('