From d3fd42026e2844c98c0d2d69f1aaa01302744400 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Sun, 30 Sep 2012 19:51:10 +0200 Subject: [PATCH] Add support for HSL color values. Closes #25. --- chrome/content/color-picker.js | 83 +++-------- chrome/content/firepicker.js | 243 +++++++++++++++++++++++++++++---- 2 files changed, 238 insertions(+), 88 deletions(-) diff --git a/chrome/content/color-picker.js b/chrome/content/color-picker.js index d917112..0e10e1d 100644 --- a/chrome/content/color-picker.js +++ b/chrome/content/color-picker.js @@ -12,61 +12,13 @@ var stopEvent = function(e) { e.stopPropagation(); }; -var ColorConverter = { - HSV2RGB: function(h, s, v, a) { - if (h + 0.0000000001 >= 1) {h = 0} - h *= 6; - - var i = parseInt(h, 10), - f = h - i, - p = v * (1 - s), - q = v * (1 - s * f), - t = v * (1 - s * (1 - f)), - r, g, b; - - switch (i) { - 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 new Color(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), a && (Math.round(a * 100) / 100)); - }, - - HSV2RGBString: function(h, s, v, a) { - return this.HSV2RGB(h, s, v, a).toString(); - }, - - RGB2HSV: function(rgb) { - var r = rgb.r, g = rgb.g, b = rgb.b, a = rgb.a; - - var max = Math.max(r, g, b), - min = Math.min(r, g, b), - delta = max - min, - s = (max === 0) ? 0 : 1-(min/max), - v = max, h; - - switch (max) { - case min: h=0; break; - case r: h=(g-b)/delta; - if (g= 1) {h = 0} + h *= 6; + + var i = parseInt(h, 10), + f = h - i, + p = v * (1 - s), + q = v * (1 - s * f), + t = v * (1 - s * (1 - f)), + r, g, b; + + switch (i) { + 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 new Color.RGB(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), this.a); + }, + + toHSL: function() { + var h = this.v1, s = this.v2, v = this.v3, a = this.a, + newL = (2 - s) * v, + newS = (s * v) / (newL <= 1 ? newL : 2 - newL); + + return new Color.HSL(h, isNaN(newS) ? 0 : newS, newL / 2, this.a); + }, + + setH: function(h) { + this.v1 = h; + }, + + getH: function() { + return this.v1; + }, + + setS: function(s) { + this.v2 = s; + }, + + getS: function() { + return this.v2; + }, + + setV: function(v) { + this.v3 = v; + }, + + getV: function() { + return this.v3; + }, + + setA: function(a) { + this.a = a; + }, + + getA: function() { + return this.a; + } +}); + var ColorValue = function(cssValueObj, translation) { - this.value = cssValueObj.value; + this.cssValueObj = cssValueObj; this.translation = translation; - this.start = cssValueObj.start; - this.end = cssValueObj.end; }; ColorValue.prototype = { - rgbSplitter: /^rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})(?:,\s*([\d.]+))?\s*\)$/i, + bracketedSplitter: /^(rgb|hsl)a?\((\d{1,3})(%?),\s*(\d{1,3})(%?),\s*(\d{1,3})(%?)(?:,\s*([\d.]+))?\s*\)$/i, hexColor: /^#([\da-f]{3}|[\da-f]{6})$/i, - noColor: new Color(), + noColor: new Color.RGB(), preparePrefixSuffix: function(wholeCssValue) { - this.prefix = wholeCssValue.substring(0, this.start); - this.suffix = wholeCssValue.substring(this.end + 1); + this.prefix = wholeCssValue.substring(0, this.cssValueObj.start); + this.suffix = wholeCssValue.substring(this.cssValueObj.end + 1); }, toNewWholeCssValue: function(newColorString) { return this.prefix + newColorString + this.suffix; }, - toRGB: function() { - var hexValue = this.tryToGrabHexColorString(); - return (hexValue ? this.hex2RGB(hexValue) : this.parseRGBString()) || this.noColor; + toColor: function() { + var color, hexValue; + if (this.translation) { + color = this.hex2RGB(this.translation); + } else if (this.cssValueObj.type == 'rgb' && (hexValue = this.tryToGrabHexColorString())) { + color = this.hex2RGB(hexValue); + } else { + color = this.parseBracketedColor(); + } + return color || this.noColor; }, tryToGrabHexColorString: function() { var match; - return this.translation || ((match = this.value.match(this.hexColor)) && match[1]); + return (match = this.getValue().match(this.hexColor)) && match[1]; }, - parseRGBString: function(rgbString) { - var match = this.value.match(this.rgbSplitter); + parseBracketedColor: function() { + var match = this.cssValueObj.value.match(this.bracketedSplitter); if (match) { - return new Color(parseInt(match[1], 10), parseInt(match[2], 10), parseInt(match[3], 10), match[4]); + var colorType = match[1].toUpperCase(), v1 = parseInt(match[2], 10), v2 = parseInt(match[4], 10), v3 = parseInt(match[6], 10); + if (colorType == 'RGB') { + // convert percentages into byte values (0-255) + if (match[3]) { v1 = Math.round(v1 * 2.55); } + if (match[5]) { v2 = Math.round(v2 * 2.55); } + if (match[7]) { v3 = Math.round(v3 * 2.55); } + } else if (colorType == 'HSL') { + // Color.HSL expects its values in the 0-1 range + v1 /= 360; + v2 /= 100; + v3 /= 100; + } + return new Color[colorType](v1, v2, v3, match[8]); } }, hex2RGB: function(hex) { if (hex.length == 3) { hex = hex.replace(/(.)/g, '$1$1'); } var val = parseInt(hex, 16); - return new Color((val & 0xFF0000) >> 16, (val & 0xFF00) >> 8, val & 0xFF); + return new Color.RGB((val & 0xFF0000) >> 16, (val & 0xFF00) >> 8, val & 0xFF); + }, + + getValue: function() { + return this.cssValueObj.value; } }; ColorValue.newIfColor = function(cssValue) { - var hexTranslation; - if (cssValue.type == 'rgb' || (hexTranslation = colorNames[cssValue.value.toLowerCase()])) { + var type = cssValue.type, hexTranslation; + if (type == 'rgb' || type == 'hsl' || (hexTranslation = colorNames[cssValue.value.toLowerCase()])) { return new ColorValue(cssValue, hexTranslation); } }; @@ -243,7 +432,7 @@ ColorsDropDown.prototype = { }, addColorCell: function(colorsList, colorValue) { - var newCell = this.tags.valueCell.append({color: colorValue.value}, colorsList); + var newCell = this.tags.valueCell.append({color: colorValue.getValue()}, colorsList); newCell.colorValue = colorValue; newCell.dropDown = this; newCell.addEventListener('mousedown', this.cellMousedown, false); @@ -267,7 +456,7 @@ ColorsDropDown.prototype = { }, openPopup: function(colorCell, callback) { - this.firepicker.openPopup(this.editor, colorCell, colorCell.colorValue.toRGB(), callback); + this.firepicker.openPopup(this.editor, colorCell, colorCell.colorValue.toColor(), callback); } };