LocalCDN-Firefox-Chrome-Brave/modules/internal/color-picker/color-picker.js

835 lines
28 KiB
JavaScript

/*!
*
* The MIT License (MIT)
*
* Copyright © 2021 Taufik Nurrohman
*
* <https://github.com/taufik-nurrohman/color-picker>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the “Software”), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
(function(global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.CP = factory());
})(this, function() {
'use strict';
var isArray = function isArray(x) {
return Array.isArray(x);
};
var isDefined = function isDefined(x) {
return 'undefined' !== typeof x;
};
var isFunction = function isFunction(x) {
return 'function' === typeof x;
};
var isInstance = function isInstance(x, of ) {
return x && isSet( of ) && x instanceof of ;
};
var isNull = function isNull(x) {
return null === x;
};
var isNumber = function isNumber(x) {
return 'number' === typeof x;
};
var isNumeric = function isNumeric(x) {
return /^-?(?:\d*.)?\d+$/.test(x + "");
};
var isObject = function isObject(x, isPlain) {
if (isPlain === void 0) {
isPlain = true;
}
if ('object' !== typeof x) {
return false;
}
return isPlain ? isInstance(x, Object) : true;
};
var isSet = function isSet(x) {
return isDefined(x) && !isNull(x);
};
var isString = function isString(x) {
return 'string' === typeof x;
};
var fromJSON = function fromJSON(x) {
var value = null;
try {
value = JSON.parse(x);
} catch (e) {}
return value;
};
var fromStates = function fromStates() {
for (var _len = arguments.length, lot = new Array(_len), _key = 0; _key < _len; _key++) {
lot[_key] = arguments[_key];
}
return Object.assign.apply(Object, [{}].concat(lot));
};
var fromValue = function fromValue(x) {
if (isArray(x)) {
return x.map(function(v) {
return fromValue(x);
});
}
if (isObject(x)) {
for (var k in x) {
x[k] = fromValue(x[k]);
}
return x;
}
if (false === x) {
return 'false';
}
if (null === x) {
return 'null';
}
if (true === x) {
return 'true';
}
return "" + x;
};
var toCaseCamel = function toCaseCamel(x) {
return x.replace(/[-_.](\w)/g, function(m0, m1) {
return toCaseUpper(m1);
});
};
var toCaseUpper = function toCaseUpper(x) {
return x.toUpperCase();
};
var toCount = function toCount(x) {
return x.length;
};
var toEdge = function toEdge(x, edges) {
if (isSet(edges[0]) && x < edges[0]) {
return edges[0];
}
if (isSet(edges[1]) && x > edges[1]) {
return edges[1];
}
return x;
};
var toJSON = function toJSON(x) {
return JSON.stringify(x);
};
var toNumber = function toNumber(x, base) {
if (base === void 0) {
base = 10;
}
return base ? parseInt(x, base) : parseFloat(x);
};
var toObjectCount = function toObjectCount(x) {
return toCount(toObjectKeys(x));
};
var toObjectKeys = function toObjectKeys(x) {
return Object.keys(x);
};
var toRound = function toRound(x) {
return isNumber(x) ? Math.round(x) : null;
};
var toString = function toString(x, base) {
if (base === void 0) {
base = 10;
}
return isNumber(x) ? x.toString(base) : "" + x;
};
var toValue = function toValue(x) {
if (isArray(x)) {
return x.map(function(v) {
return toValue(v);
});
}
if (isNumeric(x)) {
return toNumber(x);
}
if (isObject(x)) {
for (var k in x) {
x[k] = toValue(x[k]);
}
return x;
}
if ('false' === x) {
return false;
}
if ('null' === x) {
return null;
}
if ('true' === x) {
return true;
}
return x;
};
var D = document;
var W = window;
var B = D.body;
var R = D.documentElement;
var getAttribute = function getAttribute(node, attribute, parseValue) {
if (parseValue === void 0) {
parseValue = true;
}
if (!hasAttribute(node, attribute)) {
return null;
}
var value = node.getAttribute(attribute);
return parseValue ? toValue(value) : value;
};
var getDatum = function getDatum(node, datum, parseValue) {
if (parseValue === void 0) {
parseValue = true;
}
var value = getAttribute(node, 'data-' + datum, parseValue),
v = (value + "").trim();
if (parseValue && v && ('[' === v[0] && ']' === v.slice(-1) || '{' === v[0] && '}' === v.slice(-1)) && null !== (v = fromJSON(value))) {
return v;
}
return value;
};
var getParent = function getParent(node) {
return node.parentNode || null;
};
var getState = function getState(node, state) {
return hasState(node, state) && node[state] || null;
};
var getText = function getText(node, trim) {
if (trim === void 0) {
trim = true;
}
var state = 'textContent';
if (!hasState(node, state)) {
return false;
}
var content = node[state];
content = trim ? content.trim() : content;
return "" !== content ? content : null;
};
var hasAttribute = function hasAttribute(node, attribute) {
return node.hasAttribute(attribute);
};
var hasState = function hasState(node, state) {
return state in node;
};
var isWindow = function isWindow(node) {
return node === W;
};
var letAttribute = function letAttribute(node, attribute) {
return node.removeAttribute(attribute), node;
};
var letElement = function letElement(node) {
var parent = getParent(node);
return node.remove(), parent;
};
var setAttribute = function setAttribute(node, attribute, value) {
if (true === value) {
value = attribute;
}
return node.setAttribute(attribute, fromValue(value)), node;
};
var setAttributes = function setAttributes(node, attributes) {
var value;
for (var attribute in attributes) {
value = attributes[attribute];
if (value || "" === value || 0 === value) {
setAttribute(node, attribute, value);
} else {
letAttribute(node, attribute);
}
}
return node;
};
var setChildLast = function setChildLast(parent, node) {
return parent.append(node), node;
};
var setDatum = function setDatum(node, datum, value) {
if (isArray(value) || isObject(value)) {
value = toJSON(value);
}
return setAttribute(node, 'data-' + datum, value);
};
var setElement = function setElement(node, content, attributes) {
node = isString(node) ? D.createElement(node) : node;
if (isObject(content)) {
attributes = content;
content = false;
}
if (isString(content)) {
setHTML(node, content);
}
if (isObject(attributes)) {
setAttributes(node, attributes);
}
return node;
};
var setHTML = function setHTML(node, content, trim) {
if (trim === void 0) {
trim = true;
}
if (null === content) {
return node;
}
var state = 'innerHTML';
return hasState(node, state) && (node[state] = trim ? content.trim() : content), node;
};
var setState = function setState(node, key, value) {
return node[key] = value, node;
};
var setStyle = function setStyle(node, style, value) {
if (isNumber(value)) {
value += 'px';
}
return node.style[toCaseCamel(style)] = fromValue(value), node;
};
var setText = function setText(node, content, trim) {
if (trim === void 0) {
trim = true;
}
if (null === content) {
return node;
}
var state = 'textContent';
return hasState(node, state) && (node[state] = trim ? content.trim() : content), node;
};
var offEvent = function offEvent(name, node, then) {
node.removeEventListener(name, then);
};
var offEventDefault = function offEventDefault(e) {
return e && e.preventDefault();
};
var offEvents = function offEvents(names, node, then) {
names.forEach(function(name) {
return offEvent(name, node, then);
});
};
var onEvent = function onEvent(name, node, then, options) {
if (options === void 0) {
options = false;
}
node.addEventListener(name, then, options);
};
var onEvents = function onEvents(names, node, then, options) {
if (options === void 0) {
options = false;
}
names.forEach(function(name) {
return onEvent(name, node, then, options);
});
};
function hook($) {
var hooks = {};
function fire(name, data) {
if (!isSet(hooks[name])) {
return $;
}
hooks[name].forEach(function(then) {
return then.apply($, data);
});
return $;
}
function off(name, then) {
if (!isSet(name)) {
return hooks = {}, $;
}
if (isSet(hooks[name])) {
if (isSet(then)) {
for (var i = 0, _j = hooks[name].length; i < _j; ++i) {
if (then === hooks[name][i]) {
hooks[name].splice(i, 1);
break;
}
} // Clean-up empty hook(s)
if (0 === j) {
delete hooks[name];
}
} else {
delete hooks[name];
}
}
return $;
}
function on(name, then) {
if (!isSet(hooks[name])) {
hooks[name] = [];
}
if (isSet(then)) {
hooks[name].push(then);
}
return $;
}
$.hooks = hooks;
$.fire = fire;
$.off = off;
$.on = on;
return $;
}
var getAxis = function getAxis(event, node) {
var touches = event.touches,
x = touches ? touches[0].clientX : event.clientX,
y = touches ? touches[0].clientY : event.clientY;
if (node) {
var rect = getRect(node);
return [x - rect[0], y - rect[1], rect[0], rect[1]];
}
return [x, y];
};
var getRect = function getRect(node) {
var h, rect, w, x, y, X, Y;
if (isWindow(node)) {
x = node.pageXOffset || R.scrollLeft || B.scrollLeft;
y = node.pageYOffset || R.scrollTop || B.scrollTop;
w = node.innerWidth;
h = node.innerHeight;
} else {
rect = node.getBoundingClientRect();
x = rect.left;
y = rect.top;
w = rect.width;
h = rect.height;
X = rect.right;
Y = rect.bottom;
}
return [x, y, w, h, X, Y];
};
let name = 'CP',
delay = W.setTimeout,
hex = 'HEX';
function getClosest(a, b) {
if (a === b) {
return a;
}
while ((a = a.parentElement) && a !== b);
return a;
} // Convert cursor position to RGBA
function P2RGB(a) {
let h = +a[0],
s = +a[1],
v = +a[2],
r,
g,
b,
i,
f,
p,
q,
t;
i = Math.floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
i = i || 0;
q = q || 0;
t = t || 0;
switch (i % 6) {
case 0:
r = v, g = t, b = p;
break;
case 1:
r = q, g = v, b = p;
break;
case 2:
r = p, g = v, b = t;
break;
case 3:
r = p, g = q, b = v;
break;
case 4:
r = t, g = p, b = v;
break;
case 5:
r = v, g = p, b = q;
break;
}
return [toRound(r * 255), toRound(g * 255), toRound(b * 255), isSet(a[3]) ? +a[3] : 1];
} // Convert RGBA to HSVA
function RGB2HSV(a) {
let r = +a[0] / 255,
g = +a[1] / 255,
b = +a[2] / 255,
max = Math.max(r, g, b),
min = Math.min(r, g, b),
h,
s,
v = max,
d = max - min;
s = max === 0 ? 0 : d / max;
if (max === min) {
h = 0; // Achromatic
} else {
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h /= 6;
}
return [h, s, v, isSet(a[3]) ? +a[3] : 1];
}
const EVENTS_DOWN = ['touchstart', 'mousedown'];
const EVENTS_MOVE = ['touchmove', 'mousemove'];
const EVENTS_RESIZE = ['orientationchange', 'resize'];
const EVENTS_UP = ['touchend', 'mouseup'];
function CP(source, state = {}) {
if (!source) return;
const $ = this; // Return new instance if `CP` was called without the `new` operator
if (!isInstance($, CP)) {
return new CP(source, state);
} // Already instantiated, skip!
if (source[name]) {
return;
}
let {
fire,
hooks
} = hook($);
$.state = state = fromStates(CP.state, isString(state) ? {
color: state
} : state || {});
$.source = source;
$.visible = false; // Store current instance to `CP.instances`
CP.instances[source.id || source.name || toObjectCount(CP.instances)] = $; // Mark current DOM as active color picker to prevent duplicate instance
source[name] = 1;
function theValue(from) {
let to = CP[isFunction(CP[state.color]) ? state.color : hex],
theColor; // Get value from `data-color` attribute
if (theColor = getDatum(source, 'color')) {
if (isSet(from)) {
return setDatum(source, 'color', to(from));
}
return to(theColor);
} // Get value from `value` attribute
if (theColor = getState(source, 'value')) {
if (isSet(from)) {
return setState(source, 'value', to(from));
}
return to(theColor);
} // Get value from content
if (theColor = getText(source)) {
if (isSet(from)) {
return setText(source, to(from));
}
return to(theColor);
}
if (isSet(from)) {
return; // Do nothing
}
return [0, 0, 0, 1]; // Default to black
}
let className = state['class'],
doEnter,
doExit,
doFit,
doResize,
theColor = theValue(),
theData = RGB2HSV(theColor),
self = setElement('div', {
'class': className
}),
C = setElement('div'),
SV = setElement('div', {
'class': className + ':sv'
}),
H = setElement('div', {
'class': className + ':h'
}),
A = setElement('div', {
'class': className + ':a'
}),
SVColor = setElement('div'),
SVSaturation = setElement('div'),
SVValue = setElement('div'),
SVCursor = setElement('i'),
HColor = setElement('div'),
HCursor = setElement('i'),
AColor = setElement('div'),
APattern = setElement('div'),
ACursor = setElement('i'),
SVStarting = 0,
HStarting = 0,
AStarting = 0,
SVDragging = 0,
HDragging = 0,
ADragging = 0;
setChildLast(self, C);
setChildLast(C, SV);
setChildLast(C, H);
setChildLast(C, A);
setChildLast(SV, SVColor);
setChildLast(SV, SVSaturation);
setChildLast(SV, SVValue);
setChildLast(SV, SVCursor);
setChildLast(H, HColor);
setChildLast(H, HCursor);
setChildLast(A, AColor);
setChildLast(A, APattern);
setChildLast(A, ACursor);
function doApply(isFirst, toParent) {
// Refresh data
theData = RGB2HSV(theColor = theValue());
if (!isFirst) {
setChildLast(toParent || state.parent || B, self);
$.visible = true;
}
doEnter = toParent => {
return doApply(0, toParent), fire('enter', theColor), $;
};
doExit = () => {
if (getParent(self)) {
letElement(self);
$.current = null;
$.visible = false;
}
offEvents(EVENTS_DOWN, SV, doDownSV);
offEvents(EVENTS_DOWN, H, doDownH);
offEvents(EVENTS_DOWN, A, doDownA);
offEvents(EVENTS_MOVE, D, doMove);
offEvents(EVENTS_UP, D, doStop);
offEvents(EVENTS_RESIZE, W, doResize);
return fire('exit', theColor);
};
doFit = to => {
let rootRect = getRect(R),
sourceRect = getRect(source),
winRect = getRect(W),
scrollBarHeight = winRect[3] - R.clientHeight,
// Horizontal scroll bar
scrollBarWidth = winRect[2] - rootRect[2],
// Vertical scroll bar
selfRect = getRect(self),
selfHeight = selfRect[3],
selfWidth = selfRect[2],
selfLeft = sourceRect[0] + winRect[0],
selfTop = sourceRect[1] + winRect[1] + sourceRect[3]; // Drop!
if (isObject(to)) {
isSet(to[0]) && (selfLeft = to[0]);
isSet(to[1]) && (selfTop = to[1]);
} else {
let minX = winRect[0],
minY = winRect[1],
maxX = winRect[0] + winRect[2] - selfWidth - scrollBarWidth,
maxY = winRect[1] + winRect[3] - selfHeight - scrollBarHeight;
selfLeft = toEdge(selfLeft, [minX, maxX]) >> 0;
selfTop = toEdge(selfTop, [minY, maxY]) >> 0;
}
setStyle(self, 'left', selfLeft);
setStyle(self, 'top', selfTop);
return fire('fit', theColor);
};
doResize = () => doFit();
function doDownA(e) {
$.current = A;
AStarting = ADragging = 1;
doMove(e);
offEventDefault(e);
}
function doDownH(e) {
$.current = H;
HStarting = HDragging = 1;
doMove(e);
offEventDefault(e);
}
function doDownSV(e) {
$.current = SV;
SVStarting = SVDragging = 1;
doMove(e);
offEventDefault(e);
}
function doMove(e) {
SVDragging && doSetSVCursor(e);
HDragging && doSetHCursor(e);
ADragging && doSetACursor(e);
theColor = P2RGB(theData);
if (SVDragging || HDragging || ADragging) {
fire(SVStarting || HStarting || AStarting ? 'start' : 'drag', theColor);
fire('change', theColor);
}
SVStarting = HStarting = AStarting = 0;
}
function doSetColor() {
doSetCursor(theData);
let a = P2RGB(theData),
b = P2RGB([theData[0], 1, 1]);
setStyle(SVColor, 'background-color', 'rgb(' + b[0] + ',' + b[1] + ',' + b[2] + ')');
setStyle(AColor, 'background-image', 'linear-gradient(rgb(' + a[0] + ',' + a[1] + ',' + a[2] + '),transparent)');
}
function doSetCursor(x) {
isSet(x[1]) && setStyle(SVCursor, 'right', SVWidth - SVWidthCursor / 2 - SVWidth * +x[1]);
isSet(x[2]) && setStyle(SVCursor, 'top', SVHeight - SVHeightCursor / 2 - SVHeight * +x[2]);
isSet(x[0]) && setStyle(HCursor, 'top', HHeight - HHeightCursor / 2 - HHeight * +x[0]);
isSet(x[3]) && setStyle(ACursor, 'top', AHeight - AHeightCursor / 2 - AHeight * +x[3]);
}
function doSetACursor(e) {
theData[3] = (AHeight - toEdge(getAxis(e, A)[1], [0, AHeight])) / AHeight;
doSetColor();
}
function doSetHCursor(e) {
theData[0] = (HHeight - toEdge(getAxis(e, H)[1], [0, HHeight])) / HHeight;
doSetColor();
}
function doSetSVCursor(e) {
let SVPoint = getAxis(e, SV),
x = toEdge(SVPoint[0], [0, SVWidth]),
y = toEdge(SVPoint[1], [0, SVHeight]);
theData[1] = 1 - (SVWidth - x) / SVWidth;
theData[2] = (SVHeight - y) / SVHeight;
doSetColor();
}
function doStop(e) {
theColor = P2RGB(theData);
let t = e.target,
isSource = source === getClosest(t, source),
isSelf = self === getClosest(t, self);
$.current = null;
if (!isSource && !isSelf) {
if (hooks.blur) {
fire('blur', theColor);
} else {
// Click outside the source or picker element to exit
if (SVDragging || HDragging || ADragging);
else {
getParent(self) && doExit();
}
}
} else {
if (isSelf) {
if (SVDragging || HDragging || ADragging) {
fire('stop', theColor);
}
}
}
SVDragging = HDragging = ADragging = 0;
}
let SVRect = getRect(SV),
SVRectCursor = getRect(SVCursor),
HRect = getRect(H),
HRectCursor = getRect(HCursor),
ARect = getRect(A),
ARectCursor = getRect(ACursor),
SVHeight = SVRect[3],
SVHeightCursor = SVRectCursor[3],
SVWidth = SVRect[2],
SVWidthCursor = SVRectCursor[2],
HHeight = HRect[3],
HHeightCursor = HRectCursor[3],
AHeight = ARect[3],
AHeightCursor = ARectCursor[3];
if (isFirst) {
onEvents(EVENTS_DOWN, source, doClick);
delay(() => {
fire('change', theColor);
}, 1);
} else {
onEvents(EVENTS_DOWN, SV, doDownSV);
onEvents(EVENTS_DOWN, H, doDownH);
onEvents(EVENTS_DOWN, A, doDownA);
onEvents(EVENTS_MOVE, D, doMove);
onEvents(EVENTS_UP, D, doStop);
onEvents(EVENTS_RESIZE, W, doResize);
doFit();
}
doSetColor();
$.color = (r, g, b, a) => CP[isFunction(CP[state.color]) ? state.color : hex]([r, g, b, a]);
$.current = null;
$.enter = doEnter;
$.exit = doExit;
$.fit = doFit;
$.get = () => theValue();
$.pop = () => {
if (!source[name]) {
return $; // Already ejected
}
delete source[name];
offEvents(EVENTS_DOWN, source, doClick);
return doExit(), fire('pop', theColor);
};
$.set = (r, g, b, a) => {
theData = RGB2HSV([r, g, b, a]);
return doSetColor(), $;
};
$.self = self;
$.value = (r, g, b, a) => ($.set(r, g, b, a), fire('change', [r, g, b, a]));
}
doApply(1);
function doClick(e) {
if (hooks.focus) {
fire('focus', theColor);
} else {
let t = e.target,
isSource = source === getClosest(t, source);
if (isSource) {
!getParent(self) && doEnter(state.parent);
} else {
doExit();
}
}
}
return $;
}
CP[hex] = x => {
if (isString(x)) {
let count = (x = x.trim()).length;
if ((4 === count || 7 === count) && '#' === x[0]) {
if (/^#([a-f\d]{3}){1,2}$/i.test(x)) {
if (4 === count) {
return [toNumber(x[1] + x[1], 16), toNumber(x[2] + x[2], 16), toNumber(x[3] + x[3], 16), 1];
}
return [toNumber(x[1] + x[2], 16), toNumber(x[3] + x[4], 16), toNumber(x[5] + x[6], 16), 1];
}
} else if ((5 === count || 9 === count) && '#' === x[0]) {
if (/^#([a-f\d]{3,4}){1,2}$/i.test(x)) {
if (5 === count) {
return [toNumber(x[1] + x[1], 16), toNumber(x[2] + x[2], 16), toNumber(x[3] + x[3], 16), toNumber(x[4] + x[4], 16) / 255];
}
return [toNumber(x[1] + x[2], 16), toNumber(x[3] + x[4], 16), toNumber(x[5] + x[6], 16), toNumber(x[7] + x[8], 16) / 255];
}
}
return [0, 0, 0, 1]; // Default to black
}
return '#' + ('000000' + toString(+x[2] | +x[1] << 8 | +x[0] << 16, 16)).slice(-6) + (isSet(x[3]) && x[3] < 1 ? toString(toRound(x[3] * 255) + 0x10000, 16).substr(-2) : "");
};
CP.instances = {};
CP.state = {
'class': 'color-picker',
'color': hex,
'parent': null
};
CP.version = '2.2.1';
return CP;
});