##// END OF EJS Templates
when new repo is created make user follow it automatically,...
when new repo is created make user follow it automatically, add tilte to currently logged in user.

File last commit:

r547:1e757ac9 default
r786:2889a444 beta
Show More
colorpicker-debug.js
1783 lines | 57.8 KiB | application/javascript | JavascriptLexer
/*
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;
}
}
YAHOO.log("Error calculating the websafe value for " + v, "warn");
}
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;
this.logger = new YAHOO.widget.LogWriter("ColorPicker");
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
this.logger.log("creating host element");
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.logger.log("Hue slider is being set to " + h);
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.logger.log("Setting picker slider to " + [s, v]);
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.logger.log("hsv " + [this._getH(),this._getS(),this._getV()]);
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) {
this.logger.log("hue update: " + newOffset , "warn");
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) {
this.logger.log(sub("picker update [{x}, {y}]", 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() {
this.logger.log("Building markup");
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.logger.log("RGB value set to " + rgb);
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 {
this.logger.log("Using pre-existing markup");
}
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.logger.log("picker size" + 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.logger.log("HSV converted to RGB " + hsv + " : " + rgb);
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) {
this.logger.log(this.get(this.TXT.ILLEGAL_HEX), "error");
return false;
}
rgb = Color.hex2rgb(hex);
this.logger.log(sub("Hex value set to {hex} ({rgb})", {
hex: hex, rgb: rgb
}));
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);
this.logger.log(sub("RGB value set to {rgb} (hsv: {hsv})", {
"hsv": hsv, "rgb": rgb
}));
// 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"});