Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.

Commit

Permalink
Merge pull request #13154 from nyteksf/nyteksf/issue7723
Browse files Browse the repository at this point in the history
#7723 - Adding Support For '0x' Notation Color Format
  • Loading branch information
zaggino authored Mar 14, 2017
2 parents d00e464 + 1dccc61 commit 7372631
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 23 deletions.
2 changes: 1 addition & 1 deletion src/command/KeyBindingManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ define(function (require, exports, module) {
var normalizedKey = normalizeKeyDescriptorString(key);

if (!normalizedKey) {
console.log("Fail to nomalize " + key);
console.log("Failed to normalize " + key);
} else if (_isKeyAssigned(normalizedKey)) {
var binding = _keyMap[normalizedKey],
command = CommandManager.get(binding.commandID),
Expand Down
110 changes: 94 additions & 16 deletions src/extensions/default/InlineColorEditor/ColorEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,61 @@ define(function (require, exports, module) {
*/
var STEP_MULTIPLIER = 5;

/**
* Convert 0x notation into hex6 format for tinycolor
* compatibility: ("0xFFAACC" => "#FFFFFF")
* @param {string} str - String to ensure hex format for
* @returns {string} - str in hex format
*/
function ensureHexFormat(str) {
return (/^0x/).test(str) ? str.replace("0x","#") : str;
}

/**
* Converts a color to a 0x-prefixed string
* @param {tinycolor} color - color to convert
* @returns {string} - color as 0x-prefixed string
*/
function as0xString(color) {
return color.toHexString().replace("#", "0x");
}

/**
* Converts 0x-prefixed color to hex
* @param {string} color - Color to convert
* @param {boolean} convertToString - true if color should
* be returned as string
* @returns {tinycolor|string} - Hex color as a Tinycolor object
* or a hex string
*/
function _0xColorToHex(color, convertToStr) {
var hexColor = tinycolor(color.replace("0x", "#"));
hexColor._format = "0x";

if (convertToStr) {
return hexColor.toString();
}
return hexColor;
}

/**
* Ensures that a string is in Tinycolor supported format
* @param {string} color - Color to check the format for
* @param {boolean} convertToString - true if color should
* be returned as string
* @returns {tinycolor|string} - Color as a Tinycolor object
* or a hex string
*/
function checkSetFormat(color, convertToStr) {
if ((/^0x/).test(color)) {
return _0xColorToHex(color, convertToStr);
}
if (convertToStr) {
return tinycolor(color).toString();
}
return tinycolor(color);
}

/**
* Color picker control; may be used standalone or within an InlineColorEditor inline widget.
* @param {!jQuery} $parent DOM node into which to append the root of the color picker UI
Expand All @@ -64,8 +119,9 @@ define(function (require, exports, module) {
this._handleHueDrag = this._handleHueDrag.bind(this);
this._handleSelectionFieldDrag = this._handleSelectionFieldDrag.bind(this);

this._color = tinycolor(color);
this._originalColor = color;
this._color = checkSetFormat(color);

this._redoColor = null;
this._isUpperCase = PreferencesManager.get("uppercaseColors");
PreferencesManager.on("change", "uppercaseColors", function () {
Expand All @@ -77,6 +133,7 @@ define(function (require, exports, module) {
this.$rgbaButton = this.$element.find(".rgba");
this.$hexButton = this.$element.find(".hex");
this.$hslButton = this.$element.find(".hsla");
this.$0xButton = this.$element.find(".0x");
this.$currentColor = this.$element.find(".current-color");
this.$originalColor = this.$element.find(".original-color");
this.$selection = this.$element.find(".color-selection-field");
Expand All @@ -96,8 +153,9 @@ define(function (require, exports, module) {
this._addListeners();

// Initially selected color
this.$originalColor.css("background-color", this._originalColor);
this._commitColor(color);
this.$originalColor.css("background-color", checkSetFormat(this._originalColor));

this._commitColor(color);
}

/**
Expand Down Expand Up @@ -137,6 +195,7 @@ define(function (require, exports, module) {
this._bindColorFormatToRadioButton("rgba");
this._bindColorFormatToRadioButton("hex");
this._bindColorFormatToRadioButton("hsla");
this._bindColorFormatToRadioButton("0x");

this._bindInputHandlers();

Expand All @@ -158,14 +217,14 @@ define(function (require, exports, module) {
* Update all UI elements to reflect the selected color (_color and _hsv). It is usually
* incorrect to call this directly; use _commitColor() or setColorAsHsv() instead.
*/
ColorEditor.prototype._synchronize = function () {
var colorValue = this.getColor().getOriginalInput(),
colorObject = tinycolor(colorValue),
hueColor = "hsl(" + this._hsv.h + ", 100%, 50%)";

ColorEditor.prototype._synchronize = function () {
var colorValue = this.getColor().getOriginalInput();
var colorObject = checkSetFormat(colorValue);
var hueColor = "hsl(" + this._hsv.h + ", 100%, 50%)";
this._updateColorTypeRadioButtons(colorObject.getFormat());
this.$colorValue.val(colorValue);
this.$currentColor.css("background-color", colorValue);
this.$currentColor.css("background-color", checkSetFormat(colorValue, true));
this.$selection.css("background-color", hueColor);
this.$hueBase.css("background-color", hueColor);

Expand Down Expand Up @@ -228,6 +287,9 @@ define(function (require, exports, module) {
case "hsl":
this.$buttonList.find(".hsla").parent().addClass("selected");
break;
case "0x":
this.$buttonList.find(".0x").parent().addClass("selected");
break;
}
};

Expand All @@ -237,8 +299,9 @@ define(function (require, exports, module) {
self = this;
handler = function (event) {
var newFormat = $(event.currentTarget).html().toLowerCase().replace("%", "p"),
newColor = self.getColor().toString(),
colorObject = tinycolor(newColor);
newColor = self.getColor().toString();

var colorObject = checkSetFormat(newColor);

switch (newFormat) {
case "hsla":
Expand All @@ -254,6 +317,11 @@ define(function (require, exports, module) {
newColor = colorObject.toHexString();
self._hsv.a = 1;
break;
case "0x":
newColor = as0xString(colorObject);
self._hsv.a = 1;
self._format = "0x";
break;
}

// We need to run this again whenever RGB/HSL/Hex conversions
Expand Down Expand Up @@ -317,9 +385,10 @@ define(function (require, exports, module) {
/** Handle changes in text field */
ColorEditor.prototype._handleTextFieldInput = function (losingFocus) {
var newColor = $.trim(this.$colorValue.val()),
newColorObj = tinycolor(newColor),
newColorObj = checkSetFormat(newColor),
newColorOk = newColorObj.isValid();


// TinyColor will auto correct an incomplete rgb or hsl value into a valid color value.
// eg. rgb(0,0,0 -> rgb(0, 0, 0)
// We want to avoid having TinyColor do this, because we don't want to sync the color
Expand All @@ -328,7 +397,7 @@ define(function (require, exports, module) {
// TinyColor actually generates to see if it's different. If so, then we assume the color
// was incomplete to begin with.
if (newColorOk) {
newColorOk = (newColorObj.toString() === this._normalizeColorString(newColor));
newColorOk = (newColorObj.toString() === this._normalizeColorString(ensureHexFormat(newColor)));
}

// Restore to the previous valid color if the new color is invalid or incomplete.
Expand Down Expand Up @@ -363,10 +432,12 @@ define(function (require, exports, module) {

// Create swatches
swatches.forEach(function (swatch) {
var swatchValue = checkSetFormat(swatch.value, true);
var stringFormat = (swatch.count > 1) ? Strings.COLOR_EDITOR_USED_COLOR_TIP_PLURAL : Strings.COLOR_EDITOR_USED_COLOR_TIP_SINGULAR,
usedColorTip = StringUtils.format(stringFormat, swatch.value, swatch.count);

self.$swatches.append("<li tabindex='0'><div class='swatch-bg'><div class='swatch' style='background-color: " +
swatch.value + ";' title='" + usedColorTip + "'></div></div> <span class='value'" + " title='" +
swatchValue + ";' title='" + usedColorTip + "'></div></div> <span class='value'" + " title='" +
usedColorTip + "'>" + swatch.value + "</span></li>");
});

Expand All @@ -376,6 +447,7 @@ define(function (require, exports, module) {
event.keyCode === KeyEvent.DOM_VK_ENTER ||
event.keyCode === KeyEvent.DOM_VK_SPACE) {
// Enter/Space is same as clicking on swatch

self._commitColor($(event.currentTarget).find(".value").html());
} else if (event.keyCode === KeyEvent.DOM_VK_TAB) {
// Tab on last swatch loops back to color square
Expand Down Expand Up @@ -427,6 +499,9 @@ define(function (require, exports, module) {
case "name":
colorVal = this._hsv.a < 1 ? newColor.toRgbString() : newColor.toHexString();
break;
case "0x":
colorVal = as0xString(newColor);
break;
}
colorVal = this._isUpperCase ? colorVal.toUpperCase() : colorVal;
this._commitColor(colorVal, false);
Expand All @@ -439,11 +514,15 @@ define(function (require, exports, module) {
* @param {boolean=} resetHsv Pass false ONLY if hsv set already been modified to match colorVal. Default: true.
*/
ColorEditor.prototype._commitColor = function (colorVal, resetHsv) {

if (resetHsv === undefined) {
resetHsv = true;
}
this._callback(colorVal);
this._color = tinycolor(colorVal);

var colorObj = checkSetFormat(colorVal);
colorObj._originalInput = colorVal;
this._color = colorObj;

if (resetHsv) {
this._hsv = this._color.toHsv();
Expand Down Expand Up @@ -531,9 +610,8 @@ define(function (require, exports, module) {
*/
ColorEditor.prototype.undo = function () {
if (this._originalColor.toString() !== this._color.toString()) {
var curColor = this._color.toString();
this._commitColor(this._originalColor, true);
this._redoColor = curColor;
this._redoColor = this._color.toString();
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<li class="selected" title="{{COLOR_EDITOR_RGBA_BUTTON_TIP}}"><a href="#" tabindex="0" class="rgba">RGBa</a></li>
<li title="{{COLOR_EDITOR_HEX_BUTTON_TIP}}"><a href="#" tabindex="0" class="hex">Hex</a></li>
<li title="{{COLOR_EDITOR_HSLA_BUTTON_TIP}}"><a href="#" tabindex="0" class="hsla">HSLa</a></li>
<li title="{{COLOR_EDITOR_0X_BUTTON_TIP}}"><a href="#" tabindex="0" class="0x">0x</a></li>
</ul>
</footer>
</section>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ define(function (require, exports, module) {
var self = this;
if (colorString !== this._color) {
var range = this.getCurrentRange();

if (!range) {
return;
}
Expand Down
12 changes: 8 additions & 4 deletions src/extensions/default/QuickView/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,11 @@ define(function (require, exports, module) {
function hasLengthInPixels(args) {
return (args.length > 1 && args[1].indexOf("px") > 0);
}

// Ensures that input is in usable hex format
function ensureHexFormat(str) {
return (/^0x/).test(str) ? str.replace("0x","#") : str;
}

// Normalizes px color stops to %
function normalizeGradientExpressionForQuickview(expression) {
Expand Down Expand Up @@ -400,15 +405,14 @@ define(function (require, exports, module) {
}
} else if (pos.ch <= match.index + match[0].length) {
// build the css for previewing the gradient from the regex result
var previewCSS = gradientMatch.prefix + (gradientMatch.colorValue || match[0]);
var previewCSS = gradientMatch.prefix + (gradientMatch.colorValue || match[0]);

// normalize the arguments to something that we can display to the user
// NOTE: we need both the div and the popover's _previewCSS member
// (used by unit tests) to match so normalize the css for both
previewCSS = normalizeGradientExpressionForQuickview(previewCSS);
previewCSS = normalizeGradientExpressionForQuickview(ensureHexFormat(previewCSS));

var preview = "<div class='color-swatch' style='background:" + previewCSS + "'>" +
"</div>";
var preview = "<div class='color-swatch' style='background:" + previewCSS + "'>" + "</div>";
var startPos = {line: pos.line, ch: match.index},
endPos = {line: pos.line, ch: match.index + match[0].length},
startCoords = cm.charCoords(startPos),
Expand Down
1 change: 1 addition & 0 deletions src/nls/root/strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@ define({
"COLOR_EDITOR_RGBA_BUTTON_TIP" : "RGBa Format",
"COLOR_EDITOR_HEX_BUTTON_TIP" : "Hex Format",
"COLOR_EDITOR_HSLA_BUTTON_TIP" : "HSLa Format",
"COLOR_EDITOR_0X_BUTTON_TIP" : "Hex (0x) Format",
"COLOR_EDITOR_USED_COLOR_TIP_SINGULAR" : "{0} (Used {1} time)",
"COLOR_EDITOR_USED_COLOR_TIP_PLURAL" : "{0} (Used {1} times)",

Expand Down
4 changes: 2 additions & 2 deletions src/utils/ColorUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ define(function (require, exports, module) {

/**
* Regular expression that matches reasonably well-formed colors in hex format (3 or 6 digits),
* rgb()/rgba() function format, hsl()/hsla() function format,
* rgb()/rgba() function format, hsl()/hsla() function format, 0x notation format
* or color name format according to CSS Color Module Level 3 (http://www.w3.org/TR/css3-color/)
* or "rebeccapurple" from CSS Color Module Level 4.
* @const @type {RegExp}
*/
// use RegExp.source of the RegExp literal to avoid doubled backslashes
var COLOR_REGEX = new RegExp(/#[a-f0-9]{6}\b|#[a-f0-9]{3}\b|\brgb\(\s*(?:[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b\s*,\s*(?:[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b\s*,\s*(?:[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b\s*\)|\brgb\(\s*(?:[0-9]{1,2}%|100%)\s*,\s*(?:[0-9]{1,2}%|100%)\s*,\s*(?:[0-9]{1,2}%|100%)\s*\)|\brgba\(\s*(?:[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b\s*,\s*(?:[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b\s*,\s*(?:[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b\s*,\s*(?:1|1\.0|0|0?\.[0-9]{1,3})\s*\)|\brgba\(\s*(?:[0-9]{1,2}%|100%)\s*,\s*(?:[0-9]{1,2}%|100%)\s*,\s*(?:[0-9]{1,2}%|100%)\s*,\s*(?:1|1\.0|0|0?\.[0-9]{1,3})\s*\)|\bhsl\(\s*(?:[0-9]{1,3})\b\s*,\s*(?:[0-9]{1,2}|100)\b%\s*,\s*(?:[0-9]{1,2}|100)\b%\s*\)|\bhsla\(\s*(?:[0-9]{1,3})\b\s*,\s*(?:[0-9]{1,2}|100)\b%\s*,\s*(?:[0-9]{1,2}|100)\b%\s*,\s*(?:1|1\.0|0|0?\.[0-9]{1,3})\s*\)|\b/.source + COLOR_NAMES.join("\\b|\\b") + "\\b", "gi");
var COLOR_REGEX = new RegExp(/0x([a-f0-9]{6})\b|#[a-f0-9]{6}\b|#[a-f0-9]{3}\b|\brgb\(\s*(?:[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b\s*,\s*(?:[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b\s*,\s*(?:[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b\s*\)|\brgb\(\s*(?:[0-9]{1,2}%|100%)\s*,\s*(?:[0-9]{1,2}%|100%)\s*,\s*(?:[0-9]{1,2}%|100%)\s*\)|\brgba\(\s*(?:[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b\s*,\s*(?:[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b\s*,\s*(?:[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b\s*,\s*(?:1|1\.0|0|0?\.[0-9]{1,3})\s*\)|\brgba\(\s*(?:[0-9]{1,2}%|100%)\s*,\s*(?:[0-9]{1,2}%|100%)\s*,\s*(?:[0-9]{1,2}%|100%)\s*,\s*(?:1|1\.0|0|0?\.[0-9]{1,3})\s*\)|\bhsl\(\s*(?:[0-9]{1,3})\b\s*,\s*(?:[0-9]{1,2}|100)\b%\s*,\s*(?:[0-9]{1,2}|100)\b%\s*\)|\bhsla\(\s*(?:[0-9]{1,3})\b\s*,\s*(?:[0-9]{1,2}|100)\b%\s*,\s*(?:[0-9]{1,2}|100)\b%\s*,\s*(?:1|1\.0|0|0?\.[0-9]{1,3})\s*\)|\b/.source + COLOR_NAMES.join("\\b|\\b") + "\\b", "gi");

/*
* Adds a color swatch to code hints where this is supported.
Expand Down

0 comments on commit 7372631

Please sign in to comment.