extract colorconverter.js
This commit is contained in:
parent
1fe290fb8c
commit
807ea6aa70
|
@ -72,6 +72,7 @@
|
|||
<script src="vendor/codemirror/keymap/vim.js"></script>
|
||||
|
||||
<link href="vendor-overwrites/colorpicker/colorpicker.css" rel="stylesheet">
|
||||
<script src="vendor-overwrites/colorpicker/colorconverter.js"></script>
|
||||
<script src="vendor-overwrites/colorpicker/colorpicker.js"></script>
|
||||
<script src="vendor-overwrites/colorpicker/colorview.js"></script>
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
<script src="vendor/codemirror/addon/fold/brace-fold.js"></script>
|
||||
|
||||
<link href="vendor-overwrites/colorpicker/colorpicker.css" rel="stylesheet">
|
||||
<script src="vendor-overwrites/colorpicker/colorconverter.js"></script>
|
||||
<script src="vendor-overwrites/colorpicker/colorview.js"></script>
|
||||
|
||||
<script src="edit/codemirror-default.js"></script>
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var colorParser = (() => {
|
||||
const el = document.createElement('div');
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=14563
|
||||
document.head.appendChild(el);
|
||||
|
||||
function parseRGB(color) {
|
||||
const [r, g, b, a = 1] = color.match(/[.\d]+/g).map(Number);
|
||||
return {r, g, b, a};
|
||||
}
|
||||
|
||||
function parse(color) {
|
||||
el.style.color = color;
|
||||
if (el.style.color === '') {
|
||||
throw new Error(chrome.i18n.getMessage('styleMetaErrorColor', color));
|
||||
}
|
||||
color = getComputedStyle(el).color;
|
||||
el.style.color = '';
|
||||
return parseRGB(color);
|
||||
}
|
||||
|
||||
function format({r, g, b, a = 1}) {
|
||||
if (a === 1) {
|
||||
return `rgb(${r}, ${g}, ${b})`;
|
||||
}
|
||||
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
||||
}
|
||||
|
||||
function formatHex({r, g, b, a = null}) {
|
||||
let hex = '#' + (0x1000000 + (r << 16) + (g << 8) + (b | 0)).toString(16).substr(1);
|
||||
if (a !== null) {
|
||||
hex += (0x100 + Math.floor(a * 255)).toString(16).substr(1);
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
|
||||
return {parse, format, formatHex};
|
||||
})();
|
|
@ -1,4 +1,4 @@
|
|||
/* global loadScript mozParser semverCompare colorParser styleCodeEmpty */
|
||||
/* global loadScript mozParser semverCompare colorConverter styleCodeEmpty */
|
||||
'use strict';
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
|
@ -76,9 +76,10 @@ var usercss = (() => {
|
|||
}
|
||||
if (rgb) {
|
||||
if (vars[name].type === 'color') {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
const color = colorParser.parse(vars[name].value);
|
||||
return `${color.r}, ${color.g}, ${color.b}`;
|
||||
const color = colorConverter.parse(vars[name].value);
|
||||
if (!color) return null;
|
||||
const {r, g, b} = color;
|
||||
return `${r}, ${g}, ${b}`;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -545,7 +546,7 @@ var usercss = (() => {
|
|||
} else if (va.type === 'checkbox' && !/^[01]$/.test(va[value])) {
|
||||
throw new Error(chrome.i18n.getMessage('styleMetaErrorCheckbox'));
|
||||
} else if (va.type === 'color') {
|
||||
va[value] = colorParser.format(colorParser.parse(va[value]));
|
||||
va[value] = colorConverter.format(colorConverter.parse(va[value]), 'rgb');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,14 +27,14 @@
|
|||
"background/storage.js",
|
||||
"js/prefs.js",
|
||||
"js/script-loader.js",
|
||||
"js/color-parser.js",
|
||||
"js/usercss.js",
|
||||
"background/background.js",
|
||||
"background/usercss-helper.js",
|
||||
"background/style-via-api.js",
|
||||
"background/search-db.js",
|
||||
"background/update.js",
|
||||
"vendor/node-semver/semver.js"
|
||||
"vendor/node-semver/semver.js",
|
||||
"vendor-overwrites/colorpicker/colorconverter.js"
|
||||
]
|
||||
},
|
||||
"commands": {
|
||||
|
|
|
@ -141,6 +141,7 @@
|
|||
</template>
|
||||
|
||||
<link rel="stylesheet" href="vendor-overwrites/colorpicker/colorpicker.css">
|
||||
<script src="vendor-overwrites/colorpicker/colorconverter.js"></script>
|
||||
<script src="vendor-overwrites/colorpicker/colorpicker.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="msgbox/msgbox.css">
|
||||
|
|
318
vendor-overwrites/colorpicker/colorconverter.js
Normal file
318
vendor-overwrites/colorpicker/colorconverter.js
Normal file
|
@ -0,0 +1,318 @@
|
|||
'use strict';
|
||||
|
||||
const colorConverter = (() => {
|
||||
|
||||
return {
|
||||
parse,
|
||||
format,
|
||||
formatAlpha,
|
||||
RGBtoHSV,
|
||||
HSVtoRGB,
|
||||
HSLtoHSV,
|
||||
HSVtoHSL,
|
||||
constrainHue,
|
||||
snapToInt,
|
||||
// NAMED_COLORS is added below
|
||||
};
|
||||
|
||||
function format(color, type, hexUppercase) {
|
||||
const a = formatAlpha(color.a);
|
||||
const hasA = Boolean(a);
|
||||
if (type === 'rgb' && color.type === 'hsl') {
|
||||
color = HSVtoRGB(HSLtoHSV(color));
|
||||
}
|
||||
const {r, g, b, h, s, l} = color;
|
||||
switch (type) {
|
||||
case 'hex': {
|
||||
const rgbStr = (0x1000000 + (r << 16) + (g << 8) + (b | 0)).toString(16).slice(1);
|
||||
const aStr = hasA ? (0x100 + Math.round(a * 255)).toString(16).slice(1) : '';
|
||||
const hexStr = `#${rgbStr + aStr}`.replace(/^#(.)\1(.)\2(.)\3(?:(.)\4)?$/, '#$1$2$3$4');
|
||||
return hexUppercase ? hexStr.toUpperCase() : hexStr.toLowerCase();
|
||||
}
|
||||
case 'rgb':
|
||||
return hasA ?
|
||||
`rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${a})` :
|
||||
`rgb(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)})`;
|
||||
case 'hsl':
|
||||
return hasA ?
|
||||
`hsla(${h}, ${s}%, ${l}%, ${a})` :
|
||||
`hsl(${h}, ${s}%, ${l}%)`;
|
||||
}
|
||||
}
|
||||
|
||||
function parse(str) {
|
||||
if (typeof str !== 'string') return;
|
||||
str = str.trim();
|
||||
if (!str) return;
|
||||
|
||||
if (str[0] !== '#' && !str.includes('(')) {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
str = colorConverter.NAMED_COLORS.get(str);
|
||||
if (!str) return;
|
||||
}
|
||||
|
||||
if (str[0] === '#') {
|
||||
str = str.slice(1);
|
||||
const [r, g, b, a = 255] = str.length <= 4 ?
|
||||
str.match(/(.)/g).map(c => parseInt(c + c, 16)) :
|
||||
str.match(/(..)/g).map(c => parseInt(c, 16));
|
||||
return {type: 'hex', r, g, b, a: a === 255 ? undefined : a / 255};
|
||||
}
|
||||
|
||||
const [, type, value] = str.match(/^(rgb|hsl)a?\((.*?)\)|$/i);
|
||||
if (!type) return;
|
||||
|
||||
const comma = value.includes(',') && !value.includes('/');
|
||||
const num = value.split(comma ? /\s*,\s*/ : /\s+(?!\/)|\s*\/\s*/);
|
||||
if (num.length < 3 || num.length > 4) return;
|
||||
|
||||
let a = !num[3] ? 1 : parseFloat(num[3]) / (num[3].endsWith('%') ? 100 : 1);
|
||||
if (isNaN(a)) a = 1;
|
||||
|
||||
const first = num[0];
|
||||
if (/rgb/i.test(type)) {
|
||||
const k = first.endsWith('%') ? 2.55 : 1;
|
||||
const [r, g, b] = num.map(s => parseFloat(s) * k);
|
||||
return {type: 'rgb', r, g, b, a};
|
||||
} else {
|
||||
let h = parseFloat(first);
|
||||
if (first.endsWith('grad')) h *= 360 / 400;
|
||||
else if (first.endsWith('rad')) h *= 180 / Math.PI;
|
||||
else if (first.endsWith('turn')) h *= 360;
|
||||
const s = parseFloat(num[1]);
|
||||
const l = parseFloat(num[2]);
|
||||
return {type: 'hsl', h, s, l, a};
|
||||
}
|
||||
}
|
||||
|
||||
function formatAlpha(a) {
|
||||
return isNaN(a) ? '' :
|
||||
(a + .5e-6).toFixed(7).slice(0, -1).replace(/^0(?=\.[1-9])|^1\.0+?$|\.?0+$/g, '');
|
||||
}
|
||||
|
||||
function RGBtoHSV({r, g, b, a}) {
|
||||
r /= 255;
|
||||
g /= 255;
|
||||
b /= 255;
|
||||
const MaxC = Math.max(r, g, b);
|
||||
const MinC = Math.min(r, g, b);
|
||||
const DeltaC = MaxC - MinC;
|
||||
|
||||
let h =
|
||||
DeltaC === 0 ? 0 :
|
||||
MaxC === r ? 60 * (((g - b) / DeltaC) % 6) :
|
||||
MaxC === g ? 60 * (((b - r) / DeltaC) + 2) :
|
||||
MaxC === b ? 60 * (((r - g) / DeltaC) + 4) :
|
||||
0;
|
||||
h = constrainHue(h);
|
||||
return {
|
||||
h,
|
||||
s: MaxC === 0 ? 0 : DeltaC / MaxC,
|
||||
v: MaxC,
|
||||
a,
|
||||
};
|
||||
}
|
||||
|
||||
function HSVtoRGB({h, s, v}) {
|
||||
h = constrainHue(h) % 360;
|
||||
const C = s * v;
|
||||
const X = C * (1 - Math.abs((h / 60) % 2 - 1));
|
||||
const m = v - C;
|
||||
const [r, g, b] =
|
||||
h >= 0 && h < 60 ? [C, X, 0] :
|
||||
h >= 60 && h < 120 ? [X, C, 0] :
|
||||
h >= 120 && h < 180 ? [0, C, X] :
|
||||
h >= 180 && h < 240 ? [0, X, C] :
|
||||
h >= 240 && h < 300 ? [X, 0, C] :
|
||||
h >= 300 && h < 360 ? [C, 0, X] : [];
|
||||
return {
|
||||
r: snapToInt(Math.round((r + m) * 255)),
|
||||
g: snapToInt(Math.round((g + m) * 255)),
|
||||
b: snapToInt(Math.round((b + m) * 255)),
|
||||
};
|
||||
}
|
||||
|
||||
function HSLtoHSV({h, s, l, a}) {
|
||||
const t = s * (l < 50 ? l : 100 - l) / 100;
|
||||
return {
|
||||
h: constrainHue(h),
|
||||
s: t + l ? 200 * t / (t + l) / 100 : 0,
|
||||
v: (t + l) / 100,
|
||||
a,
|
||||
};
|
||||
}
|
||||
|
||||
function HSVtoHSL({h, s, v}) {
|
||||
const l = (2 - s) * v / 2;
|
||||
const t = l < .5 ? l * 2 : 2 - l * 2;
|
||||
return {
|
||||
h: Math.round(constrainHue(h)),
|
||||
s: Math.round(t ? s * v / t * 100 : 0),
|
||||
l: Math.round(l * 100),
|
||||
};
|
||||
}
|
||||
|
||||
function constrainHue(h) {
|
||||
return h < 0 ? h % 360 + 360 :
|
||||
h > 360 ? h % 360 :
|
||||
h;
|
||||
}
|
||||
|
||||
function snapToInt(num) {
|
||||
const int = Math.round(num);
|
||||
return Math.abs(int - num) < 1e-3 ? int : num;
|
||||
}
|
||||
})();
|
||||
|
||||
colorConverter.NAMED_COLORS = new Map([
|
||||
['transparent', 'rgba(0, 0, 0, 0)'],
|
||||
// CSS4 named colors
|
||||
['aliceblue', '#f0f8ff'],
|
||||
['antiquewhite', '#faebd7'],
|
||||
['aqua', '#00ffff'],
|
||||
['aquamarine', '#7fffd4'],
|
||||
['azure', '#f0ffff'],
|
||||
['beige', '#f5f5dc'],
|
||||
['bisque', '#ffe4c4'],
|
||||
['black', '#000000'],
|
||||
['blanchedalmond', '#ffebcd'],
|
||||
['blue', '#0000ff'],
|
||||
['blueviolet', '#8a2be2'],
|
||||
['brown', '#a52a2a'],
|
||||
['burlywood', '#deb887'],
|
||||
['cadetblue', '#5f9ea0'],
|
||||
['chartreuse', '#7fff00'],
|
||||
['chocolate', '#d2691e'],
|
||||
['coral', '#ff7f50'],
|
||||
['cornflowerblue', '#6495ed'],
|
||||
['cornsilk', '#fff8dc'],
|
||||
['crimson', '#dc143c'],
|
||||
['cyan', '#00ffff'],
|
||||
['darkblue', '#00008b'],
|
||||
['darkcyan', '#008b8b'],
|
||||
['darkgoldenrod', '#b8860b'],
|
||||
['darkgray', '#a9a9a9'],
|
||||
['darkgrey', '#a9a9a9'],
|
||||
['darkgreen', '#006400'],
|
||||
['darkkhaki', '#bdb76b'],
|
||||
['darkmagenta', '#8b008b'],
|
||||
['darkolivegreen', '#556b2f'],
|
||||
['darkorange', '#ff8c00'],
|
||||
['darkorchid', '#9932cc'],
|
||||
['darkred', '#8b0000'],
|
||||
['darksalmon', '#e9967a'],
|
||||
['darkseagreen', '#8fbc8f'],
|
||||
['darkslateblue', '#483d8b'],
|
||||
['darkslategray', '#2f4f4f'],
|
||||
['darkslategrey', '#2f4f4f'],
|
||||
['darkturquoise', '#00ced1'],
|
||||
['darkviolet', '#9400d3'],
|
||||
['deeppink', '#ff1493'],
|
||||
['deepskyblue', '#00bfff'],
|
||||
['dimgray', '#696969'],
|
||||
['dimgrey', '#696969'],
|
||||
['dodgerblue', '#1e90ff'],
|
||||
['firebrick', '#b22222'],
|
||||
['floralwhite', '#fffaf0'],
|
||||
['forestgreen', '#228b22'],
|
||||
['fuchsia', '#ff00ff'],
|
||||
['gainsboro', '#dcdcdc'],
|
||||
['ghostwhite', '#f8f8ff'],
|
||||
['gold', '#ffd700'],
|
||||
['goldenrod', '#daa520'],
|
||||
['gray', '#808080'],
|
||||
['grey', '#808080'],
|
||||
['green', '#008000'],
|
||||
['greenyellow', '#adff2f'],
|
||||
['honeydew', '#f0fff0'],
|
||||
['hotpink', '#ff69b4'],
|
||||
['indianred', '#cd5c5c'],
|
||||
['indigo', '#4b0082'],
|
||||
['ivory', '#fffff0'],
|
||||
['khaki', '#f0e68c'],
|
||||
['lavender', '#e6e6fa'],
|
||||
['lavenderblush', '#fff0f5'],
|
||||
['lawngreen', '#7cfc00'],
|
||||
['lemonchiffon', '#fffacd'],
|
||||
['lightblue', '#add8e6'],
|
||||
['lightcoral', '#f08080'],
|
||||
['lightcyan', '#e0ffff'],
|
||||
['lightgoldenrodyellow', '#fafad2'],
|
||||
['lightgray', '#d3d3d3'],
|
||||
['lightgrey', '#d3d3d3'],
|
||||
['lightgreen', '#90ee90'],
|
||||
['lightpink', '#ffb6c1'],
|
||||
['lightsalmon', '#ffa07a'],
|
||||
['lightseagreen', '#20b2aa'],
|
||||
['lightskyblue', '#87cefa'],
|
||||
['lightslategray', '#778899'],
|
||||
['lightslategrey', '#778899'],
|
||||
['lightsteelblue', '#b0c4de'],
|
||||
['lightyellow', '#ffffe0'],
|
||||
['lime', '#00ff00'],
|
||||
['limegreen', '#32cd32'],
|
||||
['linen', '#faf0e6'],
|
||||
['magenta', '#ff00ff'],
|
||||
['maroon', '#800000'],
|
||||
['mediumaquamarine', '#66cdaa'],
|
||||
['mediumblue', '#0000cd'],
|
||||
['mediumorchid', '#ba55d3'],
|
||||
['mediumpurple', '#9370db'],
|
||||
['mediumseagreen', '#3cb371'],
|
||||
['mediumslateblue', '#7b68ee'],
|
||||
['mediumspringgreen', '#00fa9a'],
|
||||
['mediumturquoise', '#48d1cc'],
|
||||
['mediumvioletred', '#c71585'],
|
||||
['midnightblue', '#191970'],
|
||||
['mintcream', '#f5fffa'],
|
||||
['mistyrose', '#ffe4e1'],
|
||||
['moccasin', '#ffe4b5'],
|
||||
['navajowhite', '#ffdead'],
|
||||
['navy', '#000080'],
|
||||
['oldlace', '#fdf5e6'],
|
||||
['olive', '#808000'],
|
||||
['olivedrab', '#6b8e23'],
|
||||
['orange', '#ffa500'],
|
||||
['orangered', '#ff4500'],
|
||||
['orchid', '#da70d6'],
|
||||
['palegoldenrod', '#eee8aa'],
|
||||
['palegreen', '#98fb98'],
|
||||
['paleturquoise', '#afeeee'],
|
||||
['palevioletred', '#db7093'],
|
||||
['papayawhip', '#ffefd5'],
|
||||
['peachpuff', '#ffdab9'],
|
||||
['peru', '#cd853f'],
|
||||
['pink', '#ffc0cb'],
|
||||
['plum', '#dda0dd'],
|
||||
['powderblue', '#b0e0e6'],
|
||||
['purple', '#800080'],
|
||||
['rebeccapurple', '#663399'],
|
||||
['red', '#ff0000'],
|
||||
['rosybrown', '#bc8f8f'],
|
||||
['royalblue', '#4169e1'],
|
||||
['saddlebrown', '#8b4513'],
|
||||
['salmon', '#fa8072'],
|
||||
['sandybrown', '#f4a460'],
|
||||
['seagreen', '#2e8b57'],
|
||||
['seashell', '#fff5ee'],
|
||||
['sienna', '#a0522d'],
|
||||
['silver', '#c0c0c0'],
|
||||
['skyblue', '#87ceeb'],
|
||||
['slateblue', '#6a5acd'],
|
||||
['slategray', '#708090'],
|
||||
['slategrey', '#708090'],
|
||||
['snow', '#fffafa'],
|
||||
['springgreen', '#00ff7f'],
|
||||
['steelblue', '#4682b4'],
|
||||
['tan', '#d2b48c'],
|
||||
['teal', '#008080'],
|
||||
['thistle', '#d8bfd8'],
|
||||
['tomato', '#ff6347'],
|
||||
['turquoise', '#40e0d0'],
|
||||
['violet', '#ee82ee'],
|
||||
['wheat', '#f5deb3'],
|
||||
['white', '#ffffff'],
|
||||
['whitesmoke', '#f5f5f5'],
|
||||
['yellow', '#ffff00'],
|
||||
['yellowgreen', '#9acd32'],
|
||||
]);
|
|
@ -1,4 +1,4 @@
|
|||
/* global CodeMirror NAMED_COLORS */
|
||||
/* global CodeMirror colorConverter */
|
||||
'use strict';
|
||||
|
||||
(window.CodeMirror ? window.CodeMirror.prototype : window).colorpicker = function () {
|
||||
|
@ -57,8 +57,6 @@
|
|||
hide,
|
||||
setColor,
|
||||
getColor,
|
||||
stringToColor,
|
||||
colorToString,
|
||||
options,
|
||||
};
|
||||
return PUBLIC_API;
|
||||
|
@ -178,7 +176,7 @@
|
|||
Object.defineProperty($inputs.hsl, 'color', {get: inputsToHSL});
|
||||
Object.defineProperty($inputs, 'color', {get: () => $inputs[currentFormat].color});
|
||||
|
||||
HUE_COLORS.forEach(color => Object.assign(color, stringToColor(color.hex)));
|
||||
HUE_COLORS.forEach(color => Object.assign(color, colorConverter.parse(color.hex)));
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
@ -235,7 +233,7 @@
|
|||
function setColor(color) {
|
||||
switch (typeof color) {
|
||||
case 'string':
|
||||
color = stringToColor(color);
|
||||
color = colorConverter.parse(color);
|
||||
break;
|
||||
case 'object': {
|
||||
const {r, g, b, a} = color;
|
||||
|
@ -267,7 +265,9 @@
|
|||
return;
|
||||
}
|
||||
readCurrentColorFromRamps();
|
||||
const color = type === 'hsl' ? HSVtoHSL(HSV) : HSVtoRGB(HSV);
|
||||
const color = type === 'hsl' ?
|
||||
colorConverter.HSVtoHSL(HSV) :
|
||||
colorConverter.HSVtoRGB(HSV);
|
||||
return type ? colorToString(color, type) : color;
|
||||
}
|
||||
|
||||
|
@ -279,7 +279,7 @@
|
|||
HSV.h = HSV.s = HSV.v = 0;
|
||||
} else {
|
||||
const {x, y} = dragging.saturationPointerPos;
|
||||
HSV.h = snapToInt((dragging.hueKnobPos / $hue.offsetWidth) * 360);
|
||||
HSV.h = colorConverter.snapToInt((dragging.hueKnobPos / $hue.offsetWidth) * 360);
|
||||
HSV.s = x / $sat.offsetWidth;
|
||||
HSV.v = ($sat.offsetHeight - y) / $sat.offsetHeight;
|
||||
}
|
||||
|
@ -304,7 +304,7 @@
|
|||
function setFromHueElement(event) {
|
||||
const {left, width} = getScreenBounds($hue);
|
||||
const currentX = event ? getTouchPosition(event).clientX :
|
||||
left + width * constrainHue(HSV.h) / 360;
|
||||
left + width * colorConverter.constrainHue(HSV.h) / 360;
|
||||
const normalizedH = constrain(0, 1, (currentX - left) / width);
|
||||
const x = dragging.hueKnobPos = width * normalizedH;
|
||||
$hueKnob.style.left = (x - Math.round($hueKnob.offsetWidth / 2)) + 'px';
|
||||
|
@ -443,9 +443,11 @@
|
|||
//region State-to-DOM
|
||||
|
||||
function setFromColor(color) {
|
||||
color = typeof color === 'string' ? stringToColor(color) : color;
|
||||
color = color || stringToColor('#f00');
|
||||
const newHSV = color.type === 'hsl' ? HSLtoHSV(color) : RGBtoHSV(color);
|
||||
color = typeof color === 'string' ? colorConverter.parse(color) : color;
|
||||
color = color || colorConverter.parse('#f00');
|
||||
const newHSV = color.type === 'hsl' ?
|
||||
colorConverter.HSLtoHSV(color) :
|
||||
colorConverter.RGBtoHSV(color);
|
||||
if (Object.keys(newHSV).every(k => Math.abs(newHSV[k] - HSV[k]) < 1e-3)) {
|
||||
return;
|
||||
}
|
||||
|
@ -489,7 +491,7 @@
|
|||
}
|
||||
|
||||
function renderInputs() {
|
||||
const rgb = HSVtoRGB(HSV);
|
||||
const rgb = colorConverter.HSVtoRGB(HSV);
|
||||
switch (currentFormat) {
|
||||
case 'hex':
|
||||
$hexCode.value = colorToString(rgb, 'hex');
|
||||
|
@ -502,7 +504,7 @@
|
|||
break;
|
||||
}
|
||||
case 'hsl': {
|
||||
const {h, s, l} = HSVtoHSL(HSV);
|
||||
const {h, s, l} = colorConverter.HSVtoHSL(HSV);
|
||||
$hsl.h.value = h;
|
||||
$hsl.s.value = s;
|
||||
$hsl.l.value = l;
|
||||
|
@ -723,144 +725,17 @@
|
|||
//region Color conversion utilities
|
||||
|
||||
function colorToString(color, type = currentFormat) {
|
||||
const a = alphaToString(color.a);
|
||||
const hasA = Boolean(a);
|
||||
if (type === 'rgb' && color.type === 'hsl') {
|
||||
color = HSVtoRGB(HSLtoHSV(color));
|
||||
}
|
||||
const {r, g, b, h, s, l} = color;
|
||||
switch (type) {
|
||||
case 'hex': {
|
||||
const rgbStr = (0x1000000 + (r << 16) + (g << 8) + (b | 0)).toString(16).slice(1);
|
||||
const aStr = hasA ? (0x100 + Math.round(a * 255)).toString(16).slice(1) : '';
|
||||
const hexStr = `#${rgbStr + aStr}`.replace(/^#(.)\1(.)\2(.)\3(?:(.)\4)?$/, '#$1$2$3$4');
|
||||
return options.hexUppercase ? hexStr.toUpperCase() : hexStr.toLowerCase();
|
||||
}
|
||||
case 'rgb':
|
||||
return hasA ?
|
||||
`rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${a})` :
|
||||
`rgb(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)})`;
|
||||
case 'hsl':
|
||||
return hasA ?
|
||||
`hsla(${h}, ${s}%, ${l}%, ${a})` :
|
||||
`hsl(${h}, ${s}%, ${l}%)`;
|
||||
}
|
||||
return colorConverter.format(color, type, options.hexUppercase);
|
||||
}
|
||||
|
||||
function stringToColor(str) {
|
||||
if (typeof str !== 'string') return;
|
||||
str = str.trim();
|
||||
if (!str) return;
|
||||
|
||||
if (str[0] !== '#' && !str.includes('(')) {
|
||||
str = NAMED_COLORS.get(str);
|
||||
if (!str) return;
|
||||
}
|
||||
|
||||
if (str[0] === '#') {
|
||||
str = str.slice(1);
|
||||
const [r, g, b, a = 255] = str.length <= 4 ?
|
||||
str.match(/(.)/g).map(c => parseInt(c + c, 16)) :
|
||||
str.match(/(..)/g).map(c => parseInt(c, 16));
|
||||
return {type: 'hex', r, g, b, a: a === 255 ? undefined : a / 255};
|
||||
}
|
||||
|
||||
const [, type, value] = str.match(/^(rgb|hsl)a?\((.*?)\)|$/i);
|
||||
if (!type) return;
|
||||
|
||||
const comma = value.includes(',') && !value.includes('/');
|
||||
const num = value.split(comma ? /\s*,\s*/ : /\s+(?!\/)|\s*\/\s*/);
|
||||
if (num.length < 3 || num.length > 4) return;
|
||||
|
||||
let a = !num[3] ? 1 : parseFloat(num[3]) / (num[3].endsWith('%') ? 100 : 1);
|
||||
if (isNaN(a)) a = 1;
|
||||
|
||||
const first = num[0];
|
||||
if (/rgb/i.test(type)) {
|
||||
const k = first.endsWith('%') ? 2.55 : 1;
|
||||
const [r, g, b] = num.map(s => parseFloat(s) * k);
|
||||
return {type: 'rgb', r, g, b, a};
|
||||
} else {
|
||||
let h = parseFloat(first);
|
||||
if (first.endsWith('grad')) h *= 360 / 400;
|
||||
else if (first.endsWith('rad')) h *= 180 / Math.PI;
|
||||
else if (first.endsWith('turn')) h *= 360;
|
||||
const s = parseFloat(num[1]);
|
||||
const l = parseFloat(num[2]);
|
||||
return {type: 'hsl', h, s, l, a};
|
||||
}
|
||||
}
|
||||
|
||||
function constrainHue(h) {
|
||||
return h < 0 ? h % 360 + 360 :
|
||||
h > 360 ? h % 360 :
|
||||
h;
|
||||
}
|
||||
|
||||
function RGBtoHSV({r, g, b, a}) {
|
||||
r /= 255;
|
||||
g /= 255;
|
||||
b /= 255;
|
||||
const MaxC = Math.max(r, g, b);
|
||||
const MinC = Math.min(r, g, b);
|
||||
const DeltaC = MaxC - MinC;
|
||||
|
||||
let h =
|
||||
DeltaC === 0 ? 0 :
|
||||
MaxC === r ? 60 * (((g - b) / DeltaC) % 6) :
|
||||
MaxC === g ? 60 * (((b - r) / DeltaC) + 2) :
|
||||
MaxC === b ? 60 * (((r - g) / DeltaC) + 4) :
|
||||
0;
|
||||
h = constrainHue(h);
|
||||
return {
|
||||
h,
|
||||
s: MaxC === 0 ? 0 : DeltaC / MaxC,
|
||||
v: MaxC,
|
||||
a,
|
||||
};
|
||||
}
|
||||
|
||||
function HSVtoRGB({h, s, v}) {
|
||||
h = constrainHue(h) % 360;
|
||||
const C = s * v;
|
||||
const X = C * (1 - Math.abs((h / 60) % 2 - 1));
|
||||
const m = v - C;
|
||||
const [r, g, b] =
|
||||
h >= 0 && h < 60 ? [C, X, 0] :
|
||||
h >= 60 && h < 120 ? [X, C, 0] :
|
||||
h >= 120 && h < 180 ? [0, C, X] :
|
||||
h >= 180 && h < 240 ? [0, X, C] :
|
||||
h >= 240 && h < 300 ? [X, 0, C] :
|
||||
h >= 300 && h < 360 ? [C, 0, X] : [];
|
||||
return {
|
||||
r: snapToInt(Math.round((r + m) * 255)),
|
||||
g: snapToInt(Math.round((g + m) * 255)),
|
||||
b: snapToInt(Math.round((b + m) * 255)),
|
||||
};
|
||||
}
|
||||
|
||||
function HSLtoHSV({h, s, l, a}) {
|
||||
const t = s * (l < 50 ? l : 100 - l) / 100;
|
||||
return {
|
||||
h: constrainHue(h),
|
||||
s: t + l ? 200 * t / (t + l) / 100 : 0,
|
||||
v: (t + l) / 100,
|
||||
a,
|
||||
};
|
||||
}
|
||||
|
||||
function HSVtoHSL({h, s, v}) {
|
||||
const l = (2 - s) * v / 2;
|
||||
const t = l < .5 ? l * 2 : 2 - l * 2;
|
||||
return {
|
||||
h: Math.round(constrainHue(h)),
|
||||
s: Math.round(t ? s * v / t * 100 : 0),
|
||||
l: Math.round(l * 100),
|
||||
};
|
||||
function alphaToString(a = HSV.a) {
|
||||
return colorConverter.formatAlpha(a);
|
||||
}
|
||||
|
||||
function currentColorToString(format = currentFormat, alpha = HSV.a) {
|
||||
const converted = format === 'hsl' ? HSVtoHSL(HSV) : HSVtoRGB(HSV);
|
||||
const converted = format === 'hsl' ?
|
||||
colorConverter.HSVtoHSL(HSV) :
|
||||
colorConverter.HSVtoRGB(HSV);
|
||||
converted.a = isNaN(alpha) || alpha === 1 ? undefined : alpha;
|
||||
return colorToString(converted, format);
|
||||
}
|
||||
|
@ -887,10 +762,6 @@
|
|||
return HUE_COLORS[0].hex;
|
||||
}
|
||||
|
||||
function alphaToString(a = HSV.a) {
|
||||
return isNaN(a) ? '' : (a + .5e-6).toFixed(7).slice(0, -1).replace(/^0(?=\.[1-9])|^1\.0+?$|\.?0+$/g, '');
|
||||
}
|
||||
|
||||
//endregion
|
||||
//region Miscellaneous utilities
|
||||
|
||||
|
@ -964,11 +835,6 @@
|
|||
return value < min ? min : value > max ? max : value;
|
||||
}
|
||||
|
||||
function snapToInt(num) {
|
||||
const int = Math.round(num);
|
||||
return Math.abs(int - num) < 1e-3 ? int : num;
|
||||
}
|
||||
|
||||
function parseAs(el, parser) {
|
||||
const num = parser(el.value);
|
||||
if (!isNaN(num) &&
|
||||
|
|
|
@ -1,159 +1,6 @@
|
|||
/* global CodeMirror */
|
||||
/* global CodeMirror colorConverter */
|
||||
'use strict';
|
||||
|
||||
const NAMED_COLORS = new Map([
|
||||
['transparent', 'rgba(0, 0, 0, 0)'],
|
||||
// CSS4 named colors
|
||||
['aliceblue', '#f0f8ff'],
|
||||
['antiquewhite', '#faebd7'],
|
||||
['aqua', '#00ffff'],
|
||||
['aquamarine', '#7fffd4'],
|
||||
['azure', '#f0ffff'],
|
||||
['beige', '#f5f5dc'],
|
||||
['bisque', '#ffe4c4'],
|
||||
['black', '#000000'],
|
||||
['blanchedalmond', '#ffebcd'],
|
||||
['blue', '#0000ff'],
|
||||
['blueviolet', '#8a2be2'],
|
||||
['brown', '#a52a2a'],
|
||||
['burlywood', '#deb887'],
|
||||
['cadetblue', '#5f9ea0'],
|
||||
['chartreuse', '#7fff00'],
|
||||
['chocolate', '#d2691e'],
|
||||
['coral', '#ff7f50'],
|
||||
['cornflowerblue', '#6495ed'],
|
||||
['cornsilk', '#fff8dc'],
|
||||
['crimson', '#dc143c'],
|
||||
['cyan', '#00ffff'],
|
||||
['darkblue', '#00008b'],
|
||||
['darkcyan', '#008b8b'],
|
||||
['darkgoldenrod', '#b8860b'],
|
||||
['darkgray', '#a9a9a9'],
|
||||
['darkgrey', '#a9a9a9'],
|
||||
['darkgreen', '#006400'],
|
||||
['darkkhaki', '#bdb76b'],
|
||||
['darkmagenta', '#8b008b'],
|
||||
['darkolivegreen', '#556b2f'],
|
||||
['darkorange', '#ff8c00'],
|
||||
['darkorchid', '#9932cc'],
|
||||
['darkred', '#8b0000'],
|
||||
['darksalmon', '#e9967a'],
|
||||
['darkseagreen', '#8fbc8f'],
|
||||
['darkslateblue', '#483d8b'],
|
||||
['darkslategray', '#2f4f4f'],
|
||||
['darkslategrey', '#2f4f4f'],
|
||||
['darkturquoise', '#00ced1'],
|
||||
['darkviolet', '#9400d3'],
|
||||
['deeppink', '#ff1493'],
|
||||
['deepskyblue', '#00bfff'],
|
||||
['dimgray', '#696969'],
|
||||
['dimgrey', '#696969'],
|
||||
['dodgerblue', '#1e90ff'],
|
||||
['firebrick', '#b22222'],
|
||||
['floralwhite', '#fffaf0'],
|
||||
['forestgreen', '#228b22'],
|
||||
['fuchsia', '#ff00ff'],
|
||||
['gainsboro', '#dcdcdc'],
|
||||
['ghostwhite', '#f8f8ff'],
|
||||
['gold', '#ffd700'],
|
||||
['goldenrod', '#daa520'],
|
||||
['gray', '#808080'],
|
||||
['grey', '#808080'],
|
||||
['green', '#008000'],
|
||||
['greenyellow', '#adff2f'],
|
||||
['honeydew', '#f0fff0'],
|
||||
['hotpink', '#ff69b4'],
|
||||
['indianred', '#cd5c5c'],
|
||||
['indigo', '#4b0082'],
|
||||
['ivory', '#fffff0'],
|
||||
['khaki', '#f0e68c'],
|
||||
['lavender', '#e6e6fa'],
|
||||
['lavenderblush', '#fff0f5'],
|
||||
['lawngreen', '#7cfc00'],
|
||||
['lemonchiffon', '#fffacd'],
|
||||
['lightblue', '#add8e6'],
|
||||
['lightcoral', '#f08080'],
|
||||
['lightcyan', '#e0ffff'],
|
||||
['lightgoldenrodyellow', '#fafad2'],
|
||||
['lightgray', '#d3d3d3'],
|
||||
['lightgrey', '#d3d3d3'],
|
||||
['lightgreen', '#90ee90'],
|
||||
['lightpink', '#ffb6c1'],
|
||||
['lightsalmon', '#ffa07a'],
|
||||
['lightseagreen', '#20b2aa'],
|
||||
['lightskyblue', '#87cefa'],
|
||||
['lightslategray', '#778899'],
|
||||
['lightslategrey', '#778899'],
|
||||
['lightsteelblue', '#b0c4de'],
|
||||
['lightyellow', '#ffffe0'],
|
||||
['lime', '#00ff00'],
|
||||
['limegreen', '#32cd32'],
|
||||
['linen', '#faf0e6'],
|
||||
['magenta', '#ff00ff'],
|
||||
['maroon', '#800000'],
|
||||
['mediumaquamarine', '#66cdaa'],
|
||||
['mediumblue', '#0000cd'],
|
||||
['mediumorchid', '#ba55d3'],
|
||||
['mediumpurple', '#9370db'],
|
||||
['mediumseagreen', '#3cb371'],
|
||||
['mediumslateblue', '#7b68ee'],
|
||||
['mediumspringgreen', '#00fa9a'],
|
||||
['mediumturquoise', '#48d1cc'],
|
||||
['mediumvioletred', '#c71585'],
|
||||
['midnightblue', '#191970'],
|
||||
['mintcream', '#f5fffa'],
|
||||
['mistyrose', '#ffe4e1'],
|
||||
['moccasin', '#ffe4b5'],
|
||||
['navajowhite', '#ffdead'],
|
||||
['navy', '#000080'],
|
||||
['oldlace', '#fdf5e6'],
|
||||
['olive', '#808000'],
|
||||
['olivedrab', '#6b8e23'],
|
||||
['orange', '#ffa500'],
|
||||
['orangered', '#ff4500'],
|
||||
['orchid', '#da70d6'],
|
||||
['palegoldenrod', '#eee8aa'],
|
||||
['palegreen', '#98fb98'],
|
||||
['paleturquoise', '#afeeee'],
|
||||
['palevioletred', '#db7093'],
|
||||
['papayawhip', '#ffefd5'],
|
||||
['peachpuff', '#ffdab9'],
|
||||
['peru', '#cd853f'],
|
||||
['pink', '#ffc0cb'],
|
||||
['plum', '#dda0dd'],
|
||||
['powderblue', '#b0e0e6'],
|
||||
['purple', '#800080'],
|
||||
['rebeccapurple', '#663399'],
|
||||
['red', '#ff0000'],
|
||||
['rosybrown', '#bc8f8f'],
|
||||
['royalblue', '#4169e1'],
|
||||
['saddlebrown', '#8b4513'],
|
||||
['salmon', '#fa8072'],
|
||||
['sandybrown', '#f4a460'],
|
||||
['seagreen', '#2e8b57'],
|
||||
['seashell', '#fff5ee'],
|
||||
['sienna', '#a0522d'],
|
||||
['silver', '#c0c0c0'],
|
||||
['skyblue', '#87ceeb'],
|
||||
['slateblue', '#6a5acd'],
|
||||
['slategray', '#708090'],
|
||||
['slategrey', '#708090'],
|
||||
['snow', '#fffafa'],
|
||||
['springgreen', '#00ff7f'],
|
||||
['steelblue', '#4682b4'],
|
||||
['tan', '#d2b48c'],
|
||||
['teal', '#008080'],
|
||||
['thistle', '#d8bfd8'],
|
||||
['tomato', '#ff6347'],
|
||||
['turquoise', '#40e0d0'],
|
||||
['violet', '#ee82ee'],
|
||||
['wheat', '#f5deb3'],
|
||||
['white', '#ffffff'],
|
||||
['whitesmoke', '#f5f5f5'],
|
||||
['yellow', '#ffff00'],
|
||||
['yellowgreen', '#9acd32'],
|
||||
]);
|
||||
|
||||
(() => {
|
||||
//region Constants
|
||||
|
||||
|
@ -193,8 +40,12 @@ const NAMED_COLORS = new Map([
|
|||
!CSS.supports('color', 'hsl(1turn, 2%, 3%)') && /deg|g?rad|turn/,
|
||||
].filter(Boolean).map(rx => rx.source).join('|') || '^$', 'i'),
|
||||
};
|
||||
const RX_DETECT = new RegExp('(^|[\\s():,/])(' + RX_COLOR.hex.source +
|
||||
'|(?:rgb|hsl)a?(?=\\()|(?:' + [...NAMED_COLORS.keys()].join('|') + ')(?=[\\s;()/]|$))', 'gi');
|
||||
const RX_DETECT = new RegExp('(^|[\\s():,/])' +
|
||||
'(' +
|
||||
RX_COLOR.hex.source + '|' +
|
||||
'(?:rgb|hsl)a?(?=\\()|(?:' + [...colorConverter.NAMED_COLORS.keys()].join('|') + ')' +
|
||||
'(?=[\\s;()/]|$)' +
|
||||
')', 'gi');
|
||||
const RX_DETECT_FUNC = /(rgb|hsl)a?\(/iy;
|
||||
|
||||
const RX_COMMENT = /\/\*(?:.(?!\*\/))*(?:.?\*\/|$)/g;
|
||||
|
@ -532,7 +383,7 @@ const NAMED_COLORS = new Map([
|
|||
|
||||
function checkColor() {
|
||||
if (isHex) return testAt(RX_COLOR.hex, 0, color);
|
||||
if (!isFunc) return NAMED_COLORS.has(color.toLowerCase());
|
||||
if (!isFunc) return colorConverter.NAMED_COLORS.has(color.toLowerCase());
|
||||
|
||||
const colorLower = color.toLowerCase();
|
||||
if (cache.has(colorLower)) return true;
|
||||
|
@ -558,8 +409,8 @@ const NAMED_COLORS = new Map([
|
|||
function getSafeColorValue() {
|
||||
if (isHex && color.length !== 5 && color.length !== 9) return color;
|
||||
if (!isFunc || !RX_COLOR.unsupported.test(color)) return color;
|
||||
const value = state.popup.stringToColor(color);
|
||||
return state.popup.colorToString(value, 'rgb');
|
||||
const value = colorConverter.parse(color);
|
||||
return colorConverter.format(value, 'rgb');
|
||||
}
|
||||
|
||||
// update or skip or delete existing swatches
|
||||
|
@ -734,7 +585,7 @@ const NAMED_COLORS = new Map([
|
|||
const value = color.slice(token.length + 1, -1);
|
||||
return testAt(RX_COLOR[type], 0, value) && color;
|
||||
}
|
||||
return (token[0] === '#' || NAMED_COLORS.has(token)) && token;
|
||||
return (token[0] === '#' || colorConverter.NAMED_COLORS.has(token)) && token;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user