|
|
/*
|
|
|
Copyright (c) 2009, Yahoo! Inc. All rights reserved.
|
|
|
Code licensed under the BSD License:
|
|
|
http://developer.yahoo.net/yui/license.txt
|
|
|
version: 2.8.0r4
|
|
|
*/
|
|
|
/**
|
|
|
* Provides color conversion and validation utils
|
|
|
* @class YAHOO.util.Color
|
|
|
* @namespace YAHOO.util
|
|
|
*/
|
|
|
YAHOO.util.Color = function() {
|
|
|
|
|
|
var ZERO = "0",
|
|
|
isArray = YAHOO.lang.isArray,
|
|
|
isNumber = YAHOO.lang.isNumber;
|
|
|
|
|
|
return {
|
|
|
|
|
|
/**
|
|
|
* Converts 0-1 to 0-255
|
|
|
* @method real2dec
|
|
|
* @param n {float} the number to convert
|
|
|
* @return {int} a number 0-255
|
|
|
*/
|
|
|
real2dec: function(n) {
|
|
|
return Math.min(255, Math.round(n*256));
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Converts HSV (h[0-360], s[0-1]), v[0-1] to RGB [255,255,255]
|
|
|
* @method hsv2rgb
|
|
|
* @param h {int|[int, float, float]} the hue, or an
|
|
|
* array containing all three parameters
|
|
|
* @param s {float} the saturation
|
|
|
* @param v {float} the value/brightness
|
|
|
* @return {[int, int, int]} the red, green, blue values in
|
|
|
* decimal.
|
|
|
*/
|
|
|
hsv2rgb: function(h, s, v) {
|
|
|
|
|
|
if (isArray(h)) {
|
|
|
return this.hsv2rgb.call(this, h[0], h[1], h[2]);
|
|
|
}
|
|
|
|
|
|
var r, g, b,
|
|
|
i = Math.floor((h/60)%6),
|
|
|
f = (h/60)-i,
|
|
|
p = v*(1-s),
|
|
|
q = v*(1-f*s),
|
|
|
t = v*(1-(1-f)*s),
|
|
|
fn;
|
|
|
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
fn=this.real2dec;
|
|
|
|
|
|
return [fn(r), fn(g), fn(b)];
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Converts to RGB [255,255,255] to HSV (h[0-360], s[0-1]), v[0-1]
|
|
|
* @method rgb2hsv
|
|
|
* @param r {int|[int, int, int]} the red value, or an
|
|
|
* array containing all three parameters
|
|
|
* @param g {int} the green value
|
|
|
* @param b {int} the blue value
|
|
|
* @return {[int, float, float]} the value converted to hsv
|
|
|
*/
|
|
|
rgb2hsv: function(r, g, b) {
|
|
|
|
|
|
if (isArray(r)) {
|
|
|
return this.rgb2hsv.apply(this, r);
|
|
|
}
|
|
|
|
|
|
r /= 255;
|
|
|
g /= 255;
|
|
|
b /= 255;
|
|
|
|
|
|
var h,s,
|
|
|
min = Math.min(Math.min(r,g),b),
|
|
|
max = Math.max(Math.max(r,g),b),
|
|
|
delta = max-min,
|
|
|
hsv;
|
|
|
|
|
|
switch (max) {
|
|
|
case min: h=0; break;
|
|
|
case r: h=60*(g-b)/delta;
|
|
|
if (g<b) {
|
|
|
h+=360;
|
|
|
}
|
|
|
break;
|
|
|
case g: h=(60*(b-r)/delta)+120; break;
|
|
|
case b: h=(60*(r-g)/delta)+240; break;
|
|
|
}
|
|
|
|
|
|
s = (max === 0) ? 0 : 1-(min/max);
|
|
|
|
|
|
hsv = [Math.round(h), s, max];
|
|
|
|
|
|
return hsv;
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Converts decimal rgb values into a hex string
|
|
|
* 255,255,255 -> FFFFFF
|
|
|
* @method rgb2hex
|
|
|
* @param r {int|[int, int, int]} the red value, or an
|
|
|
* array containing all three parameters
|
|
|
* @param g {int} the green value
|
|
|
* @param b {int} the blue value
|
|
|
* @return {string} the hex string
|
|
|
*/
|
|
|
rgb2hex: function(r, g, b) {
|
|
|
if (isArray(r)) {
|
|
|
return this.rgb2hex.apply(this, r);
|
|
|
}
|
|
|
|
|
|
var f=this.dec2hex;
|
|
|
return f(r) + f(g) + f(b);
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Converts an int 0...255 to hex pair 00...FF
|
|
|
* @method dec2hex
|
|
|
* @param n {int} the number to convert
|
|
|
* @return {string} the hex equivalent
|
|
|
*/
|
|
|
dec2hex: function(n) {
|
|
|
n = parseInt(n,10)|0;
|
|
|
n = (n > 255 || n < 0) ? 0 : n;
|
|
|
|
|
|
return (ZERO+n.toString(16)).slice(-2).toUpperCase();
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Converts a hex pair 00...FF to an int 0...255
|
|
|
* @method hex2dec
|
|
|
* @param str {string} the hex pair to convert
|
|
|
* @return {int} the decimal
|
|
|
*/
|
|
|
hex2dec: function(str) {
|
|
|
return parseInt(str,16);
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Converts a hex string to rgb
|
|
|
* @method hex2rgb
|
|
|
* @param str {string} the hex string
|
|
|
* @return {[int, int, int]} an array containing the rgb values
|
|
|
*/
|
|
|
hex2rgb: function(s) {
|
|
|
var f = this.hex2dec;
|
|
|
return [f(s.slice(0, 2)), f(s.slice(2, 4)), f(s.slice(4, 6))];
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Returns the closest websafe color to the supplied rgb value.
|
|
|
* @method websafe
|
|
|
* @param r {int|[int, int, int]} the red value, or an
|
|
|
* array containing all three parameters
|
|
|
* @param g {int} the green value
|
|
|
* @param b {int} the blue value
|
|
|
* @return {[int, int, int]} an array containing the closes
|
|
|
* websafe rgb colors.
|
|
|
*/
|
|
|
websafe: function(r, g, b) {
|
|
|
|
|
|
if (isArray(r)) {
|
|
|
return this.websafe.apply(this, r);
|
|
|
}
|
|
|
|
|
|
// returns the closest match [0, 51, 102, 153, 204, 255]
|
|
|
var f = function(v) {
|
|
|
if (isNumber(v)) {
|
|
|
v = Math.min(Math.max(0, v), 255);
|
|
|
var i, next;
|
|
|
for (i=0; i<256; i=i+51) {
|
|
|
next = i+51;
|
|
|
if (v >= i && v <= next) {
|
|
|
return (v-i > 25) ? next : i;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return v;
|
|
|
};
|
|
|
|
|
|
return [f(r), f(g), f(b)];
|
|
|
}
|
|
|
};
|
|
|
}();
|
|
|
|
|
|
|
|
|
/**
|
|
|
* The colorpicker module provides a widget for selecting colors
|
|
|
* @module colorpicker
|
|
|
* @requires yahoo, dom, event, element, slider
|
|
|
*/
|
|
|
(function() {
|
|
|
|
|
|
var _pickercount = 0,
|
|
|
util = YAHOO.util,
|
|
|
lang = YAHOO.lang,
|
|
|
Slider = YAHOO.widget.Slider,
|
|
|
Color = util.Color,
|
|
|
Dom = util.Dom,
|
|
|
Event = util.Event,
|
|
|
sub = lang.substitute,
|
|
|
|
|
|
b = "yui-picker";
|
|
|
|
|
|
|
|
|
/**
|
|
|
* A widget to select colors
|
|
|
* @namespace YAHOO.widget
|
|
|
* @class YAHOO.widget.ColorPicker
|
|
|
* @extends YAHOO.util.Element
|
|
|
* @constructor
|
|
|
* @param {HTMLElement | String | Object} el(optional) The html
|
|
|
* element that represents the colorpicker, or the attribute object to use.
|
|
|
* An element will be created if none provided.
|
|
|
* @param {Object} attr (optional) A key map of the colorpicker's
|
|
|
* initial attributes. Ignored if first arg is attributes object.
|
|
|
*/
|
|
|
function ColorPicker(el, attr) {
|
|
|
_pickercount = _pickercount + 1;
|
|
|
attr = attr || {};
|
|
|
if (arguments.length === 1 && !YAHOO.lang.isString(el) && !el.nodeName) {
|
|
|
attr = el; // treat first arg as attr object
|
|
|
el = attr.element || null;
|
|
|
}
|
|
|
|
|
|
if (!el && !attr.element) { // create if we dont have one
|
|
|
el = this._createHostElement(attr);
|
|
|
}
|
|
|
|
|
|
ColorPicker.superclass.constructor.call(this, el, attr);
|
|
|
|
|
|
this.initPicker();
|
|
|
}
|
|
|
|
|
|
YAHOO.extend(ColorPicker, YAHOO.util.Element, {
|
|
|
|
|
|
/**
|
|
|
* The element ids used by this control
|
|
|
* @property ID
|
|
|
* @final
|
|
|
*/
|
|
|
ID : {
|
|
|
|
|
|
/**
|
|
|
* The id for the "red" form field
|
|
|
* @property ID.R
|
|
|
* @type String
|
|
|
* @final
|
|
|
* @default yui-picker-r
|
|
|
*/
|
|
|
R: b + "-r",
|
|
|
|
|
|
/**
|
|
|
* The id for the "red" hex pair output
|
|
|
* @property ID.R_HEX
|
|
|
* @type String
|
|
|
* @final
|
|
|
* @default yui-picker-rhex
|
|
|
*/
|
|
|
R_HEX: b + "-rhex",
|
|
|
|
|
|
/**
|
|
|
* The id for the "green" form field
|
|
|
* @property ID.G
|
|
|
* @type String
|
|
|
* @final
|
|
|
* @default yui-picker-g
|
|
|
*/
|
|
|
G: b + "-g",
|
|
|
|
|
|
/**
|
|
|
* The id for the "green" hex pair output
|
|
|
* @property ID.G_HEX
|
|
|
* @type String
|
|
|
* @final
|
|
|
* @default yui-picker-ghex
|
|
|
*/
|
|
|
G_HEX: b + "-ghex",
|
|
|
|
|
|
|
|
|
/**
|
|
|
* The id for the "blue" form field
|
|
|
* @property ID.B
|
|
|
* @type String
|
|
|
* @final
|
|
|
* @default yui-picker-b
|
|
|
*/
|
|
|
B: b + "-b",
|
|
|
|
|
|
/**
|
|
|
* The id for the "blue" hex pair output
|
|
|
* @property ID.B_HEX
|
|
|
* @type String
|
|
|
* @final
|
|
|
* @default yui-picker-bhex
|
|
|
*/
|
|
|
B_HEX: b + "-bhex",
|
|
|
|
|
|
/**
|
|
|
* The id for the "hue" form field
|
|
|
* @property ID.H
|
|
|
* @type String
|
|
|
* @final
|
|
|
* @default yui-picker-h
|
|
|
*/
|
|
|
H: b + "-h",
|
|
|
|
|
|
/**
|
|
|
* The id for the "saturation" form field
|
|
|
* @property ID.S
|
|
|
* @type String
|
|
|
* @final
|
|
|
* @default yui-picker-s
|
|
|
*/
|
|
|
S: b + "-s",
|
|
|
|
|
|
/**
|
|
|
* The id for the "value" form field
|
|
|
* @property ID.V
|
|
|
* @type String
|
|
|
* @final
|
|
|
* @default yui-picker-v
|
|
|
*/
|
|
|
V: b + "-v",
|
|
|
|
|
|
/**
|
|
|
* The id for the picker region slider
|
|
|
* @property ID.PICKER_BG
|
|
|
* @type String
|
|
|
* @final
|
|
|
* @default yui-picker-bg
|
|
|
*/
|
|
|
PICKER_BG: b + "-bg",
|
|
|
|
|
|
/**
|
|
|
* The id for the picker region thumb
|
|
|
* @property ID.PICKER_THUMB
|
|
|
* @type String
|
|
|
* @final
|
|
|
* @default yui-picker-thumb
|
|
|
*/
|
|
|
PICKER_THUMB: b + "-thumb",
|
|
|
|
|
|
/**
|
|
|
* The id for the hue slider
|
|
|
* @property ID.HUE_BG
|
|
|
* @type String
|
|
|
* @final
|
|
|
* @default yui-picker-hue-bg
|
|
|
*/
|
|
|
HUE_BG: b + "-hue-bg",
|
|
|
|
|
|
/**
|
|
|
* The id for the hue thumb
|
|
|
* @property ID.HUE_THUMB
|
|
|
* @type String
|
|
|
* @final
|
|
|
* @default yui-picker-hue-thumb
|
|
|
*/
|
|
|
HUE_THUMB: b + "-hue-thumb",
|
|
|
|
|
|
/**
|
|
|
* The id for the hex value form field
|
|
|
* @property ID.HEX
|
|
|
* @type String
|
|
|
* @final
|
|
|
* @default yui-picker-hex
|
|
|
*/
|
|
|
HEX: b + "-hex",
|
|
|
|
|
|
/**
|
|
|
* The id for the color swatch
|
|
|
* @property ID.SWATCH
|
|
|
* @type String
|
|
|
* @final
|
|
|
* @default yui-picker-swatch
|
|
|
*/
|
|
|
SWATCH: b + "-swatch",
|
|
|
|
|
|
/**
|
|
|
* The id for the websafe color swatch
|
|
|
* @property ID.WEBSAFE_SWATCH
|
|
|
* @type String
|
|
|
* @final
|
|
|
* @default yui-picker-websafe-swatch
|
|
|
*/
|
|
|
WEBSAFE_SWATCH: b + "-websafe-swatch",
|
|
|
|
|
|
/**
|
|
|
* The id for the control details
|
|
|
* @property ID.CONTROLS
|
|
|
* @final
|
|
|
* @default yui-picker-controls
|
|
|
*/
|
|
|
CONTROLS: b + "-controls",
|
|
|
|
|
|
/**
|
|
|
* The id for the rgb controls
|
|
|
* @property ID.RGB_CONTROLS
|
|
|
* @final
|
|
|
* @default yui-picker-rgb-controls
|
|
|
*/
|
|
|
RGB_CONTROLS: b + "-rgb-controls",
|
|
|
|
|
|
/**
|
|
|
* The id for the hsv controls
|
|
|
* @property ID.HSV_CONTROLS
|
|
|
* @final
|
|
|
* @default yui-picker-hsv-controls
|
|
|
*/
|
|
|
HSV_CONTROLS: b + "-hsv-controls",
|
|
|
|
|
|
/**
|
|
|
* The id for the hsv controls
|
|
|
* @property ID.HEX_CONTROLS
|
|
|
* @final
|
|
|
* @default yui-picker-hex-controls
|
|
|
*/
|
|
|
HEX_CONTROLS: b + "-hex-controls",
|
|
|
|
|
|
/**
|
|
|
* The id for the hex summary
|
|
|
* @property ID.HEX_SUMMARY
|
|
|
* @final
|
|
|
* @default yui-picker-hex-summary
|
|
|
*/
|
|
|
HEX_SUMMARY: b + "-hex-summary",
|
|
|
|
|
|
/**
|
|
|
* The id for the controls section header
|
|
|
* @property ID.CONTROLS_LABEL
|
|
|
* @final
|
|
|
* @default yui-picker-controls-label
|
|
|
*/
|
|
|
CONTROLS_LABEL: b + "-controls-label"
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Constants for any script-generated messages. The values here
|
|
|
* are the default messages. They can be updated by providing
|
|
|
* the complete list to the constructor for the "txt" attribute.
|
|
|
* @property TXT
|
|
|
* @final
|
|
|
*/
|
|
|
TXT : {
|
|
|
ILLEGAL_HEX: "Illegal hex value entered",
|
|
|
SHOW_CONTROLS: "Show color details",
|
|
|
HIDE_CONTROLS: "Hide color details",
|
|
|
CURRENT_COLOR: "Currently selected color: {rgb}",
|
|
|
CLOSEST_WEBSAFE: "Closest websafe color: {rgb}. Click to select.",
|
|
|
R: "R",
|
|
|
G: "G",
|
|
|
B: "B",
|
|
|
H: "H",
|
|
|
S: "S",
|
|
|
V: "V",
|
|
|
HEX: "#",
|
|
|
DEG: "\u00B0",
|
|
|
PERCENT: "%"
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Constants for the default image locations for img tags that are
|
|
|
* generated by the control. They can be modified by passing the
|
|
|
* complete list to the contructor for the "images" attribute
|
|
|
* @property IMAGE
|
|
|
* @final
|
|
|
*/
|
|
|
IMAGE : {
|
|
|
PICKER_THUMB: "../../build/colorpicker/assets/picker_thumb.png",
|
|
|
HUE_THUMB: "../../build/colorpicker/assets/hue_thumb.png"
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Constants for the control's default default values
|
|
|
* @property DEFAULT
|
|
|
* @final
|
|
|
*/
|
|
|
DEFAULT : {
|
|
|
PICKER_SIZE: 180
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Constants for the control's configuration attributes
|
|
|
* @property OPT
|
|
|
* @final
|
|
|
*/
|
|
|
OPT : {
|
|
|
HUE : "hue",
|
|
|
SATURATION : "saturation",
|
|
|
VALUE : "value",
|
|
|
RED : "red",
|
|
|
GREEN : "green",
|
|
|
BLUE : "blue",
|
|
|
HSV : "hsv",
|
|
|
RGB : "rgb",
|
|
|
WEBSAFE : "websafe",
|
|
|
HEX : "hex",
|
|
|
PICKER_SIZE : "pickersize",
|
|
|
SHOW_CONTROLS : "showcontrols",
|
|
|
SHOW_RGB_CONTROLS : "showrgbcontrols",
|
|
|
SHOW_HSV_CONTROLS : "showhsvcontrols",
|
|
|
SHOW_HEX_CONTROLS : "showhexcontrols",
|
|
|
SHOW_HEX_SUMMARY : "showhexsummary",
|
|
|
SHOW_WEBSAFE : "showwebsafe",
|
|
|
CONTAINER : "container",
|
|
|
IDS : "ids",
|
|
|
ELEMENTS : "elements",
|
|
|
TXT : "txt",
|
|
|
IMAGES : "images",
|
|
|
ANIMATE : "animate"
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Flag to allow individual UI updates to forego animation if available.
|
|
|
* True during construction for initial thumb placement. Set to false
|
|
|
* after that.
|
|
|
*
|
|
|
* @property skipAnim
|
|
|
* @type Boolean
|
|
|
* @default true
|
|
|
*/
|
|
|
skipAnim : true,
|
|
|
|
|
|
/**
|
|
|
* Creates the host element if it doesn't exist
|
|
|
* @method _createHostElement
|
|
|
* @protected
|
|
|
*/
|
|
|
_createHostElement : function () {
|
|
|
var el = document.createElement('div');
|
|
|
|
|
|
if (this.CSS.BASE) {
|
|
|
el.className = this.CSS.BASE;
|
|
|
}
|
|
|
|
|
|
return el;
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Moves the hue slider into the position dictated by the current state
|
|
|
* of the control
|
|
|
* @method _updateHueSlider
|
|
|
* @protected
|
|
|
*/
|
|
|
_updateHueSlider : function() {
|
|
|
var size = this.get(this.OPT.PICKER_SIZE),
|
|
|
h = this.get(this.OPT.HUE);
|
|
|
|
|
|
h = size - Math.round(h / 360 * size);
|
|
|
|
|
|
// 0 is at the top and bottom of the hue slider. Always go to
|
|
|
// the top so we don't end up sending the thumb to the bottom
|
|
|
// when the value didn't actually change (e.g., a conversion
|
|
|
// produced 360 instead of 0 and the value was already 0).
|
|
|
if (h === size) {
|
|
|
h = 0;
|
|
|
}
|
|
|
|
|
|
this.hueSlider.setValue(h, this.skipAnim);
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Moves the picker slider into the position dictated by the current state
|
|
|
* of the control
|
|
|
* @method _updatePickerSlider
|
|
|
* @protected
|
|
|
*/
|
|
|
_updatePickerSlider : function() {
|
|
|
var size = this.get(this.OPT.PICKER_SIZE),
|
|
|
s = this.get(this.OPT.SATURATION),
|
|
|
v = this.get(this.OPT.VALUE);
|
|
|
|
|
|
s = Math.round(s * size / 100);
|
|
|
v = Math.round(size - (v * size / 100));
|
|
|
|
|
|
|
|
|
this.pickerSlider.setRegionValue(s, v, this.skipAnim);
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Moves the sliders into the position dictated by the current state
|
|
|
* of the control
|
|
|
* @method _updateSliders
|
|
|
* @protected
|
|
|
*/
|
|
|
_updateSliders : function() {
|
|
|
this._updateHueSlider();
|
|
|
this._updatePickerSlider();
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Sets the control to the specified rgb value and
|
|
|
* moves the sliders to the proper positions
|
|
|
* @method setValue
|
|
|
* @param rgb {[int, int, int]} the rgb value
|
|
|
* @param silent {boolean} whether or not to fire the change event
|
|
|
*/
|
|
|
setValue : function(rgb, silent) {
|
|
|
silent = (silent) || false;
|
|
|
this.set(this.OPT.RGB, rgb, silent);
|
|
|
this._updateSliders();
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* The hue slider
|
|
|
* @property hueSlider
|
|
|
* @type YAHOO.widget.Slider
|
|
|
*/
|
|
|
hueSlider : null,
|
|
|
|
|
|
/**
|
|
|
* The picker region
|
|
|
* @property pickerSlider
|
|
|
* @type YAHOO.widget.Slider
|
|
|
*/
|
|
|
pickerSlider : null,
|
|
|
|
|
|
/**
|
|
|
* Translates the slider value into hue, int[0,359]
|
|
|
* @method _getH
|
|
|
* @protected
|
|
|
* @return {int} the hue from 0 to 359
|
|
|
*/
|
|
|
_getH : function() {
|
|
|
var size = this.get(this.OPT.PICKER_SIZE),
|
|
|
h = (size - this.hueSlider.getValue()) / size;
|
|
|
h = Math.round(h*360);
|
|
|
return (h === 360) ? 0 : h;
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Translates the slider value into saturation, int[0,1], left to right
|
|
|
* @method _getS
|
|
|
* @protected
|
|
|
* @return {int} the saturation from 0 to 1
|
|
|
*/
|
|
|
_getS : function() {
|
|
|
return this.pickerSlider.getXValue() / this.get(this.OPT.PICKER_SIZE);
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Translates the slider value into value/brightness, int[0,1], top
|
|
|
* to bottom
|
|
|
* @method _getV
|
|
|
* @protected
|
|
|
* @return {int} the value from 0 to 1
|
|
|
*/
|
|
|
_getV : function() {
|
|
|
var size = this.get(this.OPT.PICKER_SIZE);
|
|
|
return (size - this.pickerSlider.getYValue()) / size;
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Updates the background of the swatch with the current rbg value.
|
|
|
* Also updates the websafe swatch to the closest websafe color
|
|
|
* @method _updateSwatch
|
|
|
* @protected
|
|
|
*/
|
|
|
_updateSwatch : function() {
|
|
|
var rgb = this.get(this.OPT.RGB),
|
|
|
websafe = this.get(this.OPT.WEBSAFE),
|
|
|
el = this.getElement(this.ID.SWATCH),
|
|
|
color = rgb.join(","),
|
|
|
txt = this.get(this.OPT.TXT);
|
|
|
|
|
|
Dom.setStyle(el, "background-color", "rgb(" + color + ")");
|
|
|
el.title = sub(txt.CURRENT_COLOR, {
|
|
|
"rgb": "#" + this.get(this.OPT.HEX)
|
|
|
});
|
|
|
|
|
|
|
|
|
el = this.getElement(this.ID.WEBSAFE_SWATCH);
|
|
|
color = websafe.join(",");
|
|
|
|
|
|
Dom.setStyle(el, "background-color", "rgb(" + color + ")");
|
|
|
el.title = sub(txt.CLOSEST_WEBSAFE, {
|
|
|
"rgb": "#" + Color.rgb2hex(websafe)
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Reads the sliders and converts the values to RGB, updating the
|
|
|
* internal state for all the individual form fields
|
|
|
* @method _getValuesFromSliders
|
|
|
* @protected
|
|
|
*/
|
|
|
_getValuesFromSliders : function() {
|
|
|
this.set(this.OPT.RGB, Color.hsv2rgb(this._getH(), this._getS(), this._getV()));
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Updates the form field controls with the state data contained
|
|
|
* in the control.
|
|
|
* @method _updateFormFields
|
|
|
* @protected
|
|
|
*/
|
|
|
_updateFormFields : function() {
|
|
|
this.getElement(this.ID.H).value = this.get(this.OPT.HUE);
|
|
|
this.getElement(this.ID.S).value = this.get(this.OPT.SATURATION);
|
|
|
this.getElement(this.ID.V).value = this.get(this.OPT.VALUE);
|
|
|
this.getElement(this.ID.R).value = this.get(this.OPT.RED);
|
|
|
this.getElement(this.ID.R_HEX).innerHTML = Color.dec2hex(this.get(this.OPT.RED));
|
|
|
this.getElement(this.ID.G).value = this.get(this.OPT.GREEN);
|
|
|
this.getElement(this.ID.G_HEX).innerHTML = Color.dec2hex(this.get(this.OPT.GREEN));
|
|
|
this.getElement(this.ID.B).value = this.get(this.OPT.BLUE);
|
|
|
this.getElement(this.ID.B_HEX).innerHTML = Color.dec2hex(this.get(this.OPT.BLUE));
|
|
|
this.getElement(this.ID.HEX).value = this.get(this.OPT.HEX);
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Event handler for the hue slider.
|
|
|
* @method _onHueSliderChange
|
|
|
* @param newOffset {int} pixels from the start position
|
|
|
* @protected
|
|
|
*/
|
|
|
_onHueSliderChange : function(newOffset) {
|
|
|
|
|
|
var h = this._getH(),
|
|
|
rgb = Color.hsv2rgb(h, 1, 1),
|
|
|
styleDef = "rgb(" + rgb.join(",") + ")";
|
|
|
|
|
|
this.set(this.OPT.HUE, h, true);
|
|
|
|
|
|
// set picker background to the hue
|
|
|
Dom.setStyle(this.getElement(this.ID.PICKER_BG), "background-color", styleDef);
|
|
|
|
|
|
if (this.hueSlider.valueChangeSource !== Slider.SOURCE_SET_VALUE) {
|
|
|
this._getValuesFromSliders();
|
|
|
}
|
|
|
|
|
|
this._updateFormFields();
|
|
|
this._updateSwatch();
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Event handler for the picker slider, which controls the
|
|
|
* saturation and value/brightness.
|
|
|
* @method _onPickerSliderChange
|
|
|
* @param newOffset {{x: int, y: int}} x/y pixels from the start position
|
|
|
* @protected
|
|
|
*/
|
|
|
_onPickerSliderChange : function(newOffset) {
|
|
|
|
|
|
var s=this._getS(), v=this._getV();
|
|
|
this.set(this.OPT.SATURATION, Math.round(s*100), true);
|
|
|
this.set(this.OPT.VALUE, Math.round(v*100), true);
|
|
|
|
|
|
if (this.pickerSlider.valueChangeSource !== Slider.SOURCE_SET_VALUE) {
|
|
|
this._getValuesFromSliders();
|
|
|
}
|
|
|
|
|
|
this._updateFormFields();
|
|
|
this._updateSwatch();
|
|
|
},
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Key map to well-known commands for txt field input
|
|
|
* @method _getCommand
|
|
|
* @param e {Event} the keypress or keydown event
|
|
|
* @return {int} a command code
|
|
|
* <ul>
|
|
|
* <li>0 = not a number, letter in range, or special key</li>
|
|
|
* <li>1 = number</li>
|
|
|
* <li>2 = a-fA-F</li>
|
|
|
* <li>3 = increment (up arrow)</li>
|
|
|
* <li>4 = decrement (down arrow)</li>
|
|
|
* <li>5 = special key (tab, delete, return, escape, left, right)</li>
|
|
|
* <li>6 = return</li>
|
|
|
* </ul>
|
|
|
* @protected
|
|
|
*/
|
|
|
_getCommand : function(e) {
|
|
|
var c = Event.getCharCode(e);
|
|
|
|
|
|
//alert(Event.getCharCode(e) + ", " + e.keyCode + ", " + e.charCode);
|
|
|
|
|
|
// special keys
|
|
|
if (c === 38) { // up arrow
|
|
|
return 3;
|
|
|
} else if (c === 13) { // return
|
|
|
return 6;
|
|
|
} else if (c === 40) { // down array
|
|
|
return 4;
|
|
|
} else if (c >= 48 && c<=57) { // 0-9
|
|
|
return 1;
|
|
|
} else if (c >= 97 && c<=102) { // a-f
|
|
|
return 2;
|
|
|
} else if (c >= 65 && c<=70) { // A-F
|
|
|
return 2;
|
|
|
//} else if ("8, 9, 13, 27, 37, 39".indexOf(c) > -1 ||
|
|
|
// (c >= 112 && c <=123)) { // including F-keys
|
|
|
// tab, delete, return, escape, left, right or ctrl/meta sequences
|
|
|
} else if ("8, 9, 13, 27, 37, 39".indexOf(c) > -1 ||
|
|
|
e.ctrlKey || e.metaKey) { // special chars
|
|
|
return 5;
|
|
|
} else { // something we probably don't want
|
|
|
return 0;
|
|
|
}
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Use the value of the text field to update the control
|
|
|
* @method _useFieldValue
|
|
|
* @param e {Event} an event
|
|
|
* @param el {HTMLElement} the field
|
|
|
* @param prop {string} the key to the linked property
|
|
|
* @protected
|
|
|
*/
|
|
|
_useFieldValue : function(e, el, prop) {
|
|
|
var val = el.value;
|
|
|
|
|
|
if (prop !== this.OPT.HEX) {
|
|
|
val = parseInt(val, 10);
|
|
|
}
|
|
|
|
|
|
if (val !== this.get(prop)) {
|
|
|
this.set(prop, val);
|
|
|
}
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Handle keypress on one of the rgb or hsv fields.
|
|
|
* @method _rgbFieldKeypress
|
|
|
* @param e {Event} the keypress event
|
|
|
* @param el {HTMLElement} the field
|
|
|
* @param prop {string} the key to the linked property
|
|
|
* @protected
|
|
|
*/
|
|
|
_rgbFieldKeypress : function(e, el, prop) {
|
|
|
var command = this._getCommand(e),
|
|
|
inc = (e.shiftKey) ? 10 : 1;
|
|
|
switch (command) {
|
|
|
case 6: // return, update the value
|
|
|
this._useFieldValue.apply(this, arguments);
|
|
|
break;
|
|
|
|
|
|
case 3: // up arrow, increment
|
|
|
this.set(prop, Math.min(this.get(prop)+inc, 255));
|
|
|
this._updateFormFields();
|
|
|
//Event.stopEvent(e);
|
|
|
break;
|
|
|
case 4: // down arrow, decrement
|
|
|
this.set(prop, Math.max(this.get(prop)-inc, 0));
|
|
|
this._updateFormFields();
|
|
|
//Event.stopEvent(e);
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Handle keydown on the hex field
|
|
|
* @method _hexFieldKeypress
|
|
|
* @param e {Event} the keypress event
|
|
|
* @param el {HTMLElement} the field
|
|
|
* @param prop {string} the key to the linked property
|
|
|
* @protected
|
|
|
*/
|
|
|
_hexFieldKeypress : function(e, el, prop) {
|
|
|
var command = this._getCommand(e);
|
|
|
if (command === 6) { // return, update the value
|
|
|
this._useFieldValue.apply(this, arguments);
|
|
|
}
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Allows numbers and special chars, and by default allows a-f.
|
|
|
* Used for the hex field keypress handler.
|
|
|
* @method _hexOnly
|
|
|
* @param e {Event} the event
|
|
|
* @param numbersOnly omits a-f if set to true
|
|
|
* @protected
|
|
|
* @return {boolean} false if we are canceling the event
|
|
|
*/
|
|
|
_hexOnly : function(e, numbersOnly) {
|
|
|
var command = this._getCommand(e);
|
|
|
switch (command) {
|
|
|
case 6: // return
|
|
|
case 5: // special char
|
|
|
case 1: // number
|
|
|
break;
|
|
|
case 2: // hex char (a-f)
|
|
|
if (numbersOnly !== true) {
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
// fallthrough is intentional
|
|
|
|
|
|
default: // prevent alpha and punctuation
|
|
|
Event.stopEvent(e);
|
|
|
return false;
|
|
|
}
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Allows numbers and special chars only. Used for the
|
|
|
* rgb and hsv fields keypress handler.
|
|
|
* @method _numbersOnly
|
|
|
* @param e {Event} the event
|
|
|
* @protected
|
|
|
* @return {boolean} false if we are canceling the event
|
|
|
*/
|
|
|
_numbersOnly : function(e) {
|
|
|
return this._hexOnly(e, true);
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Returns the element reference that is saved. The id can be either
|
|
|
* the element id, or the key for this id in the "id" config attribute.
|
|
|
* For instance, the host element id can be obtained by passing its
|
|
|
* id (default: "yui_picker") or by its key "YUI_PICKER".
|
|
|
* @param id {string} the element id, or key
|
|
|
* @return {HTMLElement} a reference to the element
|
|
|
*/
|
|
|
getElement : function(id) {
|
|
|
return this.get(this.OPT.ELEMENTS)[this.get(this.OPT.IDS)[id]];
|
|
|
},
|
|
|
|
|
|
_createElements : function() {
|
|
|
var el, child, img, fld, p,
|
|
|
ids = this.get(this.OPT.IDS),
|
|
|
txt = this.get(this.OPT.TXT),
|
|
|
images = this.get(this.OPT.IMAGES),
|
|
|
Elem = function(type, o) {
|
|
|
var n = document.createElement(type);
|
|
|
if (o) {
|
|
|
lang.augmentObject(n, o, true);
|
|
|
}
|
|
|
return n;
|
|
|
},
|
|
|
RGBElem = function(type, obj) {
|
|
|
var o = lang.merge({
|
|
|
//type: "txt",
|
|
|
autocomplete: "off",
|
|
|
value: "0",
|
|
|
size: 3,
|
|
|
maxlength: 3
|
|
|
}, obj);
|
|
|
|
|
|
o.name = o.id;
|
|
|
return new Elem(type, o);
|
|
|
};
|
|
|
|
|
|
p = this.get("element");
|
|
|
|
|
|
// Picker slider (S and V) ---------------------------------------------
|
|
|
|
|
|
el = new Elem("div", {
|
|
|
id: ids[this.ID.PICKER_BG],
|
|
|
className: "yui-picker-bg",
|
|
|
tabIndex: -1,
|
|
|
hideFocus: true
|
|
|
});
|
|
|
|
|
|
child = new Elem("div", {
|
|
|
id: ids[this.ID.PICKER_THUMB],
|
|
|
className: "yui-picker-thumb"
|
|
|
});
|
|
|
|
|
|
img = new Elem("img", {
|
|
|
src: images.PICKER_THUMB
|
|
|
});
|
|
|
|
|
|
child.appendChild(img);
|
|
|
el.appendChild(child);
|
|
|
p.appendChild(el);
|
|
|
|
|
|
// Hue slider ---------------------------------------------
|
|
|
el = new Elem("div", {
|
|
|
id: ids[this.ID.HUE_BG],
|
|
|
className: "yui-picker-hue-bg",
|
|
|
tabIndex: -1,
|
|
|
hideFocus: true
|
|
|
});
|
|
|
|
|
|
child = new Elem("div", {
|
|
|
id: ids[this.ID.HUE_THUMB],
|
|
|
className: "yui-picker-hue-thumb"
|
|
|
});
|
|
|
|
|
|
img = new Elem("img", {
|
|
|
src: images.HUE_THUMB
|
|
|
});
|
|
|
|
|
|
child.appendChild(img);
|
|
|
el.appendChild(child);
|
|
|
p.appendChild(el);
|
|
|
|
|
|
|
|
|
// controls ---------------------------------------------
|
|
|
|
|
|
el = new Elem("div", {
|
|
|
id: ids[this.ID.CONTROLS],
|
|
|
className: "yui-picker-controls"
|
|
|
});
|
|
|
|
|
|
p.appendChild(el);
|
|
|
p = el;
|
|
|
|
|
|
// controls header
|
|
|
el = new Elem("div", {
|
|
|
className: "hd"
|
|
|
});
|
|
|
|
|
|
child = new Elem("a", {
|
|
|
id: ids[this.ID.CONTROLS_LABEL],
|
|
|
//className: "yui-picker-controls-label",
|
|
|
href: "#"
|
|
|
});
|
|
|
el.appendChild(child);
|
|
|
p.appendChild(el);
|
|
|
|
|
|
// bd
|
|
|
el = new Elem("div", {
|
|
|
className: "bd"
|
|
|
});
|
|
|
|
|
|
p.appendChild(el);
|
|
|
p = el;
|
|
|
|
|
|
// rgb
|
|
|
el = new Elem("ul", {
|
|
|
id: ids[this.ID.RGB_CONTROLS],
|
|
|
className: "yui-picker-rgb-controls"
|
|
|
});
|
|
|
|
|
|
child = new Elem("li");
|
|
|
child.appendChild(document.createTextNode(txt.R + " "));
|
|
|
|
|
|
fld = new RGBElem("input", {
|
|
|
id: ids[this.ID.R],
|
|
|
className: "yui-picker-r"
|
|
|
});
|
|
|
|
|
|
child.appendChild(fld);
|
|
|
el.appendChild(child);
|
|
|
|
|
|
child = new Elem("li");
|
|
|
child.appendChild(document.createTextNode(txt.G + " "));
|
|
|
|
|
|
fld = new RGBElem("input", {
|
|
|
id: ids[this.ID.G],
|
|
|
className: "yui-picker-g"
|
|
|
});
|
|
|
|
|
|
child.appendChild(fld);
|
|
|
el.appendChild(child);
|
|
|
|
|
|
child = new Elem("li");
|
|
|
child.appendChild(document.createTextNode(txt.B + " "));
|
|
|
|
|
|
fld = new RGBElem("input", {
|
|
|
id: ids[this.ID.B],
|
|
|
className: "yui-picker-b"
|
|
|
});
|
|
|
|
|
|
child.appendChild(fld);
|
|
|
el.appendChild(child);
|
|
|
|
|
|
p.appendChild(el);
|
|
|
|
|
|
// hsv
|
|
|
el = new Elem("ul", {
|
|
|
id: ids[this.ID.HSV_CONTROLS],
|
|
|
className: "yui-picker-hsv-controls"
|
|
|
});
|
|
|
|
|
|
child = new Elem("li");
|
|
|
child.appendChild(document.createTextNode(txt.H + " "));
|
|
|
|
|
|
fld = new RGBElem("input", {
|
|
|
id: ids[this.ID.H],
|
|
|
className: "yui-picker-h"
|
|
|
});
|
|
|
|
|
|
child.appendChild(fld);
|
|
|
child.appendChild(document.createTextNode(" " + txt.DEG));
|
|
|
|
|
|
el.appendChild(child);
|
|
|
|
|
|
child = new Elem("li");
|
|
|
child.appendChild(document.createTextNode(txt.S + " "));
|
|
|
|
|
|
fld = new RGBElem("input", {
|
|
|
id: ids[this.ID.S],
|
|
|
className: "yui-picker-s"
|
|
|
});
|
|
|
|
|
|
child.appendChild(fld);
|
|
|
child.appendChild(document.createTextNode(" " + txt.PERCENT));
|
|
|
|
|
|
el.appendChild(child);
|
|
|
|
|
|
child = new Elem("li");
|
|
|
child.appendChild(document.createTextNode(txt.V + " "));
|
|
|
|
|
|
fld = new RGBElem("input", {
|
|
|
id: ids[this.ID.V],
|
|
|
className: "yui-picker-v"
|
|
|
});
|
|
|
|
|
|
child.appendChild(fld);
|
|
|
child.appendChild(document.createTextNode(" " + txt.PERCENT));
|
|
|
|
|
|
el.appendChild(child);
|
|
|
p.appendChild(el);
|
|
|
|
|
|
|
|
|
// hex summary
|
|
|
|
|
|
el = new Elem("ul", {
|
|
|
id: ids[this.ID.HEX_SUMMARY],
|
|
|
className: "yui-picker-hex_summary"
|
|
|
});
|
|
|
|
|
|
child = new Elem("li", {
|
|
|
id: ids[this.ID.R_HEX]
|
|
|
});
|
|
|
el.appendChild(child);
|
|
|
|
|
|
child = new Elem("li", {
|
|
|
id: ids[this.ID.G_HEX]
|
|
|
});
|
|
|
el.appendChild(child);
|
|
|
|
|
|
child = new Elem("li", {
|
|
|
id: ids[this.ID.B_HEX]
|
|
|
});
|
|
|
el.appendChild(child);
|
|
|
p.appendChild(el);
|
|
|
|
|
|
// hex field
|
|
|
el = new Elem("div", {
|
|
|
id: ids[this.ID.HEX_CONTROLS],
|
|
|
className: "yui-picker-hex-controls"
|
|
|
});
|
|
|
el.appendChild(document.createTextNode(txt.HEX + " "));
|
|
|
|
|
|
child = new RGBElem("input", {
|
|
|
id: ids[this.ID.HEX],
|
|
|
className: "yui-picker-hex",
|
|
|
size: 6,
|
|
|
maxlength: 6
|
|
|
});
|
|
|
|
|
|
el.appendChild(child);
|
|
|
p.appendChild(el);
|
|
|
|
|
|
p = this.get("element");
|
|
|
|
|
|
// swatch
|
|
|
el = new Elem("div", {
|
|
|
id: ids[this.ID.SWATCH],
|
|
|
className: "yui-picker-swatch"
|
|
|
});
|
|
|
|
|
|
p.appendChild(el);
|
|
|
|
|
|
// websafe swatch
|
|
|
el = new Elem("div", {
|
|
|
id: ids[this.ID.WEBSAFE_SWATCH],
|
|
|
className: "yui-picker-websafe-swatch"
|
|
|
});
|
|
|
|
|
|
p.appendChild(el);
|
|
|
|
|
|
},
|
|
|
|
|
|
_attachRGBHSV : function(id, config) {
|
|
|
Event.on(this.getElement(id), "keydown", function(e, me) {
|
|
|
me._rgbFieldKeypress(e, this, config);
|
|
|
}, this);
|
|
|
Event.on(this.getElement(id), "keypress", this._numbersOnly, this, true);
|
|
|
Event.on(this.getElement(id), "blur", function(e, me) {
|
|
|
me._useFieldValue(e, this, config);
|
|
|
}, this);
|
|
|
},
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Updates the rgb attribute with the current state of the r,g,b
|
|
|
* fields. This is invoked from change listeners on these
|
|
|
* attributes to facilitate updating these values from the
|
|
|
* individual form fields
|
|
|
* @method _updateRGB
|
|
|
* @protected
|
|
|
*/
|
|
|
_updateRGB : function() {
|
|
|
var rgb = [this.get(this.OPT.RED),
|
|
|
this.get(this.OPT.GREEN),
|
|
|
this.get(this.OPT.BLUE)];
|
|
|
|
|
|
this.set(this.OPT.RGB, rgb);
|
|
|
|
|
|
this._updateSliders();
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Creates any missing DOM structure.
|
|
|
*
|
|
|
* @method _initElements
|
|
|
* @protected
|
|
|
*/
|
|
|
_initElements : function () {
|
|
|
// bind all of our elements
|
|
|
var o=this.OPT,
|
|
|
ids = this.get(o.IDS),
|
|
|
els = this.get(o.ELEMENTS),
|
|
|
i, el, id;
|
|
|
|
|
|
// Add the default value as a key for each element for easier lookup
|
|
|
for (i in this.ID) {
|
|
|
if (lang.hasOwnProperty(this.ID, i)) {
|
|
|
ids[this.ID[i]] = ids[i];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Check for picker element, if not there, create all of them
|
|
|
el = Dom.get(ids[this.ID.PICKER_BG]);
|
|
|
if (!el) {
|
|
|
this._createElements();
|
|
|
} else {
|
|
|
}
|
|
|
|
|
|
for (i in ids) {
|
|
|
if (lang.hasOwnProperty(ids, i)) {
|
|
|
// look for element
|
|
|
el = Dom.get(ids[i]);
|
|
|
|
|
|
// generate an id if the implementer passed in an element reference,
|
|
|
// and the element did not have an id already
|
|
|
id = Dom.generateId(el);
|
|
|
|
|
|
// update the id in case we generated the id
|
|
|
ids[i] = id; // key is WEBSAFE_SWATCH
|
|
|
ids[ids[i]] = id; // key is websafe_swatch
|
|
|
|
|
|
// store the dom ref
|
|
|
els[id] = el;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Sets the initial state of the sliders
|
|
|
* @method initPicker
|
|
|
*/
|
|
|
initPicker : function () {
|
|
|
this._initSliders();
|
|
|
this._bindUI();
|
|
|
this.syncUI(true);
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Creates the Hue and Value/Saturation Sliders.
|
|
|
*
|
|
|
* @method _initSliders
|
|
|
* @protected
|
|
|
*/
|
|
|
_initSliders : function () {
|
|
|
var ID = this.ID,
|
|
|
size = this.get(this.OPT.PICKER_SIZE);
|
|
|
|
|
|
|
|
|
this.hueSlider = Slider.getVertSlider(
|
|
|
this.getElement(ID.HUE_BG),
|
|
|
this.getElement(ID.HUE_THUMB), 0, size);
|
|
|
|
|
|
this.pickerSlider = Slider.getSliderRegion(
|
|
|
this.getElement(ID.PICKER_BG),
|
|
|
this.getElement(ID.PICKER_THUMB), 0, size, 0, size);
|
|
|
|
|
|
// Apply animate attribute configuration
|
|
|
this.set(this.OPT.ANIMATE, this.get(this.OPT.ANIMATE));
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Adds event listeners to Sliders and UI elements. Wires everything
|
|
|
* up.
|
|
|
*
|
|
|
* @method _bindUI
|
|
|
* @protected
|
|
|
*/
|
|
|
_bindUI : function () {
|
|
|
var ID = this.ID,
|
|
|
O = this.OPT;
|
|
|
|
|
|
this.hueSlider.subscribe("change",
|
|
|
this._onHueSliderChange, this, true);
|
|
|
this.pickerSlider.subscribe("change",
|
|
|
this._onPickerSliderChange, this, true);
|
|
|
|
|
|
Event.on(this.getElement(ID.WEBSAFE_SWATCH), "click", function(e) {
|
|
|
this.setValue(this.get(O.WEBSAFE));
|
|
|
}, this, true);
|
|
|
|
|
|
Event.on(this.getElement(ID.CONTROLS_LABEL), "click", function(e) {
|
|
|
this.set(O.SHOW_CONTROLS, !this.get(O.SHOW_CONTROLS));
|
|
|
Event.preventDefault(e);
|
|
|
}, this, true);
|
|
|
|
|
|
this._attachRGBHSV(ID.R, O.RED);
|
|
|
this._attachRGBHSV(ID.G, O.GREEN);
|
|
|
this._attachRGBHSV(ID.B, O.BLUE);
|
|
|
this._attachRGBHSV(ID.H, O.HUE);
|
|
|
this._attachRGBHSV(ID.S, O.SATURATION);
|
|
|
this._attachRGBHSV(ID.V, O.VALUE);
|
|
|
|
|
|
Event.on(this.getElement(ID.HEX), "keydown", function(e, me) {
|
|
|
me._hexFieldKeypress(e, this, O.HEX);
|
|
|
}, this);
|
|
|
|
|
|
Event.on(this.getElement(this.ID.HEX), "keypress",
|
|
|
this._hexOnly, this,true);
|
|
|
Event.on(this.getElement(this.ID.HEX), "blur", function(e, me) {
|
|
|
me._useFieldValue(e, this, O.HEX);
|
|
|
}, this);
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Wrapper for _updateRGB, but allows setting
|
|
|
*
|
|
|
* @method syncUI
|
|
|
* @param skipAnim {Boolean} Omit Slider animation for this action
|
|
|
*/
|
|
|
syncUI : function (skipAnim) {
|
|
|
this.skipAnim = skipAnim;
|
|
|
this._updateRGB();
|
|
|
this.skipAnim = false;
|
|
|
},
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Updates the RGB values from the current state of the HSV
|
|
|
* values. Executed when the one of the HSV form fields are
|
|
|
* updated
|
|
|
* _updateRGBFromHSV
|
|
|
* @protected
|
|
|
*/
|
|
|
_updateRGBFromHSV : function() {
|
|
|
var hsv = [this.get(this.OPT.HUE),
|
|
|
this.get(this.OPT.SATURATION)/100,
|
|
|
this.get(this.OPT.VALUE)/100],
|
|
|
rgb = Color.hsv2rgb(hsv);
|
|
|
|
|
|
this.set(this.OPT.RGB, rgb);
|
|
|
|
|
|
this._updateSliders();
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Parses the hex string to normalize shorthand values, converts
|
|
|
* the hex value to rgb and updates the rgb attribute (which
|
|
|
* updates the state for all of the other values)
|
|
|
* method _updateHex
|
|
|
* @protected
|
|
|
*/
|
|
|
_updateHex : function() {
|
|
|
|
|
|
var hex = this.get(this.OPT.HEX),
|
|
|
l = hex.length,
|
|
|
c,i,rgb;
|
|
|
|
|
|
// support #369 -> #336699 shorthand
|
|
|
if (l === 3) {
|
|
|
c = hex.split("");
|
|
|
for (i=0; i<l; i=i+1) {
|
|
|
c[i] = c[i] + c[i];
|
|
|
}
|
|
|
|
|
|
hex = c.join("");
|
|
|
}
|
|
|
|
|
|
if (hex.length !== 6) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
rgb = Color.hex2rgb(hex);
|
|
|
|
|
|
|
|
|
this.setValue(rgb);
|
|
|
},
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Returns the cached element reference. If the id is not a string, it
|
|
|
* is assumed that it is an element and this is returned.
|
|
|
* @param id {string|HTMLElement} the element key, id, or ref
|
|
|
* @param on {boolean} hide or show. If true, show
|
|
|
* @protected
|
|
|
*/
|
|
|
_hideShowEl : function(id, on) {
|
|
|
var el = (lang.isString(id) ? this.getElement(id) : id);
|
|
|
Dom.setStyle(el, "display", (on) ? "" : "none");
|
|
|
},
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Sets up the config attributes and the change listeners for this
|
|
|
* properties
|
|
|
* @method initAttributes
|
|
|
* @param attr An object containing default attribute values
|
|
|
*/
|
|
|
initAttributes : function(attr) {
|
|
|
|
|
|
attr = attr || {};
|
|
|
ColorPicker.superclass.initAttributes.call(this, attr);
|
|
|
|
|
|
/**
|
|
|
* The size of the picker. Trying to change this is not recommended.
|
|
|
* @attribute pickersize
|
|
|
* @default 180
|
|
|
* @type int
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.PICKER_SIZE, {
|
|
|
value: attr.size || this.DEFAULT.PICKER_SIZE
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* The current hue value 0-360
|
|
|
* @attribute hue
|
|
|
* @type int
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.HUE, {
|
|
|
value: attr.hue || 0,
|
|
|
validator: lang.isNumber
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* The current saturation value 0-100
|
|
|
* @attribute saturation
|
|
|
* @type int
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.SATURATION, {
|
|
|
value: attr.saturation || 0,
|
|
|
validator: lang.isNumber
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* The current value/brightness value 0-100
|
|
|
* @attribute value
|
|
|
* @type int
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.VALUE, {
|
|
|
value: lang.isNumber(attr.value) ? attr.value : 100,
|
|
|
validator: lang.isNumber
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* The current red value 0-255
|
|
|
* @attribute red
|
|
|
* @type int
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.RED, {
|
|
|
value: lang.isNumber(attr.red) ? attr.red : 255,
|
|
|
validator: lang.isNumber
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* The current green value 0-255
|
|
|
* @attribute green
|
|
|
* @type int
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.GREEN, {
|
|
|
value: lang.isNumber(attr.green) ? attr.green : 255,
|
|
|
validator: lang.isNumber
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* The current blue value 0-255
|
|
|
* @attribute blue
|
|
|
* @type int
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.BLUE, {
|
|
|
value: lang.isNumber(attr.blue) ? attr.blue : 255,
|
|
|
validator: lang.isNumber
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* The current hex value #000000-#FFFFFF, without the #
|
|
|
* @attribute hex
|
|
|
* @type string
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.HEX, {
|
|
|
value: attr.hex || "FFFFFF",
|
|
|
validator: lang.isString
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* The current rgb value. Updates the state of all of the
|
|
|
* other value fields. Read-only: use setValue to set the
|
|
|
* controls rgb value.
|
|
|
* @attribute hex
|
|
|
* @type [int, int, int]
|
|
|
* @readonly
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.RGB, {
|
|
|
value: attr.rgb || [255,255,255],
|
|
|
method: function(rgb) {
|
|
|
|
|
|
this.set(this.OPT.RED, rgb[0], true);
|
|
|
this.set(this.OPT.GREEN, rgb[1], true);
|
|
|
this.set(this.OPT.BLUE, rgb[2], true);
|
|
|
|
|
|
var websafe = Color.websafe(rgb),
|
|
|
hex = Color.rgb2hex(rgb),
|
|
|
hsv = Color.rgb2hsv(rgb);
|
|
|
|
|
|
this.set(this.OPT.WEBSAFE, websafe, true);
|
|
|
this.set(this.OPT.HEX, hex, true);
|
|
|
|
|
|
|
|
|
|
|
|
// fix bug #1754338 - when saturation is 0, hue is
|
|
|
// silently always set to 0, but input field not updated
|
|
|
if (hsv[1]) {
|
|
|
this.set(this.OPT.HUE, hsv[0], true);
|
|
|
}
|
|
|
this.set(this.OPT.SATURATION, Math.round(hsv[1]*100), true);
|
|
|
this.set(this.OPT.VALUE, Math.round(hsv[2]*100), true);
|
|
|
},
|
|
|
readonly: true
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* If the color picker will live inside of a container object,
|
|
|
* set, provide a reference to it so the control can use the
|
|
|
* container's events.
|
|
|
* @attribute container
|
|
|
* @type YAHOO.widget.Panel
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.CONTAINER, {
|
|
|
value: null,
|
|
|
method: function(container) {
|
|
|
if (container) {
|
|
|
// Position can get out of sync when the
|
|
|
// control is manipulated while display is
|
|
|
// none. Resetting the slider constraints
|
|
|
// when it is visible gets the state back in
|
|
|
// order.
|
|
|
container.showEvent.subscribe(function() {
|
|
|
// this.pickerSlider.thumb.resetConstraints();
|
|
|
// this.hueSlider.thumb.resetConstraints();
|
|
|
this.pickerSlider.focus();
|
|
|
}, this, true);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
/**
|
|
|
* The closest current websafe value
|
|
|
* @attribute websafe
|
|
|
* @type int
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.WEBSAFE, {
|
|
|
value: attr.websafe || [255,255,255]
|
|
|
});
|
|
|
|
|
|
|
|
|
var ids = attr.ids || lang.merge({}, this.ID), i;
|
|
|
|
|
|
if (!attr.ids && _pickercount > 1) {
|
|
|
for (i in ids) {
|
|
|
if (lang.hasOwnProperty(ids, i)) {
|
|
|
ids[i] = ids[i] + _pickercount;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* A list of element ids and/or element references used by the
|
|
|
* control. The default is the this.ID list, and can be customized
|
|
|
* by passing a list in the contructor
|
|
|
* @attribute ids
|
|
|
* @type {referenceid: realid}
|
|
|
* @writeonce
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.IDS, {
|
|
|
value: ids,
|
|
|
writeonce: true
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* A list of txt strings for internationalization. Default
|
|
|
* is this.TXT
|
|
|
* @attribute txt
|
|
|
* @type {key: txt}
|
|
|
* @writeonce
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.TXT, {
|
|
|
value: attr.txt || this.TXT,
|
|
|
writeonce: true
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* The img src default list
|
|
|
* is this.IMAGES
|
|
|
* @attribute images
|
|
|
* @type {key: image}
|
|
|
* @writeonce
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.IMAGES, {
|
|
|
value: attr.images || this.IMAGE,
|
|
|
writeonce: true
|
|
|
});
|
|
|
/**
|
|
|
* The element refs used by this control. Set at initialization
|
|
|
* @attribute elements
|
|
|
* @type {id: HTMLElement}
|
|
|
* @readonly
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.ELEMENTS, {
|
|
|
value: {},
|
|
|
readonly: true
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* Hide/show the entire set of controls
|
|
|
* @attribute showcontrols
|
|
|
* @type boolean
|
|
|
* @default true
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.SHOW_CONTROLS, {
|
|
|
value: lang.isBoolean(attr.showcontrols) ? attr.showcontrols : true,
|
|
|
method: function(on) {
|
|
|
|
|
|
var el = Dom.getElementsByClassName("bd", "div",
|
|
|
this.getElement(this.ID.CONTROLS))[0];
|
|
|
|
|
|
this._hideShowEl(el, on);
|
|
|
|
|
|
this.getElement(this.ID.CONTROLS_LABEL).innerHTML =
|
|
|
(on) ? this.get(this.OPT.TXT).HIDE_CONTROLS :
|
|
|
this.get(this.OPT.TXT).SHOW_CONTROLS;
|
|
|
|
|
|
}
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* Hide/show the rgb controls
|
|
|
* @attribute showrgbcontrols
|
|
|
* @type boolean
|
|
|
* @default true
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.SHOW_RGB_CONTROLS, {
|
|
|
value: lang.isBoolean(attr.showrgbcontrols) ? attr.showrgbcontrols : true,
|
|
|
method: function(on) {
|
|
|
this._hideShowEl(this.ID.RGB_CONTROLS, on);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* Hide/show the hsv controls
|
|
|
* @attribute showhsvcontrols
|
|
|
* @type boolean
|
|
|
* @default false
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.SHOW_HSV_CONTROLS, {
|
|
|
value: lang.isBoolean(attr.showhsvcontrols) ?
|
|
|
attr.showhsvcontrols : false,
|
|
|
method: function(on) {
|
|
|
//Dom.setStyle(this.getElement(this.ID.HSV_CONTROLS), "visibility", (on) ? "" : "hidden");
|
|
|
this._hideShowEl(this.ID.HSV_CONTROLS, on);
|
|
|
|
|
|
// can't show both the hsv controls and the rbg hex summary
|
|
|
if (on && this.get(this.OPT.SHOW_HEX_SUMMARY)) {
|
|
|
this.set(this.OPT.SHOW_HEX_SUMMARY, false);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* Hide/show the hex controls
|
|
|
* @attribute showhexcontrols
|
|
|
* @type boolean
|
|
|
* @default true
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.SHOW_HEX_CONTROLS, {
|
|
|
value: lang.isBoolean(attr.showhexcontrols) ?
|
|
|
attr.showhexcontrols : false,
|
|
|
method: function(on) {
|
|
|
this._hideShowEl(this.ID.HEX_CONTROLS, on);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* Hide/show the websafe swatch
|
|
|
* @attribute showwebsafe
|
|
|
* @type boolean
|
|
|
* @default true
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.SHOW_WEBSAFE, {
|
|
|
value: lang.isBoolean(attr.showwebsafe) ? attr.showwebsafe : true,
|
|
|
method: function(on) {
|
|
|
this._hideShowEl(this.ID.WEBSAFE_SWATCH, on);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* Hide/show the hex summary
|
|
|
* @attribute showhexsummary
|
|
|
* @type boolean
|
|
|
* @default true
|
|
|
*/
|
|
|
this.setAttributeConfig(this.OPT.SHOW_HEX_SUMMARY, {
|
|
|
value: lang.isBoolean(attr.showhexsummary) ? attr.showhexsummary : true,
|
|
|
method: function(on) {
|
|
|
this._hideShowEl(this.ID.HEX_SUMMARY, on);
|
|
|
|
|
|
// can't show both the hsv controls and the rbg hex summary
|
|
|
if (on && this.get(this.OPT.SHOW_HSV_CONTROLS)) {
|
|
|
this.set(this.OPT.SHOW_HSV_CONTROLS, false);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
this.setAttributeConfig(this.OPT.ANIMATE, {
|
|
|
value: lang.isBoolean(attr.animate) ? attr.animate : true,
|
|
|
method: function(on) {
|
|
|
if (this.pickerSlider) {
|
|
|
this.pickerSlider.animate = on;
|
|
|
this.hueSlider.animate = on;
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
|
|
|
this.on(this.OPT.HUE + "Change", this._updateRGBFromHSV, this, true);
|
|
|
this.on(this.OPT.SATURATION + "Change", this._updateRGBFromHSV, this, true);
|
|
|
this.on(this.OPT.VALUE + "Change", this._updateRGBFromHSV, this, true);
|
|
|
|
|
|
this.on(this.OPT.RED + "Change", this._updateRGB, this, true);
|
|
|
this.on(this.OPT.GREEN + "Change", this._updateRGB, this, true);
|
|
|
this.on(this.OPT.BLUE + "Change", this._updateRGB, this, true);
|
|
|
|
|
|
this.on(this.OPT.HEX + "Change", this._updateHex, this, true);
|
|
|
|
|
|
this._initElements();
|
|
|
}
|
|
|
});
|
|
|
|
|
|
YAHOO.widget.ColorPicker = ColorPicker;
|
|
|
})();
|
|
|
YAHOO.register("colorpicker", YAHOO.widget.ColorPicker, {version: "2.8.0r4", build: "2449"});
|
|
|
|