From 807ea6aa70aa36f5cadb14e00138687fbbfe885d Mon Sep 17 00:00:00 2001 From: tophf Date: Sun, 7 Jan 2018 11:20:55 +0300 Subject: [PATCH] extract colorconverter.js --- edit.html | 1 + install-usercss.html | 1 + js/color-parser.js | 40 --- js/usercss.js | 11 +- manifest.json | 4 +- popup.html | 1 + .../colorpicker/colorconverter.js | 318 ++++++++++++++++++ vendor-overwrites/colorpicker/colorpicker.js | 176 ++-------- vendor-overwrites/colorpicker/colorview.js | 171 +--------- 9 files changed, 361 insertions(+), 362 deletions(-) delete mode 100644 js/color-parser.js create mode 100644 vendor-overwrites/colorpicker/colorconverter.js diff --git a/edit.html b/edit.html index 50b6c57b..19375978 100644 --- a/edit.html +++ b/edit.html @@ -72,6 +72,7 @@ + diff --git a/install-usercss.html b/install-usercss.html index 8aac40de..047f8918 100644 --- a/install-usercss.html +++ b/install-usercss.html @@ -35,6 +35,7 @@ + diff --git a/js/color-parser.js b/js/color-parser.js deleted file mode 100644 index 29e7eda8..00000000 --- a/js/color-parser.js +++ /dev/null @@ -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}; -})(); diff --git a/js/usercss.js b/js/usercss.js index a8823751..8d18b16f 100644 --- a/js/usercss.js +++ b/js/usercss.js @@ -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'); } } diff --git a/manifest.json b/manifest.json index f5233c18..83e92fda 100644 --- a/manifest.json +++ b/manifest.json @@ -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": { diff --git a/popup.html b/popup.html index 12f9b0e9..edca583b 100644 --- a/popup.html +++ b/popup.html @@ -141,6 +141,7 @@ + diff --git a/vendor-overwrites/colorpicker/colorconverter.js b/vendor-overwrites/colorpicker/colorconverter.js new file mode 100644 index 00000000..45808ff1 --- /dev/null +++ b/vendor-overwrites/colorpicker/colorconverter.js @@ -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'], +]); diff --git a/vendor-overwrites/colorpicker/colorpicker.js b/vendor-overwrites/colorpicker/colorpicker.js index fac862e1..3bb15863 100644 --- a/vendor-overwrites/colorpicker/colorpicker.js +++ b/vendor-overwrites/colorpicker/colorpicker.js @@ -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) && diff --git a/vendor-overwrites/colorpicker/colorview.js b/vendor-overwrites/colorpicker/colorview.js index ab088665..f6750713 100644 --- a/vendor-overwrites/colorpicker/colorview.js +++ b/vendor-overwrites/colorpicker/colorview.js @@ -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; } }